diff --git a/asm/include/battle_commands.inc b/asm/include/battle_commands.inc index d8a75473a8..e37db9e451 100644 --- a/asm/include/battle_commands.inc +++ b/asm/include/battle_commands.inc @@ -1633,7 +1633,13 @@ .long (((\arg_2 - .) / 4) - 1) .endm - .equ BASE_ENGINE_BTL_SCR_CMDS_MAX, 298 + .macro TryActivateEmergencyExit arg_0, arg_1 + .long 299 + .long \arg_0 + .long (((\arg_1 - .) / 4) - 1) + .endm + + .equ BASE_ENGINE_BTL_SCR_CMDS_MAX, 299 // .macro YourCustomCommand // .long (BASE_ENGINE_BTL_SCR_CMDS_MAX + 1) diff --git a/data/battle_scripts/subscripts/subscript_0009_SWITCH_POKEMON.s b/data/battle_scripts/subscripts/subscript_0009_SWITCH_POKEMON.s index 8e9afe5369..fad7578165 100644 --- a/data/battle_scripts/subscripts/subscript_0009_SWITCH_POKEMON.s +++ b/data/battle_scripts/subscripts/subscript_0009_SWITCH_POKEMON.s @@ -49,6 +49,7 @@ _047: WaitTime 72 HealthbarSlideIn BATTLER_CATEGORY_SWITCHED_MON Wait + SetCurrentMoveSwitchingStatus CURRENT_MOVE_NO_SWITCH Call BATTLE_SUBSCRIPT_HEALING_WISH Call BATTLE_SUBSCRIPT_HAZARDS_CHECK CompareVarToValue OPCODE_GT, BSCRIPT_VAR_BATTLER_FAINTED, BATTLER_ENEMY2, _081 diff --git a/data/battle_scripts/subscripts/subscript_0010_SHOW_PARTY_LIST.s b/data/battle_scripts/subscripts/subscript_0010_SHOW_PARTY_LIST.s index 12c50b18b3..b8e5291173 100644 --- a/data/battle_scripts/subscripts/subscript_0010_SHOW_PARTY_LIST.s +++ b/data/battle_scripts/subscripts/subscript_0010_SHOW_PARTY_LIST.s @@ -22,6 +22,7 @@ _001: WaitTime 72 HealthbarSlideIn BATTLER_CATEGORY_SWITCHED_MON Wait + SetCurrentMoveSwitchingStatus CURRENT_MOVE_NO_SWITCH Call BATTLE_SUBSCRIPT_HEALING_WISH Call BATTLE_SUBSCRIPT_HAZARDS_CHECK CompareVarToValue OPCODE_FLAG_NOT, BSCRIPT_VAR_BATTLE_STATUS, BATTLE_STATUS_FAINTED, _030 @@ -29,4 +30,5 @@ _001: _030: GoToIfAnySwitches _001 + Call BATTLE_SUBSCRIPT_SWITCH_IN_ABILITY_CHECK End diff --git a/data/battle_scripts/subscripts/subscript_0023_POISON_DAMAGE.s b/data/battle_scripts/subscripts/subscript_0023_POISON_DAMAGE.s index 1bdcb8b1ef..ff380537d7 100644 --- a/data/battle_scripts/subscripts/subscript_0023_POISON_DAMAGE.s +++ b/data/battle_scripts/subscripts/subscript_0023_POISON_DAMAGE.s @@ -27,7 +27,11 @@ _038: PlayBattleAnimation BATTLER_CATEGORY_MSG_TEMP, BATTLE_ANIMATION_POISONED Wait UpdateVar OPCODE_FLAG_ON, BSCRIPT_VAR_BATTLE_STATUS, BATTLE_STATUS_NO_BLINK - GoToSubscript BATTLE_SUBSCRIPT_UPDATE_HP + Call BATTLE_SUBSCRIPT_UPDATE_HP + TryActivateEmergencyExit BATTLER_CATEGORY_MSG_BATTLER_TEMP, _noActivation + Call BATTLE_SUBSCRIPT_HANDLE_WIMP_OUT_EMERGENCY_EXIT + +_noActivation: Call BATTLE_SUBSCRIPT_SWITCH_IN_ABILITY_CHECK _055: diff --git a/data/battle_scripts/subscripts/subscript_0026_BURN_DAMAGE.s b/data/battle_scripts/subscripts/subscript_0026_BURN_DAMAGE.s index b3a49bf152..4b64bdfe4d 100644 --- a/data/battle_scripts/subscripts/subscript_0026_BURN_DAMAGE.s +++ b/data/battle_scripts/subscripts/subscript_0026_BURN_DAMAGE.s @@ -19,7 +19,11 @@ _020: PlayBattleAnimation BATTLER_CATEGORY_MSG_TEMP, BATTLE_ANIMATION_BURNED Wait UpdateVar OPCODE_FLAG_ON, BSCRIPT_VAR_BATTLE_STATUS, BATTLE_STATUS_NO_BLINK - GoToSubscript BATTLE_SUBSCRIPT_UPDATE_HP + Call BATTLE_SUBSCRIPT_UPDATE_HP + TryActivateEmergencyExit BATTLER_CATEGORY_MSG_BATTLER_TEMP, _noActivation + Call BATTLE_SUBSCRIPT_HANDLE_WIMP_OUT_EMERGENCY_EXIT + +_noActivation: Call BATTLE_SUBSCRIPT_SWITCH_IN_ABILITY_CHECK _041: diff --git a/data/battle_scripts/subscripts/subscript_0059_BIND_EFFECT.s b/data/battle_scripts/subscripts/subscript_0059_BIND_EFFECT.s index cee87d2ff2..886989a165 100644 --- a/data/battle_scripts/subscripts/subscript_0059_BIND_EFFECT.s +++ b/data/battle_scripts/subscripts/subscript_0059_BIND_EFFECT.s @@ -57,7 +57,11 @@ _DealDamage: Wait WaitButtonABTime 30 UpdateVar OPCODE_FLAG_ON, BSCRIPT_VAR_BATTLE_STATUS, BATTLE_STATUS_NO_BLINK - GoToSubscript BATTLE_SUBSCRIPT_UPDATE_HP + Call BATTLE_SUBSCRIPT_UPDATE_HP + TryActivateEmergencyExit BATTLER_CATEGORY_MSG_BATTLER_TEMP, _noActivation + Call BATTLE_SUBSCRIPT_HANDLE_WIMP_OUT_EMERGENCY_EXIT + +_noActivation: Call BATTLE_SUBSCRIPT_SWITCH_IN_ABILITY_CHECK _End: diff --git a/data/battle_scripts/subscripts/subscript_0069_LEECH_SEED_EFFECT.s b/data/battle_scripts/subscripts/subscript_0069_LEECH_SEED_EFFECT.s index fcc85dede1..dd53bc257d 100644 --- a/data/battle_scripts/subscripts/subscript_0069_LEECH_SEED_EFFECT.s +++ b/data/battle_scripts/subscripts/subscript_0069_LEECH_SEED_EFFECT.s @@ -30,6 +30,14 @@ _050: PrintMessage 296, TAG_NICKNAME, BATTLER_CATEGORY_MSG_DEFENDER Wait WaitButtonABTime 30 + UpdateVarFromVar OPCODE_SET, BSCRIPT_VAR_MSG_BATTLER_TEMP, BSCRIPT_VAR_MSG_DEFENDER + UpdateMonDataFromVar OPCODE_GET, BATTLER_CATEGORY_MSG_DEFENDER, BMON_DATA_MAXHP, BSCRIPT_VAR_HP_CALC + DivideVarByValue BSCRIPT_VAR_HP_CALC, 8 + UpdateVar OPCODE_MUL, BSCRIPT_VAR_HP_CALC, -1 + TryActivateEmergencyExit BATTLER_CATEGORY_MSG_BATTLER_TEMP, _noActivation //needs ctx->hp_calc_work + Call BATTLE_SUBSCRIPT_HANDLE_WIMP_OUT_EMERGENCY_EXIT + +_noActivation: Call BATTLE_SUBSCRIPT_SWITCH_IN_ABILITY_CHECK End diff --git a/data/battle_scripts/subscripts/subscript_0094_NIGHTMARE_EFFECT.s b/data/battle_scripts/subscripts/subscript_0094_NIGHTMARE_EFFECT.s index b4c73595d6..e195874b76 100644 --- a/data/battle_scripts/subscripts/subscript_0094_NIGHTMARE_EFFECT.s +++ b/data/battle_scripts/subscripts/subscript_0094_NIGHTMARE_EFFECT.s @@ -15,7 +15,11 @@ _000: Wait WaitButtonABTime 30 UpdateVar OPCODE_FLAG_ON, BSCRIPT_VAR_BATTLE_STATUS, BATTLE_STATUS_NO_BLINK - GoToSubscript BATTLE_SUBSCRIPT_UPDATE_HP + Call BATTLE_SUBSCRIPT_UPDATE_HP + TryActivateEmergencyExit BATTLER_CATEGORY_MSG_BATTLER_TEMP, _noActivation + Call BATTLE_SUBSCRIPT_HANDLE_WIMP_OUT_EMERGENCY_EXIT + +_noActivation: Call BATTLE_SUBSCRIPT_SWITCH_IN_ABILITY_CHECK _033: diff --git a/data/battle_scripts/subscripts/subscript_0098_CURSE_DAMAGE.s b/data/battle_scripts/subscripts/subscript_0098_CURSE_DAMAGE.s index a84abacfad..c1a4a2508d 100644 --- a/data/battle_scripts/subscripts/subscript_0098_CURSE_DAMAGE.s +++ b/data/battle_scripts/subscripts/subscript_0098_CURSE_DAMAGE.s @@ -15,7 +15,11 @@ _000: Wait WaitButtonABTime 30 UpdateVar OPCODE_FLAG_ON, BSCRIPT_VAR_BATTLE_STATUS, BATTLE_STATUS_NO_BLINK - GoToSubscript BATTLE_SUBSCRIPT_UPDATE_HP + Call BATTLE_SUBSCRIPT_UPDATE_HP + TryActivateEmergencyExit BATTLER_CATEGORY_MSG_BATTLER_TEMP, _noActivation + Call BATTLE_SUBSCRIPT_HANDLE_WIMP_OUT_EMERGENCY_EXIT + +_noActivation: Call BATTLE_SUBSCRIPT_SWITCH_IN_ABILITY_CHECK _033: diff --git a/data/battle_scripts/subscripts/subscript_0099_HAZARDS_CHECK.s b/data/battle_scripts/subscripts/subscript_0099_HAZARDS_CHECK.s index 26b573f9e6..b8edad4cd0 100644 --- a/data/battle_scripts/subscripts/subscript_0099_HAZARDS_CHECK.s +++ b/data/battle_scripts/subscripts/subscript_0099_HAZARDS_CHECK.s @@ -51,6 +51,11 @@ _checkSpikes: PrintMessage 429, TAG_NICKNAME, BATTLER_CATEGORY_SWITCHED_MON Wait WaitButtonABTime 30 + TryActivateEmergencyExit BATTLER_CATEGORY_MSG_BATTLER_TEMP, _noWimpOutFromSpikes + Call BATTLE_SUBSCRIPT_HANDLE_WIMP_OUT_EMERGENCY_EXIT + GoToSubscript BATTLE_SUBSCRIPT_SHOW_PARTY_LIST + +_noWimpOutFromSpikes: GoTo _landingPad _checkIfShouldDoTSpikes: @@ -124,4 +129,9 @@ _checkStealthRock: PrintMessage 1079, TAG_NICKNAME, BATTLER_CATEGORY_SWITCHED_MON Wait WaitButtonABTime 30 + TryActivateEmergencyExit BATTLER_CATEGORY_MSG_BATTLER_TEMP, _noWimpOutFromRocks + Call BATTLE_SUBSCRIPT_HANDLE_WIMP_OUT_EMERGENCY_EXIT + GoToSubscript BATTLE_SUBSCRIPT_SHOW_PARTY_LIST + +_noWimpOutFromRocks: GoTo _landingPad diff --git a/data/battle_scripts/subscripts/subscript_0104_WEATHER_CONTINUES.s b/data/battle_scripts/subscripts/subscript_0104_WEATHER_CONTINUES.s index 1eada97b30..984ba7a8e7 100644 --- a/data/battle_scripts/subscripts/subscript_0104_WEATHER_CONTINUES.s +++ b/data/battle_scripts/subscripts/subscript_0104_WEATHER_CONTINUES.s @@ -29,7 +29,17 @@ _083: CompareVarToValue OPCODE_FLAG_SET, BSCRIPT_VAR_FIELD_CONDITION, FIELD_CONDITION_SUN_ALL, _095 // {1} is buffeted by the {0}! PrintMessage 285, TAG_MOVE_NICKNAME, BATTLER_CATEGORY_MSG_TEMP, BATTLER_CATEGORY_MSG_TEMP - GoTo _112 + Wait + WaitButtonABTime 30 + Call BATTLE_SUBSCRIPT_UPDATE_HP + CompareVarToValue OPCODE_FLAG_NOT, BSCRIPT_VAR_BATTLE_STATUS, BATTLE_STATUS_FAINTED, _noFaint + Call BATTLE_SUBSCRIPT_FAINT_MON + GoTo _140 + +_noFaint: + TryActivateEmergencyExit BATTLER_CATEGORY_MSG_BATTLER_TEMP, _140 + Call BATTLE_SUBSCRIPT_HANDLE_WIMP_OUT_EMERGENCY_EXIT + GoTo _140 _095: CompareVarToValue OPCODE_EQU, BSCRIPT_VAR_TEMP_DATA, 2, _107 diff --git a/data/battle_scripts/subscripts/subscript_0215_LOSE_HP_FROM_ITEM_WITH_MESSAGE.s b/data/battle_scripts/subscripts/subscript_0215_LOSE_HP_FROM_ITEM_WITH_MESSAGE.s index bfae6b9e2b..73434b5f39 100644 --- a/data/battle_scripts/subscripts/subscript_0215_LOSE_HP_FROM_ITEM_WITH_MESSAGE.s +++ b/data/battle_scripts/subscripts/subscript_0215_LOSE_HP_FROM_ITEM_WITH_MESSAGE.s @@ -12,5 +12,9 @@ _000: PrintMessage 1132, TAG_NICKNAME_ITEM, BATTLER_CATEGORY_MSG_TEMP, BATTLER_CATEGORY_MSG_BATTLER_TEMP Wait WaitButtonABTime 30 + TryActivateEmergencyExit BATTLER_CATEGORY_MSG_BATTLER_TEMP, _noActivation + Call BATTLE_SUBSCRIPT_HANDLE_WIMP_OUT_EMERGENCY_EXIT + +_noActivation: Call BATTLE_SUBSCRIPT_SWITCH_IN_ABILITY_CHECK End diff --git a/data/battle_scripts/subscripts/subscript_0498_HANDLE_WIMP_OUT.s b/data/battle_scripts/subscripts/subscript_0498_HANDLE_WIMP_OUT.s index 5580b28182..70206c1199 100644 --- a/data/battle_scripts/subscripts/subscript_0498_HANDLE_WIMP_OUT.s +++ b/data/battle_scripts/subscripts/subscript_0498_HANDLE_WIMP_OUT.s @@ -18,7 +18,6 @@ _155: Wait HealthbarSlideOut BATTLER_CATEGORY_MSG_BATTLER_TEMP Wait - UpdateVar OPCODE_FLAG_ON, BSCRIPT_VAR_BATTLE_STATUS_2, BATTLE_STATUS2_UTURN UpdateVar OPCODE_FLAG_OFF, BSCRIPT_VAR_BATTLE_STATUS, BATTLE_STATUS_SYNCRONIZE UpdateVar OPCODE_SET, BSCRIPT_VAR_SIDE_EFFECT_MON_SELF_TURN_STATUS_FLAGS, SELF_TURN_FLAG_CLEAR SetCurrentMoveSwitchingStatus CURRENT_MOVE_SWITCH_PENDING diff --git a/data/battle_tests/abilities/emergency_exit/item_heal_stays_below_50.c b/data/battle_tests/abilities/emergency_exit/item_heal_stays_below_50.c new file mode 100644 index 0000000000..bb754c2102 --- /dev/null +++ b/data/battle_tests/abilities/emergency_exit/item_heal_stays_below_50.c @@ -0,0 +1,106 @@ +// Test: Emergency Exit - switches out when going below 50% max-HP but healing via held item is not enough to go back above the threshold +#include "../../battle_tests.h" +BEGIN_TEST +{ + .battleType = BATTLE_TYPE_TRAINER, + .weather = FIELD_CONDITION_NONE, + .fieldCondition = 0, + .terrain = TERRAIN_NONE, + .playerParty = { + { + .species = SPECIES_STARAPTOR, + .level = 40, + .form = 0, + .ability = ABILITY_RECKLESS, + .item = ITEM_NONE, + .moves = { MOVE_BRAVE_BIRD, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE } + }, + .enemyParty = { { + .species = SPECIES_GOLISOPOD, + .level = 50, + .form = 0, + .ability = ABILITY_EMERGENCY_EXIT, + .item = ITEM_ORAN_BERRY, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { + .species = SPECIES_LITTEN, + .level = 50, + .form = 0, + .ability = ABILITY_INTIMIDATE, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE } }, + .playerScript = { { + { ACTION_MOVE_SLOT_1, BATTLER_ENEMY_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + }, + { + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + } }, + .enemyScript = { { + { ACTION_MOVE_SLOT_1, BATTLER_PLAYER_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + }, + { + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + } }, + .expectations = { + { .expectationType = EXPECTATION_TYPE_HP_BAR, .battlerIDOrPartySlot = BATTLER_ENEMY_FIRST, .expectationValue.hpTaken = { 96, 96, 98, 98, 98, 102, 102, 102, 104, 104, 108, 108, 108, 110, 110, 114 } }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Staraptor was damaged by the recoil!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "The opposing Golisopod restored its health using its Oran Berry!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Golisopod's EmergencyExit" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE_CONTAINS, .expectationValue.message = "sent out Litten" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Litten's Intimidate" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Staraptor's Attack fell!" }, + } +} +END_TEST diff --git a/data/battle_tests/abilities/emergency_exit/multihit.c b/data/battle_tests/abilities/emergency_exit/multihit.c new file mode 100644 index 0000000000..4b447f38c8 --- /dev/null +++ b/data/battle_tests/abilities/emergency_exit/multihit.c @@ -0,0 +1,107 @@ +// Test: Emergency Exit - activates after last hit of a multi-hit move and falling under 50% max-hp +#include "../../battle_tests.h" +BEGIN_TEST +{ + .battleType = BATTLE_TYPE_TRAINER, + .weather = FIELD_CONDITION_NONE, + .fieldCondition = 0, + .terrain = TERRAIN_NONE, + .playerParty = { + { + .species = SPECIES_BRELOOM, + .level = 50, + .form = 0, + .ability = ABILITY_SKILL_LINK, + .item = ITEM_NONE, + .moves = { MOVE_BULLET_SEED, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE } + }, + .enemyParty = { { + .species = SPECIES_GOLISOPOD, + .level = 50, + .form = 0, + .ability = ABILITY_EMERGENCY_EXIT, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = 95, //150 + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { + .species = SPECIES_LITTEN, + .level = 50, + .form = 0, + .ability = ABILITY_INTIMIDATE, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE } }, + .playerScript = { { + { ACTION_MOVE_SLOT_1, BATTLER_ENEMY_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + }, + { + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + } }, + .enemyScript = { { + { ACTION_MOVE_SLOT_1, BATTLER_PLAYER_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + }, + { + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + } }, + .expectations = { + { .expectationType = EXPECTATION_TYPE_HP_BAR, .battlerIDOrPartySlot = BATTLER_ENEMY_FIRST, .expectationValue.hpTaken = { 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 18 } }, + { .expectationType = EXPECTATION_TYPE_HP_BAR, .battlerIDOrPartySlot = BATTLER_ENEMY_FIRST, .expectationValue.hpTaken = { 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 18 } }, + { .expectationType = EXPECTATION_TYPE_HP_BAR, .battlerIDOrPartySlot = BATTLER_ENEMY_FIRST, .expectationValue.hpTaken = { 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 18 } }, + { .expectationType = EXPECTATION_TYPE_HP_BAR, .battlerIDOrPartySlot = BATTLER_ENEMY_FIRST, .expectationValue.hpTaken = { 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 18 } }, + { .expectationType = EXPECTATION_TYPE_HP_BAR, .battlerIDOrPartySlot = BATTLER_ENEMY_FIRST, .expectationValue.hpTaken = { 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 18 } }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Golisopod's EmergencyExit" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE_CONTAINS, .expectationValue.message = "sent out Litten" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Litten's Intimidate" }, + } +} +END_TEST diff --git a/data/battle_tests/abilities/emergency_exit/multihit_drop_with_last_hit.c b/data/battle_tests/abilities/emergency_exit/multihit_drop_with_last_hit.c new file mode 100644 index 0000000000..afd0426c22 --- /dev/null +++ b/data/battle_tests/abilities/emergency_exit/multihit_drop_with_last_hit.c @@ -0,0 +1,107 @@ +// Test: Emergency Exit - activates after last hit of a multi-hit move and falling under 50% max-hp on last hit +#include "../../battle_tests.h" +BEGIN_TEST +{ + .battleType = BATTLE_TYPE_TRAINER, + .weather = FIELD_CONDITION_NONE, + .fieldCondition = 0, + .terrain = TERRAIN_NONE, + .playerParty = { + { + .species = SPECIES_BRELOOM, + .level = 50, + .form = 0, + .ability = ABILITY_SKILL_LINK, + .item = ITEM_NONE, + .moves = { MOVE_BULLET_SEED, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE } + }, + .enemyParty = { { + .species = SPECIES_GOLISOPOD, + .level = 50, + .form = 0, + .ability = ABILITY_EMERGENCY_EXIT, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = 149, //150 + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { + .species = SPECIES_LITTEN, + .level = 50, + .form = 0, + .ability = ABILITY_INTIMIDATE, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE } }, + .playerScript = { { + { ACTION_MOVE_SLOT_1, BATTLER_ENEMY_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + }, + { + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + } }, + .enemyScript = { { + { ACTION_MOVE_SLOT_1, BATTLER_PLAYER_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + }, + { + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + } }, + .expectations = { + { .expectationType = EXPECTATION_TYPE_HP_BAR, .battlerIDOrPartySlot = BATTLER_ENEMY_FIRST, .expectationValue.hpTaken = { 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 18 } }, + { .expectationType = EXPECTATION_TYPE_HP_BAR, .battlerIDOrPartySlot = BATTLER_ENEMY_FIRST, .expectationValue.hpTaken = { 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 18 } }, + { .expectationType = EXPECTATION_TYPE_HP_BAR, .battlerIDOrPartySlot = BATTLER_ENEMY_FIRST, .expectationValue.hpTaken = { 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 18 } }, + { .expectationType = EXPECTATION_TYPE_HP_BAR, .battlerIDOrPartySlot = BATTLER_ENEMY_FIRST, .expectationValue.hpTaken = { 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 18 } }, + { .expectationType = EXPECTATION_TYPE_HP_BAR, .battlerIDOrPartySlot = BATTLER_ENEMY_FIRST, .expectationValue.hpTaken = { 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 18 } }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Golisopod's EmergencyExit" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE_CONTAINS, .expectationValue.message = "sent out Litten" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Litten's Intimidate" }, + } +} +END_TEST diff --git a/data/battle_tests/abilities/emergency_exit/singles.c b/data/battle_tests/abilities/emergency_exit/no_activation_if_healed_above_50.c similarity index 90% rename from data/battle_tests/abilities/emergency_exit/singles.c rename to data/battle_tests/abilities/emergency_exit/no_activation_if_healed_above_50.c index e9d8856f51..07985b3f65 100644 --- a/data/battle_tests/abilities/emergency_exit/singles.c +++ b/data/battle_tests/abilities/emergency_exit/no_activation_if_healed_above_50.c @@ -1,4 +1,4 @@ -// Test: Emergency Exit - Recoil, Oran Berry, Switch +// Test: Emergency Exit - does not switch out when going below 50% max-HP but healed via item above 50% max-HP #include "../../battle_tests.h" BEGIN_TEST { @@ -27,10 +27,10 @@ BEGIN_TEST }, .enemyParty = { { .species = SPECIES_GOLISOPOD, - .level = 50, + .level = 55, .form = 0, .ability = ABILITY_EMERGENCY_EXIT, - .item = ITEM_ORAN_BERRY, + .item = ITEM_SITRUS_BERRY, .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, .hp = FULL_HP, .status = 0, @@ -94,10 +94,10 @@ BEGIN_TEST { ACTION_NONE, 0 }, } }, .expectations = { - { .expectationType = EXPECTATION_TYPE_HP_BAR, .battlerIDOrPartySlot = BATTLER_ENEMY_FIRST, .expectationValue.hpTaken = { 96, 96, 98, 98, 98, 102, 102, 102, 104, 104, 108, 108, 108, 110, 110, 114 } }, + { .expectationType = EXPECTATION_TYPE_HP_BAR, .battlerIDOrPartySlot = BATTLER_ENEMY_FIRST, .expectationValue.hpTaken = { 86, 90, 90, 90, 92, 92, 92, 96, 96, 96, 98, 98, 98, 102, 102, 104 } }, { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Staraptor was damaged by the recoil!" }, - { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "The opposing Golisopod restored its health using its Oran Berry!" }, - { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Staraptor's Attack fell!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "The opposing Golisopod restored its health using its Sitrus Berry!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "The opposing Golisopod used Sleep Talk!" }, } } END_TEST diff --git a/data/battle_tests/abilities/emergency_exit/only_fastest_user_switches.c b/data/battle_tests/abilities/emergency_exit/only_fastest_user_switches.c new file mode 100644 index 0000000000..d97c366915 --- /dev/null +++ b/data/battle_tests/abilities/emergency_exit/only_fastest_user_switches.c @@ -0,0 +1,129 @@ +// Test: Emergency Exit - only fastest user switches +#include "../../battle_tests.h" +BEGIN_TEST +{ + .battleType = BATTLE_TYPE_DOUBLES, + .weather = FIELD_CONDITION_NONE, + .fieldCondition = 0, + .terrain = TERRAIN_NONE, + .playerParty = { + { + .species = SPECIES_STARAPTOR, + .level = 40, + .form = 0, + .ability = ABILITY_RECKLESS, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { + .species = SPECIES_DONPHAN, + .level = 100, + .form = 0, + .ability = ABILITY_STURDY, + .item = ITEM_NONE, + .moves = { MOVE_EARTHQUAKE, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE } + }, + .enemyParty = { { + .species = SPECIES_GOLISOPOD, + .level = 5, + .form = 0, + .ability = ABILITY_EMERGENCY_EXIT, + .item = ITEM_FOCUS_SASH, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { + .species = SPECIES_GOLISOPOD, + .level = 6, + .form = 0, + .ability = ABILITY_EMERGENCY_EXIT, + .item = ITEM_FOCUS_SASH, + .moves = { MOVE_DRAGON_DANCE, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { + .species = SPECIES_LITTEN, + .level = 50, + .form = 0, + .ability = ABILITY_INTIMIDATE, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE } }, + .playerScript = { { + { ACTION_MOVE_SLOT_1, BATTLER_ENEMY_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + }, + { + { ACTION_MOVE_SLOT_1, BATTLER_ENEMY_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + } }, + .enemyScript = { { + { ACTION_MOVE_SLOT_1, BATTLER_PLAYER_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + }, + { + { ACTION_MOVE_SLOT_1, BATTLER_ENEMY_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + } }, + .expectations = { + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Donphan used Earthquake!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "It's not very effective on the opposing Golisopod or Golisopod." }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "The opposing Golisopod hung on using its Focus Sash!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "The opposing Golisopod hung on using its Focus Sash!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Golisopod's EmergencyExit" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE_CONTAINS, .expectationValue.message = "sent out Litten" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Litten's Intimidate" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "The opposing Golisopod used Sleep Talk!" }, + } +} +END_TEST diff --git a/data/battle_tests/abilities/emergency_exit/recoil.c b/data/battle_tests/abilities/emergency_exit/recoil.c new file mode 100644 index 0000000000..73246da4f7 --- /dev/null +++ b/data/battle_tests/abilities/emergency_exit/recoil.c @@ -0,0 +1,103 @@ +// Test: Emergency Exit - Emergency Exit will trigger due to recoil damage +#include "../../battle_tests.h" +BEGIN_TEST +{ + .battleType = BATTLE_TYPE_TRAINER, + .weather = FIELD_CONDITION_NONE, + .fieldCondition = 0, + .terrain = TERRAIN_NONE, + .playerParty = { + { + .species = SPECIES_STARAPTOR, + .level = 50, + .form = 0, + .ability = ABILITY_RECKLESS, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE } + }, + .enemyParty = { { + .species = SPECIES_GOLISOPOD, + .level = 50, + .form = 0, + .ability = ABILITY_EMERGENCY_EXIT, + .item = ITEM_NONE, + .moves = { MOVE_WAVE_CRASH, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = 76, //150 + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { + .species = SPECIES_LITTEN, + .level = 50, + .form = 0, + .ability = ABILITY_INTIMIDATE, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE } }, + .playerScript = { { + { ACTION_MOVE_SLOT_1, BATTLER_ENEMY_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + }, + { + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + } }, + .enemyScript = { { + { ACTION_MOVE_SLOT_1, BATTLER_PLAYER_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + }, + { + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + } }, + .expectations = { + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "The opposing Golisopod was damaged by the recoil!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Golisopod's EmergencyExit" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE_CONTAINS, .expectationValue.message = "sent out Litten" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Litten's Intimidate" }, + } +} +END_TEST diff --git a/data/battle_tests/abilities/emergency_exit/residual_damage_burn.c b/data/battle_tests/abilities/emergency_exit/residual_damage_burn.c new file mode 100644 index 0000000000..190143876a --- /dev/null +++ b/data/battle_tests/abilities/emergency_exit/residual_damage_burn.c @@ -0,0 +1,103 @@ +// Test: Emergency Exit - activates when taking residual damage and falling under 50% max-hp - Burn +#include "../../battle_tests.h" +BEGIN_TEST +{ + .battleType = BATTLE_TYPE_TRAINER, + .weather = FIELD_CONDITION_NONE, + .fieldCondition = 0, + .terrain = TERRAIN_NONE, + .playerParty = { + { + .species = SPECIES_STARAPTOR, + .level = 40, + .form = 0, + .ability = ABILITY_RECKLESS, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE } + }, + .enemyParty = { { + .species = SPECIES_GOLISOPOD, + .level = 50, + .form = 0, + .ability = ABILITY_EMERGENCY_EXIT, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = 76, //150 + .status = STATUS_BURN, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { + .species = SPECIES_LITTEN, + .level = 50, + .form = 0, + .ability = ABILITY_INTIMIDATE, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE } }, + .playerScript = { { + { ACTION_MOVE_SLOT_1, BATTLER_ENEMY_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + }, + { + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + } }, + .enemyScript = { { + { ACTION_MOVE_SLOT_1, BATTLER_PLAYER_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + }, + { + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + } }, + .expectations = { + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "The opposing Golisopod is hurt by its burn!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Golisopod's EmergencyExit" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE_CONTAINS, .expectationValue.message = "sent out Litten" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Litten's Intimidate" }, + }, +} +END_TEST diff --git a/data/battle_tests/abilities/emergency_exit/residual_damage_burn_leech_seed.c b/data/battle_tests/abilities/emergency_exit/residual_damage_burn_leech_seed.c new file mode 100644 index 0000000000..818ac5572b --- /dev/null +++ b/data/battle_tests/abilities/emergency_exit/residual_damage_burn_leech_seed.c @@ -0,0 +1,129 @@ +// Test: Emergency Exit - Residual Damage from Leech Seed, Resolve Switch, Burn damage loop without Golisopod, Speed Boost triggers +#include "../../battle_tests.h" +BEGIN_TEST +{ + .battleType = BATTLE_TYPE_DOUBLES, + .weather = FIELD_CONDITION_NONE, + .fieldCondition = 0, + .terrain = TERRAIN_NONE, + .playerParty = { + { + .species = SPECIES_FERROTHORN, + .level = 40, + .form = 0, + .ability = ABILITY_OVERGROW, + .item = ITEM_NONE, + .moves = { MOVE_LEECH_SEED, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = 50, + .status = STATUS_BURN, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { + .species = SPECIES_BLAZIKEN, + .level = 40, + .form = 0, + .ability = ABILITY_SPEED_BOOST, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE } + }, + .enemyParty = { { + .species = SPECIES_GOLISOPOD, + .level = 50, + .form = 0, + .ability = ABILITY_EMERGENCY_EXIT, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = 76, //150 + .status = STATUS_BURN, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { + .species = SPECIES_SHUCKLE, + .level = 40, + .form = 0, + .ability = ABILITY_GLUTTONY, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = STATUS_BURN, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { + .species = SPECIES_LITTEN, + .level = 50, + .form = 0, + .ability = ABILITY_INTIMIDATE, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE } }, + .playerScript = { { + { ACTION_MOVE_SLOT_1, BATTLER_ENEMY_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + }, + { + { ACTION_MOVE_SLOT_1, BATTLER_ENEMY_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + } }, + .enemyScript = { { + { ACTION_MOVE_SLOT_1, BATTLER_PLAYER_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + }, + { + { ACTION_MOVE_SLOT_1, BATTLER_ENEMY_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + } }, + .expectations = { + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "The opposing Golisopod was seeded!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "The opposing Golisopod's health is sapped by Leech Seed!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Golisopod's EmergencyExit" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE_DOES_NOT_CONTAIN, .expectationValue.message = "The opposing Golisopod is hurt by its burn!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "The opposing Shuckle is hurt by its burn!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE_CONTAINS, .expectationValue.message = "sent out Litten" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Litten's Intimidate" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Blaziken's Speed rose!" }, + }, +} +END_TEST diff --git a/data/battle_tests/abilities/emergency_exit/residual_damage_burn_speed_boost.c b/data/battle_tests/abilities/emergency_exit/residual_damage_burn_speed_boost.c new file mode 100644 index 0000000000..ad5040421c --- /dev/null +++ b/data/battle_tests/abilities/emergency_exit/residual_damage_burn_speed_boost.c @@ -0,0 +1,126 @@ +// Test: Emergency Exit - Residual Damage from Burn, Resolve Switch, Speed Boost triggers +#include "../../battle_tests.h" +BEGIN_TEST +{ + .battleType = BATTLE_TYPE_DOUBLES, + .weather = FIELD_CONDITION_NONE, + .fieldCondition = 0, + .terrain = TERRAIN_NONE, + .playerParty = { + { + .species = SPECIES_STARAPTOR, + .level = 40, + .form = 0, + .ability = ABILITY_RECKLESS, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { + .species = SPECIES_BLAZIKEN, + .level = 40, + .form = 0, + .ability = ABILITY_SPEED_BOOST, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE } + }, + .enemyParty = { { + .species = SPECIES_GOLISOPOD, + .level = 50, + .form = 0, + .ability = ABILITY_EMERGENCY_EXIT, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = 76, //150 + .status = STATUS_BURN, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { + .species = SPECIES_SHUCKLE, + .level = 40, + .form = 0, + .ability = ABILITY_GLUTTONY, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { + .species = SPECIES_LITTEN, + .level = 50, + .form = 0, + .ability = ABILITY_INTIMIDATE, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE } }, + .playerScript = { { + { ACTION_MOVE_SLOT_1, BATTLER_ENEMY_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + }, + { + { ACTION_MOVE_SLOT_1, BATTLER_ENEMY_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + } }, + .enemyScript = { { + { ACTION_MOVE_SLOT_1, BATTLER_PLAYER_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + }, + { + { ACTION_MOVE_SLOT_1, BATTLER_ENEMY_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + } }, + .expectations = { + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "The opposing Golisopod is hurt by its burn!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Golisopod's EmergencyExit" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE_CONTAINS, .expectationValue.message = "sent out Litten" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Litten's Intimidate" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Blaziken's Speed rose!" }, + }, +} +END_TEST diff --git a/data/battle_tests/abilities/emergency_exit/residual_damage_sticky_barb.c b/data/battle_tests/abilities/emergency_exit/residual_damage_sticky_barb.c new file mode 100644 index 0000000000..6af023a0d7 --- /dev/null +++ b/data/battle_tests/abilities/emergency_exit/residual_damage_sticky_barb.c @@ -0,0 +1,103 @@ +// Test: Emergency Exit - activates when taking residual damage and falling under 50% max-hp - Sticky Barb +#include "../../battle_tests.h" +BEGIN_TEST +{ + .battleType = BATTLE_TYPE_TRAINER, + .weather = FIELD_CONDITION_NONE, + .fieldCondition = 0, + .terrain = TERRAIN_NONE, + .playerParty = { + { + .species = SPECIES_STARAPTOR, + .level = 40, + .form = 0, + .ability = ABILITY_RECKLESS, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE } + }, + .enemyParty = { { + .species = SPECIES_GOLISOPOD, + .level = 50, + .form = 0, + .ability = ABILITY_EMERGENCY_EXIT, + .item = ITEM_STICKY_BARB, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = 76, // 150 + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { + .species = SPECIES_LITTEN, + .level = 50, + .form = 0, + .ability = ABILITY_INTIMIDATE, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE } }, + .playerScript = { { + { ACTION_MOVE_SLOT_1, BATTLER_ENEMY_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + }, + { + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + } }, + .enemyScript = { { + { ACTION_MOVE_SLOT_1, BATTLER_PLAYER_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + }, + { + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + } }, + .expectations = { + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "The opposing Golisopod is hurt by its Sticky Barb!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Golisopod's EmergencyExit" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE_CONTAINS, .expectationValue.message = "sent out Litten" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Litten's Intimidate" }, + }, +} +END_TEST diff --git a/data/battle_tests/abilities/emergency_exit/residual_damage_weather.c b/data/battle_tests/abilities/emergency_exit/residual_damage_weather.c new file mode 100644 index 0000000000..5f0b27ab8d --- /dev/null +++ b/data/battle_tests/abilities/emergency_exit/residual_damage_weather.c @@ -0,0 +1,103 @@ +// Test: Emergency Exit - activates when taking residual damage and falling under 50% max-hp - Sandstorm +#include "../../battle_tests.h" +BEGIN_TEST +{ + .battleType = BATTLE_TYPE_TRAINER, + .weather = FIELD_CONDITION_SANDSTORM, + .fieldCondition = 0, + .terrain = TERRAIN_NONE, + .playerParty = { + { + .species = SPECIES_STARAPTOR, + .level = 40, + .form = 0, + .ability = ABILITY_RECKLESS, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE } + }, + .enemyParty = { { + .species = SPECIES_GOLISOPOD, + .level = 50, + .form = 0, + .ability = ABILITY_EMERGENCY_EXIT, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = 76, // 150 + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { + .species = SPECIES_LITTEN, + .level = 50, + .form = 0, + .ability = ABILITY_INTIMIDATE, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE } }, + .playerScript = { { + { ACTION_MOVE_SLOT_1, BATTLER_ENEMY_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + }, + { + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + } }, + .enemyScript = { { + { ACTION_MOVE_SLOT_1, BATTLER_PLAYER_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + }, + { + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + } }, + .expectations = { + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "The opposing Golisopod is buffeted by the Sandstorm!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Golisopod's EmergencyExit" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE_CONTAINS, .expectationValue.message = "sent out Litten" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Litten's Intimidate" }, + }, +} +END_TEST diff --git a/data/battle_tests/abilities/emergency_exit/stealth_rocks.c b/data/battle_tests/abilities/emergency_exit/stealth_rocks.c new file mode 100644 index 0000000000..43cea06c53 --- /dev/null +++ b/data/battle_tests/abilities/emergency_exit/stealth_rocks.c @@ -0,0 +1,121 @@ +// Test: Emergency Exit - activates when taking damage from Stealth Rocks and going below 50% +#include "../../battle_tests.h" +BEGIN_TEST +{ + .battleType = BATTLE_TYPE_TRAINER, + .weather = FIELD_CONDITION_NONE, + .fieldCondition = 0, + .terrain = TERRAIN_NONE, + .playerParty = { + { + .species = SPECIES_SHUCKLE, + .level = 40, + .form = 0, + .ability = ABILITY_GLUTTONY, + .item = ITEM_NONE, + .moves = { MOVE_STEALTH_ROCK, MOVE_TOXIC_SPIKES, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE } + }, + .enemyParty = { { + .species = SPECIES_LITTEN, + .level = 50, + .form = 0, + .ability = ABILITY_INTIMIDATE, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { + .species = SPECIES_GOLISOPOD, + .level = 50, + .form = 0, + .ability = ABILITY_EMERGENCY_EXIT, + .item = ITEM_LUM_BERRY, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = 76, // 150 + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { + .species = SPECIES_INCINEROAR, + .level = 50, + .form = 0, + .ability = ABILITY_INTIMIDATE, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE } }, + .playerScript = { { + { ACTION_MOVE_SLOT_1, BATTLER_ENEMY_FIRST }, + { ACTION_MOVE_SLOT_2, BATTLER_ENEMY_FIRST }, + { ACTION_MOVE_SLOT_1, BATTLER_ENEMY_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + }, + { + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + } }, + .enemyScript = { { + { ACTION_MOVE_SLOT_1, BATTLER_PLAYER_FIRST }, + { ACTION_MOVE_SLOT_1, BATTLER_PLAYER_FIRST }, + { ACTION_SWITCH_SLOT_1, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + }, + { + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + } }, + .expectations = { + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "The opposing Litten used Sleep Talk!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Shuckle used Stealth Rock!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Pointed stones float in the air around the opposing side!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Shuckle used Toxic Spikes!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Poison spikes were scattered on the ground all around the opposing side!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE_CONTAINS, .expectationValue.message = "sent out Golisopod!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Pointed stones dug into the opposing Golisopod!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE_DOES_NOT_CONTAIN, .expectationValue.message = "was poisoned!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE_CONTAINS, .expectationValue.message = "sent out Litten" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Pointed stones dug into the opposing Litten!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "The opposing Litten was poisoned!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Litten's Intimidate" }, + }, +} +END_TEST diff --git a/hooks b/hooks index 1e5cbf5246..12297ef4f5 100644 --- a/hooks +++ b/hooks @@ -163,6 +163,8 @@ arm9 CreateStarterMon_hook 020960E6 1 0012 BtlCmd_TryPerishSong 02241A04 3 0012 BtlCmd_Metronome 0224089C 3 0012 BtlCmd_TryCopycat 02243A0C 3 +0012 BtlCmd_CheckSpikes 02241980 3 +0012 BtlCmd_CheckStealthRock 022446AC 3 #trainer data expansion arm9 MakeTrainerPokemonParty 08073604 3 diff --git a/include/battle.h b/include/battle.h index ffaba692f4..24f52baed6 100644 --- a/include/battle.h +++ b/include/battle.h @@ -1089,6 +1089,8 @@ struct BattleStruct { HealingWishQueue healingWishQueue; int field_condition2; // gen5+ field conditions int magicRoomCounter; + + int recoilDamage; }; enum { @@ -1976,6 +1978,12 @@ u8 LONG_CALL IsClientEnemy(void *bw, int client); */ int LONG_CALL TypeCalc(void *bw, struct BattleStruct *sp, int movenum, int movetype, int attacker, int defender, int damage, u32 *flag); +/** + * @brief used to calculate effectiveness of Stealth Rock during switch-in + * + */ +int LONG_CALL CalculateTypeEffectiveness(u8 typeMove, u8 typeMon1, u8 typeMon2); + /** * @brief sees if anticipation will automatially log a certain move (i.e. OHKO moves) * @@ -3801,4 +3809,6 @@ BOOL LONG_CALL sub_02017068(void *animManager, int battlerId); void LONG_CALL *ov12_0223B750(struct BattleSystem *battleSystem); void LONG_CALL ov12_022600F0(SysTask *task, void *data); // Task_PlayFaintingSequence +BOOL LONG_CALL IsBattlerOnField(struct BattleStruct *ctx, int battlerId); + #endif // BATTLE_H diff --git a/include/constants/battle_script_constants.h b/include/constants/battle_script_constants.h index 4bb435fec2..9b2d117b85 100644 --- a/include/constants/battle_script_constants.h +++ b/include/constants/battle_script_constants.h @@ -504,7 +504,7 @@ #define BATTLE_SUBSCRIPT_BATCH_EFFECTIVENESS (495) #define BATTLE_SUBSCRIPT_BATCH_FOLLOWUP (496) #define BATTLE_SUBSCRIPT_SUBSTITUTE_FADES (497) -#define BATTLE_SUBSCRIPT_HANDLE_WIMP_OUT (498) +#define BATTLE_SUBSCRIPT_HANDLE_WIMP_OUT_EMERGENCY_EXIT (498) #define BATTLE_SUBSCRIPT_RECOIL_HALF_MAX_HP (499) #define BATTLE_SUBSCRIPT_FUTURE_SIGHT_DAMAGE (500) #define BATTLE_SUBSCRIPT_HANDLE_HOSPITALITY (501) diff --git a/rom.ld b/rom.ld index ba5ebd2e1c..12496f1fc1 100644 --- a/rom.ld +++ b/rom.ld @@ -225,6 +225,7 @@ GetHeldItemFlingPower = 0x022558F8 | 1; GetHeldItemModifier = 0x02255844 | 1; GetNaturalGiftPower = 0x02255890 | 1; GetNaturalGiftType = 0x022558A4 | 1; +CalculateTypeEffectiveness = 0x0225264C | 1; GetArceusType = 0x02071C28 | 1; BattleWorkBattleStatusFlagGet = 0x0223B514 | 1; diff --git a/src/battle/battle_script_commands.c b/src/battle/battle_script_commands.c index 660f6b1db8..55f60dec47 100644 --- a/src/battle/battle_script_commands.c +++ b/src/battle/battle_script_commands.c @@ -140,6 +140,7 @@ BOOL btl_scr_cmd_127_ActivateHealingWish(void *bsys UNUSED, struct BattleStruct BOOL btl_scr_cmd_128_IsFieldCondition2On(void *bsys UNUSED, struct BattleStruct *ctx); BOOL btl_scr_cmd_129_SetFieldCondition2(void *bsys UNUSED, struct BattleStruct *ctx); BOOL btl_scr_cmd_12A_GoToIfMoveConditionFlagSet(void *bsys, struct BattleStruct *ctx); +BOOL btl_scr_cmd_12B_TryActivateEmergencyExit(void *bsys, struct BattleStruct *ctx); BOOL BtlCmd_GoToMoveScript(struct BattleSystem *bsys, struct BattleStruct *ctx); BOOL BtlCmd_WeatherHPRecovery(void *bw, struct BattleStruct *sp); BOOL BtlCmd_CalcWeatherBallParams(void *bw, struct BattleStruct *sp); @@ -483,6 +484,7 @@ const u8 *BattleScrCmdNames[] = { "IsFieldCondition2On", "SetFieldCondition2", "GoToIfMoveConditionFlagSet", + "TryActivateEmergencyExit" // "YourCustomCommand", }; @@ -490,7 +492,7 @@ u32 cmdAddress = 0; #pragma GCC diagnostic pop #endif // DEBUG_BATTLE_SCRIPT_COMMANDS -#define BASE_ENGINE_BTL_SCR_CMDS_MAX 0x12A +#define BASE_ENGINE_BTL_SCR_CMDS_MAX 0x12B // clang-format off const btl_scr_cmd_func NewBattleScriptCmdTable[] = { @@ -568,6 +570,7 @@ const btl_scr_cmd_func NewBattleScriptCmdTable[] = { [0x128 - START_OF_NEW_BTL_SCR_CMDS] = btl_scr_cmd_128_IsFieldCondition2On, [0x129 - START_OF_NEW_BTL_SCR_CMDS] = btl_scr_cmd_129_SetFieldCondition2, [0x12A - START_OF_NEW_BTL_SCR_CMDS] = btl_scr_cmd_12A_GoToIfMoveConditionFlagSet, + [0x12B - START_OF_NEW_BTL_SCR_CMDS] = btl_scr_cmd_12B_TryActivateEmergencyExit, // [BASE_ENGINE_BTL_SCR_CMDS_MAX - START_OF_NEW_BTL_SCR_CMDS + 1] = btl_scr_cmd_custom_01_your_custom_command, }; @@ -3144,6 +3147,72 @@ BOOL btl_scr_cmd_102_removeentryhazardfromqueue(void *bsys UNUSED, struct Battle return FALSE; } +BOOL BtlCmd_CheckSpikes(void *bw, struct BattleStruct *ctx) +{ + IncrementBattleScriptPtr(ctx, 1); + + int category = read_battle_script_param(ctx); + int adrs = read_battle_script_param(ctx); + + int battlerId = GrabClientFromBattleScriptParam(bw, ctx, category); + int fieldSide = (1 & battlerId); + + if (ctx->scw[fieldSide].spikesLayers && IsBattlerOnField(ctx, battlerId)) { + ctx->hp_calc_work = (5 - ctx->scw[fieldSide].spikesLayers) * 2; + ctx->hp_calc_work = BattleDamageDivide(ctx->battlemon[battlerId].maxhp * -1, ctx->hp_calc_work); + } else { + IncrementBattleScriptPtr(ctx, adrs); + } + + return FALSE; +} + +BOOL BtlCmd_CheckStealthRock(void *bw, struct BattleStruct *ctx) +{ + IncrementBattleScriptPtr(ctx, 1); + + int category = read_battle_script_param(ctx); + int adrs = read_battle_script_param(ctx); + + int battlerId = GrabClientFromBattleScriptParam(bw, ctx, category); + int fieldSide = (1 & battlerId); + + // TODO deal with terra + int type1 = GetBattlerVar(ctx, battlerId, BMON_DATA_TYPE_1, NULL); + int type2 = GetBattlerVar(ctx, battlerId, BMON_DATA_TYPE_2, NULL); + + if (ctx->side_condition[fieldSide] & SIDE_STATUS_STEALTH_ROCK && IsBattlerOnField(ctx, battlerId)) { + switch (CalculateTypeEffectiveness(TYPE_ROCK, type1, type2)) { + case 160: + ctx->hp_calc_work = 2; + break; + case 80: + ctx->hp_calc_work = 4; + break; + case 40: + ctx->hp_calc_work = 8; + break; + case 20: + ctx->hp_calc_work = 16; + break; + case 10: + ctx->hp_calc_work = 32; + break; + case 0: + IncrementBattleScriptPtr(ctx, adrs); + return FALSE; + default: + GF_ASSERT(FALSE); + break; + } + ctx->hp_calc_work = BattleDamageDivide(ctx->battlemon[battlerId].maxhp * -1, ctx->hp_calc_work); + } else { + IncrementBattleScriptPtr(ctx, adrs); + } + + return FALSE; +} + BOOL btl_scr_cmd_103_checkprotectcontactmoves(void *bsys UNUSED, struct BattleStruct *ctx) { IncrementBattleScriptPtr(ctx, 1); @@ -4625,9 +4694,11 @@ BOOL BtlCmd_CheckToxicSpikes(struct BattleSystem *bsys, struct BattleStruct *ctx int fieldSide = IsClientEnemy(bsys, battlerID); if (ctx->scw[fieldSide].toxicSpikesLayers) { - ctx->calc_work = ctx->scw[fieldSide].toxicSpikesLayers; - ctx->addeffect_type = SIDE_EFFECT_TYPE_TOXIC_SPIKES; - ctx->state_client = battlerID; + if (IsBattlerOnField(ctx, battlerID)) { + ctx->calc_work = ctx->scw[fieldSide].toxicSpikesLayers; + ctx->addeffect_type = SIDE_EFFECT_TYPE_TOXIC_SPIKES; + ctx->state_client = battlerID; + } if (HasType(ctx, battlerID, TYPE_POISON)) { ctx->side_condition[fieldSide] &= ~SIDE_EFFECT_TYPE_TOXIC_SPIKES; ctx->scw[fieldSide].toxicSpikesLayers = 0; @@ -5883,3 +5954,30 @@ BOOL btl_scr_cmd_12A_GoToIfMoveConditionFlagSet(void *bsys, struct BattleStruct return FALSE; } + +BOOL btl_scr_cmd_12B_TryActivateEmergencyExit(void *bsys, struct BattleStruct *ctx) +{ + IncrementBattleScriptPtr(ctx, 1); + u32 side = read_battle_script_param(ctx); + u32 client_no = GrabClientFromBattleScriptParam(bsys, ctx, side); + + int noActivation = read_battle_script_param(ctx); + + if (IsBattlerOnField(ctx, client_no) + && (ctx->currentMoveSwitchStatus < CURRENT_MOVE_SWITCH_PENDING) + && ((GetBattlerAbility(ctx, client_no) == ABILITY_WIMP_OUT) // not affected by Mold Breaker + || (GetBattlerAbility(ctx, client_no) == ABILITY_EMERGENCY_EXIT)) + //&& ((ctx->battlemon[client_no].effect_of_moves & MOVE_EFFECT_FLAG_SEMI_INVULNERABLE) == 0) // unsure if bug + && (ctx->battlemon[client_no].hp <= (s32)(ctx->battlemon[client_no].maxhp / 2)) + // EE can be triggered by any residual damage, such as Burn, Sandstorm, Curse, etc + && ((ctx->battlemon[client_no].hp - ctx->hp_calc_work) > (s32)ctx->battlemon[client_no].maxhp / 2)) { + ctx->addeffect_type = SIDE_EFFECT_TYPE_ABILITY; + ctx->state_client = client_no; + ctx->battlerIdTemp = client_no; + ctx->hazardQueueTracker = 0; // TODO: script command for this would be better? + } else { + IncrementBattleScriptPtr(ctx, noActivation); + } + + return FALSE; +} diff --git a/src/battle/other_battle_calculators.c b/src/battle/other_battle_calculators.c index 133d2ee098..f01fb3a98a 100644 --- a/src/battle/other_battle_calculators.c +++ b/src/battle/other_battle_calculators.c @@ -4624,3 +4624,14 @@ BOOL LONG_CALL ShouldUseNormalTypeEffCalc(struct BattleStruct *ctx, int attack_c return ret; } + +BOOL LONG_CALL IsBattlerOnField(struct BattleStruct *ctx, int battlerId) +{ + if (ctx->battlemon[battlerId].hp == 0) { + return FALSE; + } + if (ctx->client_status[battlerId] & 1) { // switched out + return FALSE; + } + return TRUE; +} diff --git a/src/individual/BattleController_MoveEnd.c b/src/individual/BattleController_MoveEnd.c index 865ec0ad3e..1029b7c919 100644 --- a/src/individual/BattleController_MoveEnd.c +++ b/src/individual/BattleController_MoveEnd.c @@ -131,6 +131,7 @@ void LONG_CALL BattleController_MoveEndInternal(struct BattleSystem *bsys, struc ctx->futureSightSTAB = 0; ctx->currentMoveSwitchStatus = CURRENT_MOVE_NO_SWITCH; ctx->moveConditionsFlags[ctx->attack_client].mindBlownOrSteelBeam = FALSE; + ctx->recoilDamage = 0; ctx->moveContext.hitFoesCount = 0; ctx->moveContext.hitSubstituteCount = 0; diff --git a/src/individual/ServerDoPostMoveEffects.c b/src/individual/ServerDoPostMoveEffects.c index b4c9ab7330..747808c116 100644 --- a/src/individual/ServerDoPostMoveEffects.c +++ b/src/individual/ServerDoPostMoveEffects.c @@ -2104,17 +2104,21 @@ int LONG_CALL Activate_RecoilDamage(void *bsys UNUSED, struct BattleStruct *ctx) switch (moveEffect) { case MOVE_EFFECT_RECOIL_QUARTER: // wild charge seq_no = BATTLE_SUBSCRIPT_RECOIL_1_4; + ctx->recoilDamage = ctx->store_damage[ctx->attack_client] / 4; break; case MOVE_EFFECT_RECOIL_PARALYZE_HIT: // volt tackle case MOVE_EFFECT_RECOIL_BURN_HIT: // flare blitz case MOVE_EFFECT_RECOIL_THIRD: // double edge, brave bird seq_no = BATTLE_SUBSCRIPT_RECOIL_1_3; + ctx->recoilDamage = ctx->store_damage[ctx->attack_client] / 3; break; case MOVE_EFFECT_RECOIL_HALF: // head smash, light of ruin seq_no = BATTLE_SUBSCRIPT_RECOIL_1_2; + ctx->recoilDamage = ctx->store_damage[ctx->attack_client] / 2; break; case MOVE_EFFECT_RECOIL_HALF_MAX_HP: // chloroplast seq_no = BATTLE_SUBSCRIPT_RECOIL_HALF_MAX_HP; + ctx->recoilDamage = (-1) * (ctx->battlemon[ctx->attack_client].maxhp + 1) / 2; break; default: break; @@ -2655,24 +2659,36 @@ int LONG_CALL Activate_WimpOut_EmergencyExit(void *bsys, struct BattleStruct *ct continue; } - if (MoldBreakerAbilityCheck(ctx, ctx->attack_client, client_no, ABILITY_WIMP_OUT) - || MoldBreakerAbilityCheck(ctx, ctx->attack_client, client_no, ABILITY_EMERGENCY_EXIT)) { - if ((ctx->currentMoveSwitchStatus < CURRENT_MOVE_SWITCH_PENDING) - && ctx->battlemon[client_no].hp <= (s32)(ctx->battlemon[client_no].maxhp / 2) - && ((ctx->oneSelfFlag[client_no].physical_damage) || (ctx->oneSelfFlag[client_no].special_damage)) - // EE doesn't activate if the Pokémon gets attacked by a sheer force boosted move - && !((GetBattlerAbility(ctx, ctx->attack_client) == ABILITY_SHEER_FORCE) && (ctx->battlemon[ctx->attack_client].sheer_force_flag == 1)) - && (ctx->battlemon[client_no].hp <= (s32)(ctx->battlemon[client_no].maxhp / 2)) - && ( - // checks if the pokémon has gone below half HP from the current damage instance - // physical_damage and special_damage contain the relevant damage value that was just dealt, but the value is negative - ((ctx->battlemon[client_no].hp - (ctx->oneSelfFlag[client_no].physical_damage)) > (s32)ctx->battlemon[client_no].maxhp / 2) - || ((ctx->battlemon[client_no].hp - (ctx->oneSelfFlag[client_no].special_damage)) > (s32)ctx->battlemon[client_no].maxhp / 2))) { + if ((ctx->currentMoveSwitchStatus < CURRENT_MOVE_SWITCH_PENDING) + && ((GetBattlerAbility(ctx, client_no) == ABILITY_WIMP_OUT) // not affected by Mold Breaker + || (GetBattlerAbility(ctx, client_no) == ABILITY_EMERGENCY_EXIT)) + && (ctx->pursuitContext.isActive == FALSE) + //&& ((ctx->battlemon[client_no].effect_of_moves & MOVE_EFFECT_FLAG_SEMI_INVULNERABLE) == 0) // unsure if bug + && (ctx->battlemon[client_no].hp <= (s32)(ctx->battlemon[client_no].maxhp / 2))) { + BOOL canActivate = FALSE; + if (ctx->attack_client == client_no) { + // EE can be triggered by recoil if attacker. Recoil damage is stored earlier when applied + if ((ctx->battlemon[client_no].hp - ctx->recoilDamage) > (s32)(ctx->battlemon[client_no].maxhp / 2)) { + canActivate = TRUE; + } + } else { + int overallDamage = ctx->store_damage[ctx->defence_client]; + if ((ctx->oneSelfFlag[client_no].physical_damage || ctx->oneSelfFlag[client_no].special_damage) + // EE doesn't activate if the Pokémon gets attacked by a sheer force boosted move + && !((GetBattlerAbility(ctx, ctx->attack_client) == ABILITY_SHEER_FORCE) && (ctx->battlemon[ctx->attack_client].sheer_force_flag == 1)) + && ( + // checks if the pokémon has gone below half HP from the current damage instance + (ctx->battlemon[client_no].hp - overallDamage) > (s32)ctx->battlemon[client_no].maxhp / 2)) { + canActivate = TRUE; + } + } + + if (canActivate) { ctx->addeffect_type = SIDE_EFFECT_TYPE_ABILITY; ctx->state_client = client_no; ctx->battlerIdTemp = client_no; - LoadBattleSubSeqScript(ctx, ARC_BATTLE_SUB_SEQ, BATTLE_SUBSCRIPT_HANDLE_WIMP_OUT); + LoadBattleSubSeqScript(ctx, ARC_BATTLE_SUB_SEQ, BATTLE_SUBSCRIPT_HANDLE_WIMP_OUT_EMERGENCY_EXIT); ctx->next_server_seq_no = ctx->server_seq_no; ctx->server_seq_no = CONTROLLER_COMMAND_RUN_SCRIPT; return TRUE; diff --git a/src/individual/ServerFieldConditionCheck.c b/src/individual/ServerFieldConditionCheck.c index 4cbf1afda1..c2657999ae 100644 --- a/src/individual/ServerFieldConditionCheck.c +++ b/src/individual/ServerFieldConditionCheck.c @@ -288,8 +288,14 @@ void ServerFieldConditionCheck(void *bw, struct BattleStruct *sp) debug_printf("In ENDTURN_RESOLVE_SWITCHES_1\n"); #endif - sp->fcc_seq_no++; + if (sp->currentMoveSwitchStatus == CURRENT_MOVE_SWITCH_PENDING) { + LoadBattleSubSeqScript(sp, ARC_BATTLE_SUB_SEQ, BATTLE_SUBSCRIPT_SHOW_PARTY_LIST); + sp->next_server_seq_no = sp->server_seq_no; + sp->server_seq_no = CONTROLLER_COMMAND_RUN_SCRIPT; + return; + } + break; } // TODO @@ -630,8 +636,14 @@ void ServerFieldConditionCheck(void *bw, struct BattleStruct *sp) debug_printf("In ENDTURN_RESOLVE_SWITCHES_2\n"); #endif - sp->fcc_seq_no++; + if (sp->currentMoveSwitchStatus == CURRENT_MOVE_SWITCH_PENDING) { + LoadBattleSubSeqScript(sp, ARC_BATTLE_SUB_SEQ, BATTLE_SUBSCRIPT_SHOW_PARTY_LIST); + sp->next_server_seq_no = sp->server_seq_no; + sp->server_seq_no = CONTROLLER_COMMAND_RUN_SCRIPT; + return; + } + break; } case ENDTURN_AQUA_RING: { @@ -712,7 +724,8 @@ void ServerFieldConditionCheck(void *bw, struct BattleStruct *sp) if ((sp->battlemon[battlerId].effect_of_moves & MOVE_EFFECT_FLAG_LEECH_SEED) && (sp->battlemon[sp->battlemon[battlerId].effect_of_moves & MOVE_EFFECT_FLAG_LEECH_SEED_RECIPIENT].hp != 0) - && (GetBattlerAbility(sp, battlerId) != ABILITY_MAGIC_GUARD && sp->battlemon[battlerId].hp != 0)) { + && (GetBattlerAbility(sp, battlerId) != ABILITY_MAGIC_GUARD) + && IsBattlerOnField(sp, battlerId)) { sp->attack_client_work = sp->battlemon[battlerId].effect_of_moves & MOVE_EFFECT_FLAG_LEECH_SEED_RECIPIENT; sp->defence_client_work = battlerId; LoadBattleSubSeqScript(sp, ARC_BATTLE_SUB_SEQ, BATTLE_SUBSCRIPT_LEECH_SEED_EFFECT); @@ -739,14 +752,14 @@ void ServerFieldConditionCheck(void *bw, struct BattleStruct *sp) while (sp->scc_work < client_set_max) { battlerId = sp->turnOrder[sp->scc_work]; - if ((sp->battlemon[battlerId].condition & STATUS_POISON) && sp->battlemon[battlerId].hp != 0) { + if ((sp->battlemon[battlerId].condition & STATUS_POISON) && IsBattlerOnField(sp, battlerId)) { sp->battlerIdTemp = battlerId; sp->hp_calc_work = BattleDamageDivide(sp->battlemon[battlerId].maxhp * -1, 8); LoadBattleSubSeqScript(sp, ARC_BATTLE_SUB_SEQ, BATTLE_SUBSCRIPT_POISON_DAMAGE); sp->next_server_seq_no = sp->server_seq_no; sp->server_seq_no = 22; ret = 1; - } else if ((sp->battlemon[battlerId].condition & STATUS_BAD_POISON) && sp->battlemon[battlerId].hp != 0) { + } else if ((sp->battlemon[battlerId].condition & STATUS_BAD_POISON) && IsBattlerOnField(sp, battlerId)) { sp->battlerIdTemp = battlerId; sp->hp_calc_work = BattleDamageDivide(sp->battlemon[battlerId].maxhp, 16); if ((sp->battlemon[battlerId].condition & STATUS_POISON_COUNT) != STATUS_POISON_COUNT) { @@ -779,7 +792,7 @@ void ServerFieldConditionCheck(void *bw, struct BattleStruct *sp) while (sp->scc_work < client_set_max) { battlerId = sp->turnOrder[sp->scc_work]; - if ((sp->battlemon[battlerId].condition & STATUS_BURN) && sp->battlemon[battlerId].hp != 0) { + if ((sp->battlemon[battlerId].condition & STATUS_BURN) && IsBattlerOnField(sp, battlerId)) { sp->battlerIdTemp = battlerId; LoadBattleSubSeqScript(sp, ARC_BATTLE_SUB_SEQ, BATTLE_SUBSCRIPT_BURN_DAMAGE); sp->next_server_seq_no = sp->server_seq_no; @@ -806,7 +819,7 @@ void ServerFieldConditionCheck(void *bw, struct BattleStruct *sp) while (sp->scc_work < client_set_max) { battlerId = sp->turnOrder[sp->scc_work]; - if ((sp->battlemon[battlerId].condition2 & STATUS2_NIGHTMARE) && sp->battlemon[battlerId].hp != 0) { + if ((sp->battlemon[battlerId].condition2 & STATUS2_NIGHTMARE) && IsBattlerOnField(sp, battlerId)) { if (sp->battlemon[battlerId].condition & STATUS_SLEEP) { sp->battlerIdTemp = battlerId; LoadBattleSubSeqScript(sp, ARC_BATTLE_SUB_SEQ, BATTLE_SUBSCRIPT_NIGHTMARE_EFFECT); @@ -837,7 +850,7 @@ void ServerFieldConditionCheck(void *bw, struct BattleStruct *sp) while (sp->scc_work < client_set_max) { battlerId = sp->turnOrder[sp->scc_work]; - if ((sp->battlemon[battlerId].condition2 & STATUS2_CURSE) && sp->battlemon[battlerId].hp != 0) { + if ((sp->battlemon[battlerId].condition2 & STATUS2_CURSE) && IsBattlerOnField(sp, battlerId)) { sp->battlerIdTemp = battlerId; LoadBattleSubSeqScript(sp, ARC_BATTLE_SUB_SEQ, BATTLE_SUBSCRIPT_CURSE_DAMAGE); sp->next_server_seq_no = sp->server_seq_no; @@ -864,7 +877,7 @@ void ServerFieldConditionCheck(void *bw, struct BattleStruct *sp) while (sp->scc_work < client_set_max) { battlerId = sp->turnOrder[sp->scc_work]; - if (sp->binding_turns[battlerId] && sp->battlemon[battlerId].hp != 0) { + if (sp->binding_turns[battlerId] && IsBattlerOnField(sp, battlerId)) { // sp->battlemon[battlerId].condition2 -= 1 << 13; sp->binding_turns[battlerId]--; if (sp->binding_turns[battlerId]) { @@ -1229,8 +1242,14 @@ void ServerFieldConditionCheck(void *bw, struct BattleStruct *sp) debug_printf("In ENDTURN_RESOLVE_SWITCHES_3\n"); #endif - sp->fcc_seq_no++; + if (sp->currentMoveSwitchStatus == CURRENT_MOVE_SWITCH_PENDING) { + LoadBattleSubSeqScript(sp, ARC_BATTLE_SUB_SEQ, BATTLE_SUBSCRIPT_SHOW_PARTY_LIST); + sp->next_server_seq_no = sp->server_seq_no; + sp->server_seq_no = CONTROLLER_COMMAND_RUN_SCRIPT; + return; + } + break; } case ENDTURN_SECOND_EVENT_BLOCK: { @@ -1812,8 +1831,14 @@ void ServerFieldConditionCheck(void *bw, struct BattleStruct *sp) debug_printf("In ENDTURN_RESOLVE_SWITCHES_4\n"); #endif - sp->fcc_seq_no++; + if (sp->currentMoveSwitchStatus == CURRENT_MOVE_SWITCH_PENDING) { + LoadBattleSubSeqScript(sp, ARC_BATTLE_SUB_SEQ, BATTLE_SUBSCRIPT_SHOW_PARTY_LIST); + sp->next_server_seq_no = sp->server_seq_no; + sp->server_seq_no = CONTROLLER_COMMAND_RUN_SCRIPT; + return; + } + break; } // TODO @@ -1970,6 +1995,8 @@ void ServerFieldConditionCheck(void *bw, struct BattleStruct *sp) sp->playerSideHasFaintedTeammateThisTurn = 0; sp->enemySideHasFaintedTeammateThisTurn = 0; ret = 2; + + sp->currentMoveSwitchStatus = CURRENT_MOVE_NO_SWITCH; break; } } diff --git a/src/test_battle.c b/src/test_battle.c index 2f7ee51d2e..21942cdd5d 100644 --- a/src/test_battle.c +++ b/src/test_battle.c @@ -679,7 +679,7 @@ static int TestBattle_FindNextLivePartySlot(struct BattleSystem *bsys, struct Ba static BOOL TestBattle_ShouldAutoSelectKOSwitch(struct BattleSystem *bsys, struct BattleStruct *ctx, int battler) { return sCurrentScenario != NULL - && (battler == BATTLER_PLAYER_FIRST || battler == BATTLER_PLAYER_SECOND) + //&& (battler == BATTLER_PLAYER_FIRST || battler == BATTLER_PLAYER_SECOND) // do it for all && (ctx->client_status[battler] & 1) && TestBattle_FindNextLivePartySlot(bsys, ctx, battler) != 6; }