From 4635f0e0f857af389dcb924b770e4c47d50a15bb Mon Sep 17 00:00:00 2001 From: Eduardo Quezada Date: Sun, 1 Dec 2024 18:36:25 -0300 Subject: [PATCH] Converted Stance Change to proper Form Change + Tests (#5749) --- include/constants/form_change_types.h | 12 +++- src/battle_script_commands.c | 29 +++------ src/battle_util.c | 12 +++- src/data/pokemon/form_change_tables.h | 11 ++-- test/battle/ability/stance_change.c | 84 +++++++++++++++++++++++++++ 5 files changed, 115 insertions(+), 33 deletions(-) create mode 100644 test/battle/ability/stance_change.c diff --git a/include/constants/form_change_types.h b/include/constants/form_change_types.h index 79a8a4cee7bb..8af9740cad02 100644 --- a/include/constants/form_change_types.h +++ b/include/constants/form_change_types.h @@ -134,8 +134,14 @@ // param1: amount of days #define FORM_CHANGE_DAYS_PASSED 23 -// Form change for Aegislash -#define FORM_CHANGE_BATTLE_ATTACK 24 -#define FORM_CHANGE_BATTLE_KINGS_SHIELD 25 +// Form change that activates before using a move. +// param1: move to check +// param2: ability to check, optional +#define FORM_CHANGE_BATTLE_BEFORE_MOVE 24 + +// Form change that activates before using a specific move category. +// param1: move category to check +// param2: ability to check, optional +#define FORM_CHANGE_BATTLE_BEFORE_MOVE_CATEGORY 25 #endif // GUARD_CONSTANTS_FORM_CHANGE_TYPES_H diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 0390f0e85a45..29c1c02edcc6 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1125,29 +1125,14 @@ static bool32 NoTargetPresent(u8 battler, u32 move) return FALSE; } -static bool32 TryAegiFormChange(void) +static bool32 TryFormChangeBeforeMove(void) { - // Only Aegislash with Stance Change can transform, transformed mons cannot. - if (GetBattlerAbility(gBattlerAttacker) != ABILITY_STANCE_CHANGE - || gBattleMons[gBattlerAttacker].status2 & STATUS2_TRANSFORMED) + bool32 result = TryBattleFormChange(gBattlerAttacker, FORM_CHANGE_BATTLE_BEFORE_MOVE); + if (!result) + result = TryBattleFormChange(gBattlerAttacker, FORM_CHANGE_BATTLE_BEFORE_MOVE_CATEGORY); + if (!result) return FALSE; - switch (gBattleMons[gBattlerAttacker].species) - { - default: - return FALSE; - case SPECIES_AEGISLASH_SHIELD: // Shield -> Blade - if (IS_MOVE_STATUS(gCurrentMove)) - return FALSE; - TryBattleFormChange(gBattlerAttacker, FORM_CHANGE_BATTLE_ATTACK); - break; - case SPECIES_AEGISLASH_BLADE: // Blade -> Shield - if (gCurrentMove != MOVE_KINGS_SHIELD) - return FALSE; - TryBattleFormChange(gBattlerAttacker, FORM_CHANGE_BATTLE_KINGS_SHIELD); - break; - } - BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_AttackerFormChange; return TRUE; @@ -1221,7 +1206,7 @@ static void Cmd_attackcanceler(void) gBattlescriptCurrInstr = BattleScript_MoveEnd; return; } - if (B_STANCE_CHANGE_FAIL < GEN_7 && TryAegiFormChange()) + if (B_STANCE_CHANGE_FAIL < GEN_7 && TryFormChangeBeforeMove()) return; if (AtkCanceller_UnableToUseMove(moveType)) return; @@ -1282,7 +1267,7 @@ static void Cmd_attackcanceler(void) gMoveResultFlags |= MOVE_RESULT_MISSED; return; } - if (B_STANCE_CHANGE_FAIL >= GEN_7 && TryAegiFormChange()) + if (B_STANCE_CHANGE_FAIL >= GEN_7 && TryFormChangeBeforeMove()) return; gHitMarker &= ~HITMARKER_ALLOW_NO_PP; diff --git a/src/battle_util.c b/src/battle_util.c index bcd43f8962cc..5238bbfc53df 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -10988,9 +10988,15 @@ u16 GetBattleFormChangeTargetSpecies(u32 battler, u16 method) if (GetBattlerTeraType(battler) == formChanges[i].param1) targetSpecies = formChanges[i].targetSpecies; break; - case FORM_CHANGE_BATTLE_ATTACK: - case FORM_CHANGE_BATTLE_KINGS_SHIELD: - targetSpecies = formChanges[i].targetSpecies; + case FORM_CHANGE_BATTLE_BEFORE_MOVE: + if (formChanges[i].param1 == gCurrentMove + && (formChanges[i].param2 == ABILITY_NONE || formChanges[i].param2 == GetBattlerAbility(battler))) + targetSpecies = formChanges[i].targetSpecies; + break; + case FORM_CHANGE_BATTLE_BEFORE_MOVE_CATEGORY: + if (formChanges[i].param1 == GetBattleMoveCategory(gCurrentMove) + && (formChanges[i].param2 == ABILITY_NONE || formChanges[i].param2 == GetBattlerAbility(battler))) + targetSpecies = formChanges[i].targetSpecies; break; } } diff --git a/src/data/pokemon/form_change_tables.h b/src/data/pokemon/form_change_tables.h index 4af68ce31825..340bdb1fa6cb 100644 --- a/src/data/pokemon/form_change_tables.h +++ b/src/data/pokemon/form_change_tables.h @@ -789,11 +789,12 @@ static const struct FormChange sFurfrouFormChangeTable[] = { #if P_FAMILY_HONEDGE static const struct FormChange sAegislashFormChangeTable[] = { - {FORM_CHANGE_BATTLE_ATTACK, SPECIES_AEGISLASH_BLADE}, - {FORM_CHANGE_BATTLE_KINGS_SHIELD, SPECIES_AEGISLASH_SHIELD}, - {FORM_CHANGE_BATTLE_SWITCH, SPECIES_AEGISLASH_SHIELD}, - {FORM_CHANGE_FAINT, SPECIES_AEGISLASH_SHIELD}, - {FORM_CHANGE_END_BATTLE, SPECIES_AEGISLASH_SHIELD}, + {FORM_CHANGE_BATTLE_BEFORE_MOVE_CATEGORY, SPECIES_AEGISLASH_BLADE, DAMAGE_CATEGORY_PHYSICAL, ABILITY_STANCE_CHANGE}, + {FORM_CHANGE_BATTLE_BEFORE_MOVE_CATEGORY, SPECIES_AEGISLASH_BLADE, DAMAGE_CATEGORY_SPECIAL, ABILITY_STANCE_CHANGE}, + {FORM_CHANGE_BATTLE_BEFORE_MOVE, SPECIES_AEGISLASH_SHIELD, MOVE_KINGS_SHIELD, ABILITY_STANCE_CHANGE}, + {FORM_CHANGE_BATTLE_SWITCH, SPECIES_AEGISLASH_SHIELD}, + {FORM_CHANGE_FAINT, SPECIES_AEGISLASH_SHIELD}, + {FORM_CHANGE_END_BATTLE, SPECIES_AEGISLASH_SHIELD}, {FORM_CHANGE_TERMINATOR}, }; #endif //P_FAMILY_HONEDGE diff --git a/test/battle/ability/stance_change.c b/test/battle/ability/stance_change.c new file mode 100644 index 000000000000..8221e16385b4 --- /dev/null +++ b/test/battle/ability/stance_change.c @@ -0,0 +1,84 @@ +#include "global.h" +#include "test/battle.h" + + +SINGLE_BATTLE_TEST("Stance Change changes Aegislash from Shield to Blade when using a damaging move") +{ + u16 move; + PARAMETRIZE { move = MOVE_TACKLE; } + PARAMETRIZE { move = MOVE_SWIFT; } + PARAMETRIZE { move = MOVE_GROWL; } + GIVEN { + PLAYER(SPECIES_AEGISLASH_SHIELD); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, move); } + } SCENE { + if (move != MOVE_GROWL) { + ABILITY_POPUP(player, ABILITY_STANCE_CHANGE); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + } else { + NONE_OF { + ABILITY_POPUP(player, ABILITY_STANCE_CHANGE); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + } + } + ANIMATION(ANIM_TYPE_MOVE, move, player); + } THEN { + if (move != MOVE_GROWL) + EXPECT_EQ(player->species, SPECIES_AEGISLASH_BLADE); + else + EXPECT_EQ(player->species, SPECIES_AEGISLASH_SHIELD); + } +} + +SINGLE_BATTLE_TEST("Stance Change changes Aegislash from Blade to Shield when using King's Shield") +{ + u16 move; + PARAMETRIZE { move = MOVE_PROTECT; } + PARAMETRIZE { move = MOVE_KINGS_SHIELD; } + GIVEN { + PLAYER(SPECIES_AEGISLASH_BLADE); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, move); } + } SCENE { + if (move == MOVE_KINGS_SHIELD) { + ABILITY_POPUP(player, ABILITY_STANCE_CHANGE); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + } else { + NONE_OF { + ABILITY_POPUP(player, ABILITY_STANCE_CHANGE); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + } + } + ANIMATION(ANIM_TYPE_MOVE, move, player); + } THEN { + if (move == MOVE_KINGS_SHIELD) + EXPECT_EQ(player->species, SPECIES_AEGISLASH_SHIELD); + else + EXPECT_EQ(player->species, SPECIES_AEGISLASH_BLADE); + } +} + +SINGLE_BATTLE_TEST("Stance Change doesn't change Aegislash to Shield if King's Shield is called by a different move - Sleep Talk") +{ + KNOWN_FAILING; // Currently does change form + GIVEN { + ASSUME(gMovesInfo[MOVE_SLEEP_TALK].effect == EFFECT_SLEEP_TALK); + PLAYER(SPECIES_AEGISLASH_BLADE) { Moves(MOVE_KINGS_SHIELD, MOVE_SLEEP_TALK); Status1(STATUS1_SLEEP_TURN(3)); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_SLEEP_TALK); } + } SCENE { + NONE_OF { + ABILITY_POPUP(player, ABILITY_STANCE_CHANGE); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + } + ANIMATION(ANIM_TYPE_MOVE, MOVE_KINGS_SHIELD, player); + } THEN { + EXPECT_EQ(player->species, SPECIES_AEGISLASH_BLADE); + } +} + +TO_DO_BATTLE_TEST("Stance Change doesn't change Aegislash to Shield if King's Shield is called by a different move - Me First");