From 292b528e70c38c349869c8116c2e48e1e872979f Mon Sep 17 00:00:00 2001 From: Pawkkie Date: Fri, 31 May 2024 21:39:26 -0400 Subject: [PATCH 01/21] First draft --- test/battle/ability/clear_body.c | 214 +++++++++++++++++++++++++++++-- 1 file changed, 203 insertions(+), 11 deletions(-) diff --git a/test/battle/ability/clear_body.c b/test/battle/ability/clear_body.c index 7f167c9fe7..0200601bb2 100644 --- a/test/battle/ability/clear_body.c +++ b/test/battle/ability/clear_body.c @@ -17,7 +17,7 @@ SINGLE_BATTLE_TEST("Clear Body prevents intimidate") } SCENE { HP_BAR(player, captureDamage: &turnOneHit); ABILITY_POPUP(player, ABILITY_INTIMIDATE); - NONE_OF { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); } + NONE_OF { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); } ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); MESSAGE("Foe Beldum's Clear Body prevents stat loss!"); HP_BAR(player, captureDamage: &turnTwoHit); @@ -26,13 +26,205 @@ SINGLE_BATTLE_TEST("Clear Body prevents intimidate") } } -TO_DO_BATTLE_TEST("Clear Body prevents stat stage reduction from moves"); // Growl, Leer, Confide, Fake Tears, Scary Face, Sweet Scent, Sand Attack (Attack, Defense, Sp. Attack, Sp. Defense, Speed, Evasion, Accuracy -TO_DO_BATTLE_TEST("Clear Body prevents Sticky Web"); -TO_DO_BATTLE_TEST("Clear Body doesn't prevent stat stage reduction from moves used by the user"); // e.g. Superpower -TO_DO_BATTLE_TEST("Clear Body doesn't prevent Speed reduction from Iron Ball"); -TO_DO_BATTLE_TEST("Clear Body doesn't prevent Speed reduction from paralysis"); -TO_DO_BATTLE_TEST("Clear Body doesn't prevent Attack reduction from burn"); -TO_DO_BATTLE_TEST("Clear Body doesn't prevent receiving negative stat changes from Baton Pass"); -TO_DO_BATTLE_TEST("Clear Body doesn't prevent Topsy-Turvy"); -TO_DO_BATTLE_TEST("Clear Body doesn't prevent Spectral Thief from resetting positive stat changes"); -TO_DO_BATTLE_TEST("Clear Body is ignored by Mold Breaker"); +SINGLE_BATTLE_TEST("Clear Body prevents stat stage reduction from moves") +{ + u16 move; + PARAMETRIZE{ move = MOVE_GROWL; } + PARAMETRIZE{ move = MOVE_LEER; } + PARAMETRIZE{ move = MOVE_CONFIDE; } + PARAMETRIZE{ move = MOVE_FAKE_TEARS; } + PARAMETRIZE{ move = MOVE_SCARY_FACE; } + PARAMETRIZE{ move = MOVE_SWEET_SCENT; } + PARAMETRIZE{ move = MOVE_SAND_ATTACK; } + + GIVEN { + ASSUME(gMovesInfo[MOVE_GROWL].effect == EFFECT_ATTACK_DOWN); + ASSUME(gMovesInfo[MOVE_LEER].effect == EFFECT_DEFENSE_DOWN); + ASSUME(gMovesInfo[MOVE_CONFIDE].effect == EFFECT_SPECIAL_ATTACK_DOWN); + ASSUME(gMovesInfo[MOVE_FAKE_TEARS].effect == EFFECT_SPECIAL_DEFENSE_DOWN); + ASSUME(gMovesInfo[MOVE_SCARY_FACE].effect == EFFECT_SPEED_DOWN_2); + ASSUME(gMovesInfo[MOVE_SWEET_SCENT].effect == EFFECT_EVASION_DOWN); + ASSUME(gMovesInfo[MOVE_SAND_ATTACK].effect == EFFECT_ACCURACY_DOWN); + PLAYER(SPECIES_ZIGZAGOON) { Moves(move); } + OPPONENT(SPECIES_BELDUM) { Ability(ABILITY_CLEAR_BODY); } + } WHEN { + TURN{ MOVE(player, move); } + } SCENE { + NONE_OF { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); } + ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); + MESSAGE("Foe Beldum's Clear Body prevents stat loss!"); + } +} + +SINGLE_BATTLE_TEST("Clear Body prevents Sticky Web") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_STICKY_WEB].effect == EFFECT_STICKY_WEB); + ASSUME(gMovesInfo[MOVE_SELF_DESTRUCT].effect == EFFECT_EXPLOSION); + PLAYER(SPECIES_ARIADOS) { Speed(2); Moves(MOVE_STICKY_WEB, MOVE_PROTECT); } + OPPONENT(SPECIES_SNORLAX) { Speed(1); Moves(MOVE_CELEBRATE, MOVE_SELF_DESTRUCT); } + OPPONENT(SPECIES_BELDUM) { Speed(1); Ability(ABILITY_CLEAR_BODY); } + } WHEN { + TURN{ MOVE(player, MOVE_STICKY_WEB); MOVE(opponent, MOVE_CELEBRATE); } + TURN{ MOVE(player, MOVE_PROTECT); MOVE(opponent, MOVE_SELF_DESTRUCT); SEND_OUT(opponent, 1); } + } SCENE { + NONE_OF { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); } + ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); + MESSAGE("Foe Beldum's Clear Body prevents stat loss!"); + } +} + +SINGLE_BATTLE_TEST("Clear Body doesn't prevent stat stage reduction from moves used by the user") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_SUPERPOWER].additionalEffects->moveEffect == MOVE_EFFECT_ATK_DEF_DOWN); + PLAYER(SPECIES_ODDISH) + OPPONENT(SPECIES_BELDUM) { Moves(MOVE_SUPERPOWER); Ability(ABILITY_CLEAR_BODY); } + } WHEN { + TURN{ MOVE(opponent, MOVE_SUPERPOWER); } + } SCENE { + NONE_OF { ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); MESSAGE("Foe Beldum's Clear Body prevents stat loss!"); } + } +} + +SINGLE_BATTLE_TEST("Clear Body is ignored by Mold Breaker") +{ + u16 move; + PARAMETRIZE{ move = MOVE_GROWL; } + PARAMETRIZE{ move = MOVE_LEER; } + PARAMETRIZE{ move = MOVE_CONFIDE; } + PARAMETRIZE{ move = MOVE_FAKE_TEARS; } + PARAMETRIZE{ move = MOVE_SCARY_FACE; } + PARAMETRIZE{ move = MOVE_SWEET_SCENT; } + PARAMETRIZE{ move = MOVE_SAND_ATTACK; } + + GIVEN { + PLAYER(SPECIES_ZIGZAGOON) { Ability(ABILITY_MOLD_BREAKER); Moves(move); } + OPPONENT(SPECIES_BELDUM) { Ability(ABILITY_CLEAR_BODY); } + } WHEN { + TURN{ MOVE(player, move); } + } SCENE { + NONE_OF { ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); MESSAGE("Foe Beldum's Clear Body prevents stat loss!"); } + } +} + +SINGLE_BATTLE_TEST("Clear Body doesn't prevent Speed reduction from Iron Ball") +{ + u16 heldItem; + PARAMETRIZE{ heldItem = ITEM_NONE; } + PARAMETRIZE{ heldItem = ITEM_IRON_BALL; } + GIVEN { + ASSUME(gItemsInfo[ITEM_IRON_BALL].holdEffect == HOLD_EFFECT_IRON_BALL); + PLAYER(SPECIES_ZIGZAGOON) { Speed(4); } + OPPONENT(SPECIES_BELDUM) { Speed(6); Ability(ABILITY_CLEAR_BODY); Item(heldItem); } + } WHEN { + TURN{ MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + if (heldItem == ITEM_IRON_BALL) + { + MESSAGE("Zigzagoon used Celebrate!"); + MESSAGE("Foe Beldum used Celebrate!"); + } + else + { + MESSAGE("Foe Beldum used Celebrate!"); + MESSAGE("Zigzagoon used Celebrate!"); + } + } +} + +SINGLE_BATTLE_TEST("Clear Body doesn't prevent Speed reduction from paralysis") +{ + GIVEN { + PLAYER(SPECIES_ZIGZAGOON) { Speed(4); Moves(MOVE_THUNDER_WAVE); } + OPPONENT(SPECIES_BELDUM) { Speed(6); Ability(ABILITY_CLEAR_BODY); } + } WHEN { + TURN{ MOVE(player, MOVE_THUNDER_WAVE); MOVE(opponent, MOVE_CELEBRATE); } + TURN{ MOVE(player, MOVE_THUNDER_WAVE); MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + MESSAGE("Foe Beldum used Celebrate!"); + MESSAGE("Zigzagoon used Thunder Wave!"); + MESSAGE("Zigzagoon used Thunder Wave!"); + ONE_OF { + MESSAGE("Foe Beldum used Celebrate!"); + MESSAGE("Foe Beldum is paralyzed! It can't move!"); + } + } +} + +SINGLE_BATTLE_TEST("Clear Body doesn't prevent Attack reduction from burn", s16 damage) +{ + bool32 burned; + PARAMETRIZE{ burned = FALSE; } + PARAMETRIZE{ burned = TRUE; } + GIVEN { + ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + PLAYER(SPECIES_WOBBUFFET) + OPPONENT(SPECIES_BELDUM) { Ability(ABILITY_CLEAR_BODY); if (burned) Status1(STATUS1_BURN); } + } WHEN { + TURN{ MOVE(opponent, MOVE_TACKLE); } + } SCENE { + HP_BAR(player, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Clear Body doesn't prevent receiving negative stat changes from Baton Pass") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_SCARY_FACE].effect == EFFECT_SPEED_DOWN_2); + ASSUME(gMovesInfo[MOVE_BATON_PASS].effect == EFFECT_BATON_PASS); + PLAYER(SPECIES_ZIGZAGOON) { Speed(4); Moves(MOVE_SCARY_FACE); } + OPPONENT(SPECIES_EEVEE) { Speed(3); Moves(MOVE_BATON_PASS, MOVE_CELEBRATE); } + OPPONENT(SPECIES_BELDUM) { Speed(6); Ability(ABILITY_CLEAR_BODY); } + } WHEN { + TURN{ MOVE(player, MOVE_SCARY_FACE); MOVE(opponent, MOVE_BATON_PASS); SEND_OUT(opponent, 1); } + TURN{ MOVE(player, MOVE_SCARY_FACE); MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + MESSAGE("Zigzagoon used Scary Face!"); + MESSAGE("Foe Beldum used Celebrate!"); + } +} + +SINGLE_BATTLE_TEST("Clear Body doesn't prevent Topsy-Turvy") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_TOPSY_TURVY].effect == EFFECT_TOPSY_TURVY); + ASSUME(gMovesInfo[MOVE_SCARY_FACE].effect == EFFECT_SPEED_DOWN_2); + ASSUME(gMovesInfo[MOVE_BATON_PASS].effect == EFFECT_BATON_PASS); + PLAYER(SPECIES_INKAY) { Speed(4); Moves(MOVE_SCARY_FACE, MOVE_TOPSY_TURVY); } + OPPONENT(SPECIES_EEVEE) { Speed(3); Moves(MOVE_BATON_PASS, MOVE_CELEBRATE); } + OPPONENT(SPECIES_BELDUM) { Speed(6); Ability(ABILITY_CLEAR_BODY); } + } WHEN { + TURN{ MOVE(player, MOVE_SCARY_FACE); MOVE(opponent, MOVE_BATON_PASS); SEND_OUT(opponent, 1); } + TURN{ MOVE(player, MOVE_TOPSY_TURVY); MOVE(opponent, MOVE_CELEBRATE); } + TURN{ MOVE(player, MOVE_SCARY_FACE); MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + MESSAGE("Inkay used Topsy-Turvy!"); + MESSAGE("Foe Beldum used Celebrate!"); + MESSAGE("Foe Beldum used Celebrate!"); + MESSAGE("Inkay used Scary Face!"); + } +} + +SINGLE_BATTLE_TEST("Clear Body doesn't prevent Spectral Thief from resetting positive stat changes") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_SPECTRAL_THIEF].additionalEffects->moveEffect == MOVE_EFFECT_SPECTRAL_THIEF); + ASSUME(gMovesInfo[MOVE_AGILITY].effect == EFFECT_SPEED_UP_2); + PLAYER(SPECIES_ZIGZAGOON) { Speed(4); Moves(MOVE_SPECTRAL_THIEF, MOVE_CELEBRATE); } + OPPONENT(SPECIES_BELDUM) { Speed(5); Ability(ABILITY_CLEAR_BODY); Moves(MOVE_AGILITY, MOVE_CELEBRATE); } + } WHEN { + TURN{ MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_AGILITY); } + TURN{ MOVE(player, MOVE_SPECTRAL_THIEF); MOVE(opponent, MOVE_CELEBRATE); } + TURN{ MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + MESSAGE("Foe Beldum used Agility!"); + MESSAGE("Zigzagoon used Celebrate!"); + MESSAGE("Foe Beldum used Celebrate!"); + MESSAGE("Zigzagoon used Spectral Thief!"); + MESSAGE("Zigzagoon used Celebrate!"); + MESSAGE("Foe Beldum used Celebrate!"); + } +} From 167a898bc06cc6d0b625d70fe26e5b1c8da616d5 Mon Sep 17 00:00:00 2001 From: Pawkkie Date: Fri, 31 May 2024 22:05:35 -0400 Subject: [PATCH 02/21] WOBBUFFET + cleanup --- test/battle/ability/clear_body.c | 56 ++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/test/battle/ability/clear_body.c b/test/battle/ability/clear_body.c index 0200601bb2..6fb1e127bc 100644 --- a/test/battle/ability/clear_body.c +++ b/test/battle/ability/clear_body.c @@ -45,7 +45,7 @@ SINGLE_BATTLE_TEST("Clear Body prevents stat stage reduction from moves") ASSUME(gMovesInfo[MOVE_SCARY_FACE].effect == EFFECT_SPEED_DOWN_2); ASSUME(gMovesInfo[MOVE_SWEET_SCENT].effect == EFFECT_EVASION_DOWN); ASSUME(gMovesInfo[MOVE_SAND_ATTACK].effect == EFFECT_ACCURACY_DOWN); - PLAYER(SPECIES_ZIGZAGOON) { Moves(move); } + PLAYER(SPECIES_WOBBUFFET) { Moves(move); } OPPONENT(SPECIES_BELDUM) { Ability(ABILITY_CLEAR_BODY); } } WHEN { TURN{ MOVE(player, move); } @@ -60,13 +60,12 @@ SINGLE_BATTLE_TEST("Clear Body prevents Sticky Web") { GIVEN { ASSUME(gMovesInfo[MOVE_STICKY_WEB].effect == EFFECT_STICKY_WEB); - ASSUME(gMovesInfo[MOVE_SELF_DESTRUCT].effect == EFFECT_EXPLOSION); - PLAYER(SPECIES_ARIADOS) { Speed(2); Moves(MOVE_STICKY_WEB, MOVE_PROTECT); } - OPPONENT(SPECIES_SNORLAX) { Speed(1); Moves(MOVE_CELEBRATE, MOVE_SELF_DESTRUCT); } - OPPONENT(SPECIES_BELDUM) { Speed(1); Ability(ABILITY_CLEAR_BODY); } + PLAYER(SPECIES_WOBBUFFET) + OPPONENT(SPECIES_WOBBUFFET) + OPPONENT(SPECIES_BELDUM) { Ability(ABILITY_CLEAR_BODY); } } WHEN { TURN{ MOVE(player, MOVE_STICKY_WEB); MOVE(opponent, MOVE_CELEBRATE); } - TURN{ MOVE(player, MOVE_PROTECT); MOVE(opponent, MOVE_SELF_DESTRUCT); SEND_OUT(opponent, 1); } + TURN{ SWITCH(opponent, 1); } } SCENE { NONE_OF { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); } ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); @@ -78,7 +77,7 @@ SINGLE_BATTLE_TEST("Clear Body doesn't prevent stat stage reduction from moves u { GIVEN { ASSUME(gMovesInfo[MOVE_SUPERPOWER].additionalEffects->moveEffect == MOVE_EFFECT_ATK_DEF_DOWN); - PLAYER(SPECIES_ODDISH) + PLAYER(SPECIES_WOBBUFFET) OPPONENT(SPECIES_BELDUM) { Moves(MOVE_SUPERPOWER); Ability(ABILITY_CLEAR_BODY); } } WHEN { TURN{ MOVE(opponent, MOVE_SUPERPOWER); } @@ -99,7 +98,14 @@ SINGLE_BATTLE_TEST("Clear Body is ignored by Mold Breaker") PARAMETRIZE{ move = MOVE_SAND_ATTACK; } GIVEN { - PLAYER(SPECIES_ZIGZAGOON) { Ability(ABILITY_MOLD_BREAKER); Moves(move); } + ASSUME(gMovesInfo[MOVE_GROWL].effect == EFFECT_ATTACK_DOWN); + ASSUME(gMovesInfo[MOVE_LEER].effect == EFFECT_DEFENSE_DOWN); + ASSUME(gMovesInfo[MOVE_CONFIDE].effect == EFFECT_SPECIAL_ATTACK_DOWN); + ASSUME(gMovesInfo[MOVE_FAKE_TEARS].effect == EFFECT_SPECIAL_DEFENSE_DOWN); + ASSUME(gMovesInfo[MOVE_SCARY_FACE].effect == EFFECT_SPEED_DOWN_2); + ASSUME(gMovesInfo[MOVE_SWEET_SCENT].effect == EFFECT_EVASION_DOWN); + ASSUME(gMovesInfo[MOVE_SAND_ATTACK].effect == EFFECT_ACCURACY_DOWN); + PLAYER(SPECIES_PINSIR) { Ability(ABILITY_MOLD_BREAKER); Moves(move); } OPPONENT(SPECIES_BELDUM) { Ability(ABILITY_CLEAR_BODY); } } WHEN { TURN{ MOVE(player, move); } @@ -115,20 +121,20 @@ SINGLE_BATTLE_TEST("Clear Body doesn't prevent Speed reduction from Iron Ball") PARAMETRIZE{ heldItem = ITEM_IRON_BALL; } GIVEN { ASSUME(gItemsInfo[ITEM_IRON_BALL].holdEffect == HOLD_EFFECT_IRON_BALL); - PLAYER(SPECIES_ZIGZAGOON) { Speed(4); } + PLAYER(SPECIES_WOBBUFFET) { Speed(4); } OPPONENT(SPECIES_BELDUM) { Speed(6); Ability(ABILITY_CLEAR_BODY); Item(heldItem); } } WHEN { TURN{ MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } } SCENE { if (heldItem == ITEM_IRON_BALL) { - MESSAGE("Zigzagoon used Celebrate!"); + MESSAGE("Wobbuffet used Celebrate!"); MESSAGE("Foe Beldum used Celebrate!"); } else { MESSAGE("Foe Beldum used Celebrate!"); - MESSAGE("Zigzagoon used Celebrate!"); + MESSAGE("Wobbuffet used Celebrate!"); } } } @@ -136,15 +142,15 @@ SINGLE_BATTLE_TEST("Clear Body doesn't prevent Speed reduction from Iron Ball") SINGLE_BATTLE_TEST("Clear Body doesn't prevent Speed reduction from paralysis") { GIVEN { - PLAYER(SPECIES_ZIGZAGOON) { Speed(4); Moves(MOVE_THUNDER_WAVE); } + PLAYER(SPECIES_WOBBUFFET) { Speed(4); Moves(MOVE_THUNDER_WAVE); } OPPONENT(SPECIES_BELDUM) { Speed(6); Ability(ABILITY_CLEAR_BODY); } } WHEN { TURN{ MOVE(player, MOVE_THUNDER_WAVE); MOVE(opponent, MOVE_CELEBRATE); } TURN{ MOVE(player, MOVE_THUNDER_WAVE); MOVE(opponent, MOVE_CELEBRATE); } } SCENE { MESSAGE("Foe Beldum used Celebrate!"); - MESSAGE("Zigzagoon used Thunder Wave!"); - MESSAGE("Zigzagoon used Thunder Wave!"); + MESSAGE("Wobbuffet used Thunder Wave!"); + MESSAGE("Wobbuffet used Thunder Wave!"); ONE_OF { MESSAGE("Foe Beldum used Celebrate!"); MESSAGE("Foe Beldum is paralyzed! It can't move!"); @@ -175,14 +181,14 @@ SINGLE_BATTLE_TEST("Clear Body doesn't prevent receiving negative stat changes f GIVEN { ASSUME(gMovesInfo[MOVE_SCARY_FACE].effect == EFFECT_SPEED_DOWN_2); ASSUME(gMovesInfo[MOVE_BATON_PASS].effect == EFFECT_BATON_PASS); - PLAYER(SPECIES_ZIGZAGOON) { Speed(4); Moves(MOVE_SCARY_FACE); } - OPPONENT(SPECIES_EEVEE) { Speed(3); Moves(MOVE_BATON_PASS, MOVE_CELEBRATE); } + PLAYER(SPECIES_WOBBUFFET) { Speed(4); Moves(MOVE_SCARY_FACE); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(3); Moves(MOVE_BATON_PASS); } OPPONENT(SPECIES_BELDUM) { Speed(6); Ability(ABILITY_CLEAR_BODY); } } WHEN { TURN{ MOVE(player, MOVE_SCARY_FACE); MOVE(opponent, MOVE_BATON_PASS); SEND_OUT(opponent, 1); } TURN{ MOVE(player, MOVE_SCARY_FACE); MOVE(opponent, MOVE_CELEBRATE); } } SCENE { - MESSAGE("Zigzagoon used Scary Face!"); + MESSAGE("Wobbuffet used Scary Face!"); MESSAGE("Foe Beldum used Celebrate!"); } } @@ -193,18 +199,18 @@ SINGLE_BATTLE_TEST("Clear Body doesn't prevent Topsy-Turvy") ASSUME(gMovesInfo[MOVE_TOPSY_TURVY].effect == EFFECT_TOPSY_TURVY); ASSUME(gMovesInfo[MOVE_SCARY_FACE].effect == EFFECT_SPEED_DOWN_2); ASSUME(gMovesInfo[MOVE_BATON_PASS].effect == EFFECT_BATON_PASS); - PLAYER(SPECIES_INKAY) { Speed(4); Moves(MOVE_SCARY_FACE, MOVE_TOPSY_TURVY); } - OPPONENT(SPECIES_EEVEE) { Speed(3); Moves(MOVE_BATON_PASS, MOVE_CELEBRATE); } + PLAYER(SPECIES_WOBBUFFET) { Speed(4); Moves(MOVE_SCARY_FACE, MOVE_TOPSY_TURVY); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(3); Moves(MOVE_BATON_PASS); } OPPONENT(SPECIES_BELDUM) { Speed(6); Ability(ABILITY_CLEAR_BODY); } } WHEN { TURN{ MOVE(player, MOVE_SCARY_FACE); MOVE(opponent, MOVE_BATON_PASS); SEND_OUT(opponent, 1); } TURN{ MOVE(player, MOVE_TOPSY_TURVY); MOVE(opponent, MOVE_CELEBRATE); } TURN{ MOVE(player, MOVE_SCARY_FACE); MOVE(opponent, MOVE_CELEBRATE); } } SCENE { - MESSAGE("Inkay used Topsy-Turvy!"); + MESSAGE("Wobbuffet used Topsy-Turvy!"); MESSAGE("Foe Beldum used Celebrate!"); MESSAGE("Foe Beldum used Celebrate!"); - MESSAGE("Inkay used Scary Face!"); + MESSAGE("Wobbuffet used Scary Face!"); } } @@ -213,7 +219,7 @@ SINGLE_BATTLE_TEST("Clear Body doesn't prevent Spectral Thief from resetting pos GIVEN { ASSUME(gMovesInfo[MOVE_SPECTRAL_THIEF].additionalEffects->moveEffect == MOVE_EFFECT_SPECTRAL_THIEF); ASSUME(gMovesInfo[MOVE_AGILITY].effect == EFFECT_SPEED_UP_2); - PLAYER(SPECIES_ZIGZAGOON) { Speed(4); Moves(MOVE_SPECTRAL_THIEF, MOVE_CELEBRATE); } + PLAYER(SPECIES_WOBBUFFET) { Speed(4); Moves(MOVE_SPECTRAL_THIEF, MOVE_CELEBRATE); } OPPONENT(SPECIES_BELDUM) { Speed(5); Ability(ABILITY_CLEAR_BODY); Moves(MOVE_AGILITY, MOVE_CELEBRATE); } } WHEN { TURN{ MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_AGILITY); } @@ -221,10 +227,10 @@ SINGLE_BATTLE_TEST("Clear Body doesn't prevent Spectral Thief from resetting pos TURN{ MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } } SCENE { MESSAGE("Foe Beldum used Agility!"); - MESSAGE("Zigzagoon used Celebrate!"); + MESSAGE("Wobbuffet used Celebrate!"); MESSAGE("Foe Beldum used Celebrate!"); - MESSAGE("Zigzagoon used Spectral Thief!"); - MESSAGE("Zigzagoon used Celebrate!"); + MESSAGE("Wobbuffet used SpectrlThief!"); + MESSAGE("Wobbuffet used Celebrate!"); MESSAGE("Foe Beldum used Celebrate!"); } } From 587c3e4a6a876a795e6634b0c50aa3a94a586d4a Mon Sep 17 00:00:00 2001 From: Pawkkie Date: Fri, 31 May 2024 23:20:15 -0400 Subject: [PATCH 03/21] Review + change additionalEffects in tests to use MoveHasAdditionalEffect --- test/battle/ability/clear_body.c | 154 +++++++++++++--------- test/battle/move_effect/smack_down.c | 2 +- test/battle/move_effect/smelling_salts.c | 2 +- test/battle/move_effect/sparkling_aria.c | 2 +- test/battle/move_effect/thousand_arrows.c | 2 +- test/battle/move_effect/wake_up_slap.c | 2 +- 6 files changed, 95 insertions(+), 69 deletions(-) diff --git a/test/battle/ability/clear_body.c b/test/battle/ability/clear_body.c index 6fb1e127bc..2b25bbc23d 100644 --- a/test/battle/ability/clear_body.c +++ b/test/battle/ability/clear_body.c @@ -17,7 +17,9 @@ SINGLE_BATTLE_TEST("Clear Body prevents intimidate") } SCENE { HP_BAR(player, captureDamage: &turnOneHit); ABILITY_POPUP(player, ABILITY_INTIMIDATE); - NONE_OF { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); } + NONE_OF { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + } ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); MESSAGE("Foe Beldum's Clear Body prevents stat loss!"); HP_BAR(player, captureDamage: &turnTwoHit); @@ -41,16 +43,18 @@ SINGLE_BATTLE_TEST("Clear Body prevents stat stage reduction from moves") ASSUME(gMovesInfo[MOVE_GROWL].effect == EFFECT_ATTACK_DOWN); ASSUME(gMovesInfo[MOVE_LEER].effect == EFFECT_DEFENSE_DOWN); ASSUME(gMovesInfo[MOVE_CONFIDE].effect == EFFECT_SPECIAL_ATTACK_DOWN); - ASSUME(gMovesInfo[MOVE_FAKE_TEARS].effect == EFFECT_SPECIAL_DEFENSE_DOWN); + ASSUME(gMovesInfo[MOVE_FAKE_TEARS].effect == EFFECT_SPECIAL_DEFENSE_DOWN_2); ASSUME(gMovesInfo[MOVE_SCARY_FACE].effect == EFFECT_SPEED_DOWN_2); ASSUME(gMovesInfo[MOVE_SWEET_SCENT].effect == EFFECT_EVASION_DOWN); ASSUME(gMovesInfo[MOVE_SAND_ATTACK].effect == EFFECT_ACCURACY_DOWN); - PLAYER(SPECIES_WOBBUFFET) { Moves(move); } + PLAYER(SPECIES_WOBBUFFET) OPPONENT(SPECIES_BELDUM) { Ability(ABILITY_CLEAR_BODY); } } WHEN { - TURN{ MOVE(player, move); } + TURN { MOVE(player, move); } } SCENE { - NONE_OF { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); } + NONE_OF { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + } ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); MESSAGE("Foe Beldum's Clear Body prevents stat loss!"); } @@ -64,10 +68,12 @@ SINGLE_BATTLE_TEST("Clear Body prevents Sticky Web") OPPONENT(SPECIES_WOBBUFFET) OPPONENT(SPECIES_BELDUM) { Ability(ABILITY_CLEAR_BODY); } } WHEN { - TURN{ MOVE(player, MOVE_STICKY_WEB); MOVE(opponent, MOVE_CELEBRATE); } - TURN{ SWITCH(opponent, 1); } + TURN { MOVE(player, MOVE_STICKY_WEB); } + TURN { SWITCH(opponent, 1); } } SCENE { - NONE_OF { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); } + NONE_OF { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + } ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); MESSAGE("Foe Beldum's Clear Body prevents stat loss!"); } @@ -76,41 +82,63 @@ SINGLE_BATTLE_TEST("Clear Body prevents Sticky Web") SINGLE_BATTLE_TEST("Clear Body doesn't prevent stat stage reduction from moves used by the user") { GIVEN { - ASSUME(gMovesInfo[MOVE_SUPERPOWER].additionalEffects->moveEffect == MOVE_EFFECT_ATK_DEF_DOWN); + ASSUME(MoveHasAdditionalEffect(MOVE_SUPERPOWER, MOVE_EFFECT_ATK_DEF_DOWN) == TRUE); PLAYER(SPECIES_WOBBUFFET) - OPPONENT(SPECIES_BELDUM) { Moves(MOVE_SUPERPOWER); Ability(ABILITY_CLEAR_BODY); } + OPPONENT(SPECIES_BELDUM) { Ability(ABILITY_CLEAR_BODY); } } WHEN { - TURN{ MOVE(opponent, MOVE_SUPERPOWER); } + TURN { MOVE(opponent, MOVE_SUPERPOWER); } } SCENE { - NONE_OF { ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); MESSAGE("Foe Beldum's Clear Body prevents stat loss!"); } + NONE_OF { + ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); MESSAGE("Foe Beldum's Clear Body prevents stat loss!"); + } } } -SINGLE_BATTLE_TEST("Clear Body is ignored by Mold Breaker") +SINGLE_BATTLE_TEST("Mold Breaker, Teravolt, and Turboblaze ignore Clear Body") { u16 move; - PARAMETRIZE{ move = MOVE_GROWL; } - PARAMETRIZE{ move = MOVE_LEER; } - PARAMETRIZE{ move = MOVE_CONFIDE; } - PARAMETRIZE{ move = MOVE_FAKE_TEARS; } - PARAMETRIZE{ move = MOVE_SCARY_FACE; } - PARAMETRIZE{ move = MOVE_SWEET_SCENT; } - PARAMETRIZE{ move = MOVE_SAND_ATTACK; } + u16 ability; + PARAMETRIZE{ move = MOVE_GROWL; ability = ABILITY_MOLD_BREAKER; } + PARAMETRIZE{ move = MOVE_LEER; ability = ABILITY_MOLD_BREAKER; } + PARAMETRIZE{ move = MOVE_CONFIDE; ability = ABILITY_MOLD_BREAKER; } + PARAMETRIZE{ move = MOVE_FAKE_TEARS; ability = ABILITY_MOLD_BREAKER; } + PARAMETRIZE{ move = MOVE_SCARY_FACE; ability = ABILITY_MOLD_BREAKER; } + PARAMETRIZE{ move = MOVE_SWEET_SCENT; ability = ABILITY_MOLD_BREAKER; } + PARAMETRIZE{ move = MOVE_SAND_ATTACK; ability = ABILITY_MOLD_BREAKER; } + PARAMETRIZE{ move = MOVE_GROWL; ability = ABILITY_MOLD_BREAKER; } + + PARAMETRIZE{ move = MOVE_LEER; ability = ABILITY_TERAVOLT; } + PARAMETRIZE{ move = MOVE_CONFIDE; ability = ABILITY_TERAVOLT; } + PARAMETRIZE{ move = MOVE_FAKE_TEARS; ability = ABILITY_TERAVOLT; } + PARAMETRIZE{ move = MOVE_SCARY_FACE; ability = ABILITY_TERAVOLT; } + PARAMETRIZE{ move = MOVE_SWEET_SCENT; ability = ABILITY_TERAVOLT; } + PARAMETRIZE{ move = MOVE_SAND_ATTACK; ability = ABILITY_TERAVOLT; } + PARAMETRIZE{ move = MOVE_GROWL; ability = ABILITY_TERAVOLT; } + + PARAMETRIZE{ move = MOVE_LEER; ability = ABILITY_TURBOBLAZE; } + PARAMETRIZE{ move = MOVE_CONFIDE; ability = ABILITY_TURBOBLAZE; } + PARAMETRIZE{ move = MOVE_FAKE_TEARS; ability = ABILITY_TURBOBLAZE; } + PARAMETRIZE{ move = MOVE_SCARY_FACE; ability = ABILITY_TURBOBLAZE; } + PARAMETRIZE{ move = MOVE_SWEET_SCENT; ability = ABILITY_TURBOBLAZE; } + PARAMETRIZE{ move = MOVE_SAND_ATTACK; ability = ABILITY_TURBOBLAZE; } + PARAMETRIZE{ move = MOVE_GROWL; ability = ABILITY_TURBOBLAZE; } GIVEN { ASSUME(gMovesInfo[MOVE_GROWL].effect == EFFECT_ATTACK_DOWN); ASSUME(gMovesInfo[MOVE_LEER].effect == EFFECT_DEFENSE_DOWN); ASSUME(gMovesInfo[MOVE_CONFIDE].effect == EFFECT_SPECIAL_ATTACK_DOWN); - ASSUME(gMovesInfo[MOVE_FAKE_TEARS].effect == EFFECT_SPECIAL_DEFENSE_DOWN); + ASSUME(gMovesInfo[MOVE_FAKE_TEARS].effect == EFFECT_SPECIAL_DEFENSE_DOWN_2); ASSUME(gMovesInfo[MOVE_SCARY_FACE].effect == EFFECT_SPEED_DOWN_2); ASSUME(gMovesInfo[MOVE_SWEET_SCENT].effect == EFFECT_EVASION_DOWN); ASSUME(gMovesInfo[MOVE_SAND_ATTACK].effect == EFFECT_ACCURACY_DOWN); - PLAYER(SPECIES_PINSIR) { Ability(ABILITY_MOLD_BREAKER); Moves(move); } + PLAYER(SPECIES_WOBBUFFET) { Ability(ability); } OPPONENT(SPECIES_BELDUM) { Ability(ABILITY_CLEAR_BODY); } } WHEN { - TURN{ MOVE(player, move); } + TURN { MOVE(player, move); } } SCENE { - NONE_OF { ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); MESSAGE("Foe Beldum's Clear Body prevents stat loss!"); } + NONE_OF { + ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); MESSAGE("Foe Beldum's Clear Body prevents stat loss!"); + } } } @@ -124,15 +152,13 @@ SINGLE_BATTLE_TEST("Clear Body doesn't prevent Speed reduction from Iron Ball") PLAYER(SPECIES_WOBBUFFET) { Speed(4); } OPPONENT(SPECIES_BELDUM) { Speed(6); Ability(ABILITY_CLEAR_BODY); Item(heldItem); } } WHEN { - TURN{ MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { } } SCENE { - if (heldItem == ITEM_IRON_BALL) - { + if (heldItem == ITEM_IRON_BALL) { MESSAGE("Wobbuffet used Celebrate!"); MESSAGE("Foe Beldum used Celebrate!"); } - else - { + else { MESSAGE("Foe Beldum used Celebrate!"); MESSAGE("Wobbuffet used Celebrate!"); } @@ -142,19 +168,19 @@ SINGLE_BATTLE_TEST("Clear Body doesn't prevent Speed reduction from Iron Ball") SINGLE_BATTLE_TEST("Clear Body doesn't prevent Speed reduction from paralysis") { GIVEN { - PLAYER(SPECIES_WOBBUFFET) { Speed(4); Moves(MOVE_THUNDER_WAVE); } + PLAYER(SPECIES_WOBBUFFET) { Speed(4); } OPPONENT(SPECIES_BELDUM) { Speed(6); Ability(ABILITY_CLEAR_BODY); } } WHEN { - TURN{ MOVE(player, MOVE_THUNDER_WAVE); MOVE(opponent, MOVE_CELEBRATE); } - TURN{ MOVE(player, MOVE_THUNDER_WAVE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_THUNDER_WAVE); } + TURN { MOVE(player, MOVE_THUNDER_WAVE); } } SCENE { + MESSAGE("Foe Beldum used Celebrate!"); + MESSAGE("Wobbuffet used Thunder Wave!"); + MESSAGE("Wobbuffet used Thunder Wave!"); + ONE_OF { MESSAGE("Foe Beldum used Celebrate!"); - MESSAGE("Wobbuffet used Thunder Wave!"); - MESSAGE("Wobbuffet used Thunder Wave!"); - ONE_OF { - MESSAGE("Foe Beldum used Celebrate!"); - MESSAGE("Foe Beldum is paralyzed! It can't move!"); - } + MESSAGE("Foe Beldum is paralyzed! It can't move!"); + } } } @@ -168,7 +194,7 @@ SINGLE_BATTLE_TEST("Clear Body doesn't prevent Attack reduction from burn", s16 PLAYER(SPECIES_WOBBUFFET) OPPONENT(SPECIES_BELDUM) { Ability(ABILITY_CLEAR_BODY); if (burned) Status1(STATUS1_BURN); } } WHEN { - TURN{ MOVE(opponent, MOVE_TACKLE); } + TURN { MOVE(opponent, MOVE_TACKLE); } } SCENE { HP_BAR(player, captureDamage: &results[i].damage); } FINALLY { @@ -181,15 +207,15 @@ SINGLE_BATTLE_TEST("Clear Body doesn't prevent receiving negative stat changes f GIVEN { ASSUME(gMovesInfo[MOVE_SCARY_FACE].effect == EFFECT_SPEED_DOWN_2); ASSUME(gMovesInfo[MOVE_BATON_PASS].effect == EFFECT_BATON_PASS); - PLAYER(SPECIES_WOBBUFFET) { Speed(4); Moves(MOVE_SCARY_FACE); } - OPPONENT(SPECIES_WOBBUFFET) { Speed(3); Moves(MOVE_BATON_PASS); } + PLAYER(SPECIES_WOBBUFFET) { Speed(4); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(3); } OPPONENT(SPECIES_BELDUM) { Speed(6); Ability(ABILITY_CLEAR_BODY); } } WHEN { - TURN{ MOVE(player, MOVE_SCARY_FACE); MOVE(opponent, MOVE_BATON_PASS); SEND_OUT(opponent, 1); } - TURN{ MOVE(player, MOVE_SCARY_FACE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_SCARY_FACE); MOVE(opponent, MOVE_BATON_PASS); SEND_OUT(opponent, 1); } + TURN { MOVE(player, MOVE_SCARY_FACE); } } SCENE { - MESSAGE("Wobbuffet used Scary Face!"); - MESSAGE("Foe Beldum used Celebrate!"); + MESSAGE("Wobbuffet used Scary Face!"); + MESSAGE("Foe Beldum used Celebrate!"); } } @@ -199,38 +225,38 @@ SINGLE_BATTLE_TEST("Clear Body doesn't prevent Topsy-Turvy") ASSUME(gMovesInfo[MOVE_TOPSY_TURVY].effect == EFFECT_TOPSY_TURVY); ASSUME(gMovesInfo[MOVE_SCARY_FACE].effect == EFFECT_SPEED_DOWN_2); ASSUME(gMovesInfo[MOVE_BATON_PASS].effect == EFFECT_BATON_PASS); - PLAYER(SPECIES_WOBBUFFET) { Speed(4); Moves(MOVE_SCARY_FACE, MOVE_TOPSY_TURVY); } - OPPONENT(SPECIES_WOBBUFFET) { Speed(3); Moves(MOVE_BATON_PASS); } + PLAYER(SPECIES_WOBBUFFET) { Speed(4); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(3); } OPPONENT(SPECIES_BELDUM) { Speed(6); Ability(ABILITY_CLEAR_BODY); } } WHEN { - TURN{ MOVE(player, MOVE_SCARY_FACE); MOVE(opponent, MOVE_BATON_PASS); SEND_OUT(opponent, 1); } - TURN{ MOVE(player, MOVE_TOPSY_TURVY); MOVE(opponent, MOVE_CELEBRATE); } - TURN{ MOVE(player, MOVE_SCARY_FACE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_SCARY_FACE); MOVE(opponent, MOVE_BATON_PASS); SEND_OUT(opponent, 1); } + TURN { MOVE(player, MOVE_TOPSY_TURVY); } + TURN { MOVE(player, MOVE_SCARY_FACE); } } SCENE { - MESSAGE("Wobbuffet used Topsy-Turvy!"); - MESSAGE("Foe Beldum used Celebrate!"); - MESSAGE("Foe Beldum used Celebrate!"); - MESSAGE("Wobbuffet used Scary Face!"); + MESSAGE("Wobbuffet used Topsy-Turvy!"); + MESSAGE("Foe Beldum used Celebrate!"); + MESSAGE("Foe Beldum used Celebrate!"); + MESSAGE("Wobbuffet used Scary Face!"); } } SINGLE_BATTLE_TEST("Clear Body doesn't prevent Spectral Thief from resetting positive stat changes") { GIVEN { - ASSUME(gMovesInfo[MOVE_SPECTRAL_THIEF].additionalEffects->moveEffect == MOVE_EFFECT_SPECTRAL_THIEF); + ASSUME(MoveHasAdditionalEffect(MOVE_SPECTRAL_THIEF, MOVE_EFFECT_SPECTRAL_THIEF) == TRUE); ASSUME(gMovesInfo[MOVE_AGILITY].effect == EFFECT_SPEED_UP_2); PLAYER(SPECIES_WOBBUFFET) { Speed(4); Moves(MOVE_SPECTRAL_THIEF, MOVE_CELEBRATE); } OPPONENT(SPECIES_BELDUM) { Speed(5); Ability(ABILITY_CLEAR_BODY); Moves(MOVE_AGILITY, MOVE_CELEBRATE); } } WHEN { - TURN{ MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_AGILITY); } - TURN{ MOVE(player, MOVE_SPECTRAL_THIEF); MOVE(opponent, MOVE_CELEBRATE); } - TURN{ MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN{ MOVE(opponent, MOVE_AGILITY); } + TURN{ MOVE(player, MOVE_SPECTRAL_THIEF); } + TURN{ } } SCENE { - MESSAGE("Foe Beldum used Agility!"); - MESSAGE("Wobbuffet used Celebrate!"); - MESSAGE("Foe Beldum used Celebrate!"); - MESSAGE("Wobbuffet used SpectrlThief!"); - MESSAGE("Wobbuffet used Celebrate!"); - MESSAGE("Foe Beldum used Celebrate!"); + MESSAGE("Foe Beldum used Agility!"); + MESSAGE("Wobbuffet used Celebrate!"); + MESSAGE("Foe Beldum used Celebrate!"); + MESSAGE("Wobbuffet used SpectrlThief!"); + MESSAGE("Wobbuffet used Celebrate!"); + MESSAGE("Foe Beldum used Celebrate!"); } } diff --git a/test/battle/move_effect/smack_down.c b/test/battle/move_effect/smack_down.c index 54bf6885af..d68cb75ec3 100644 --- a/test/battle/move_effect/smack_down.c +++ b/test/battle/move_effect/smack_down.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_SMACK_DOWN].additionalEffects->moveEffect == MOVE_EFFECT_SMACK_DOWN); + ASSUME(MoveHasAdditionalEffect(MOVE_SMACK_DOWN, MOVE_EFFECT_SMACK_DOWN) == TRUE); } SINGLE_BATTLE_TEST("Smack Down does not ground mons behind substitutes") diff --git a/test/battle/move_effect/smelling_salts.c b/test/battle/move_effect/smelling_salts.c index 09168f8a1e..311024a153 100644 --- a/test/battle/move_effect/smelling_salts.c +++ b/test/battle/move_effect/smelling_salts.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_SMELLING_SALTS].additionalEffects->moveEffect == MOVE_EFFECT_REMOVE_STATUS); + ASSUME(MoveHasAdditionalEffect(MOVE_SMELLING_SALTS, MOVE_EFFECT_REMOVE_STATUS) == TRUE); ASSUME(gMovesInfo[MOVE_SMELLING_SALTS].argument == STATUS1_PARALYSIS); } diff --git a/test/battle/move_effect/sparkling_aria.c b/test/battle/move_effect/sparkling_aria.c index 1bf7de2df4..0cbfdbc3e9 100644 --- a/test/battle/move_effect/sparkling_aria.c +++ b/test/battle/move_effect/sparkling_aria.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_SPARKLING_ARIA].additionalEffects->moveEffect == MOVE_EFFECT_REMOVE_STATUS); + ASSUME(MoveHasAdditionalEffect(MOVE_SPARKLING_ARIA, MOVE_EFFECT_REMOVE_STATUS) == TRUE); ASSUME(gMovesInfo[MOVE_SPARKLING_ARIA].argument == STATUS1_BURN); ASSUME(gMovesInfo[MOVE_SPARKLING_ARIA].soundMove == TRUE); } diff --git a/test/battle/move_effect/thousand_arrows.c b/test/battle/move_effect/thousand_arrows.c index bff3706c34..ff1b041cba 100644 --- a/test/battle/move_effect/thousand_arrows.c +++ b/test/battle/move_effect/thousand_arrows.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_THOUSAND_ARROWS].additionalEffects->moveEffect == MOVE_EFFECT_SMACK_DOWN); + ASSUME(MoveHasAdditionalEffect(MOVE_THOUSAND_ARROWS, MOVE_EFFECT_SMACK_DOWN) == TRUE); ASSUME(gMovesInfo[MOVE_THOUSAND_ARROWS].ignoreTypeIfFlyingAndUngrounded == TRUE); } diff --git a/test/battle/move_effect/wake_up_slap.c b/test/battle/move_effect/wake_up_slap.c index 98bcf95b20..2c9dd7ed24 100644 --- a/test/battle/move_effect/wake_up_slap.c +++ b/test/battle/move_effect/wake_up_slap.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_WAKE_UP_SLAP].additionalEffects->moveEffect == MOVE_EFFECT_REMOVE_STATUS); + ASSUME(MoveHasAdditionalEffect(MOVE_WAKE_UP_SLAP, MOVE_EFFECT_REMOVE_STATUS) == TRUE); ASSUME(gMovesInfo[MOVE_WAKE_UP_SLAP].argument == STATUS1_SLEEP); } From 2e0c653807b2b7cf433f851bb346b2a99f1dee3b Mon Sep 17 00:00:00 2001 From: Pawkkie Date: Sat, 1 Jun 2024 11:39:41 -0400 Subject: [PATCH 04/21] Fix Sweet Scent assume --- test/battle/ability/clear_body.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/battle/ability/clear_body.c b/test/battle/ability/clear_body.c index 2b25bbc23d..511cd2ab6f 100644 --- a/test/battle/ability/clear_body.c +++ b/test/battle/ability/clear_body.c @@ -45,7 +45,7 @@ SINGLE_BATTLE_TEST("Clear Body prevents stat stage reduction from moves") ASSUME(gMovesInfo[MOVE_CONFIDE].effect == EFFECT_SPECIAL_ATTACK_DOWN); ASSUME(gMovesInfo[MOVE_FAKE_TEARS].effect == EFFECT_SPECIAL_DEFENSE_DOWN_2); ASSUME(gMovesInfo[MOVE_SCARY_FACE].effect == EFFECT_SPEED_DOWN_2); - ASSUME(gMovesInfo[MOVE_SWEET_SCENT].effect == EFFECT_EVASION_DOWN); + ASSUME(gMovesInfo[MOVE_SWEET_SCENT].effect == (B_UPDATED_MOVE_DATA >= GEN_6 ? EFFECT_EVASION_DOWN_2 : EFFECT_EVASION_DOWN)); ASSUME(gMovesInfo[MOVE_SAND_ATTACK].effect == EFFECT_ACCURACY_DOWN); PLAYER(SPECIES_WOBBUFFET) OPPONENT(SPECIES_BELDUM) { Ability(ABILITY_CLEAR_BODY); } @@ -129,7 +129,7 @@ SINGLE_BATTLE_TEST("Mold Breaker, Teravolt, and Turboblaze ignore Clear Body") ASSUME(gMovesInfo[MOVE_CONFIDE].effect == EFFECT_SPECIAL_ATTACK_DOWN); ASSUME(gMovesInfo[MOVE_FAKE_TEARS].effect == EFFECT_SPECIAL_DEFENSE_DOWN_2); ASSUME(gMovesInfo[MOVE_SCARY_FACE].effect == EFFECT_SPEED_DOWN_2); - ASSUME(gMovesInfo[MOVE_SWEET_SCENT].effect == EFFECT_EVASION_DOWN); + ASSUME(gMovesInfo[MOVE_SWEET_SCENT].effect == (B_UPDATED_MOVE_DATA >= GEN_6 ? EFFECT_EVASION_DOWN_2 : EFFECT_EVASION_DOWN)); ASSUME(gMovesInfo[MOVE_SAND_ATTACK].effect == EFFECT_ACCURACY_DOWN); PLAYER(SPECIES_WOBBUFFET) { Ability(ability); } OPPONENT(SPECIES_BELDUM) { Ability(ABILITY_CLEAR_BODY); } From 5fd3532e16eea06777ac62faf0772809aecdb434 Mon Sep 17 00:00:00 2001 From: Pawkkie Date: Sat, 1 Jun 2024 12:39:10 -0400 Subject: [PATCH 05/21] Fix assumptions --- test/battle/ability/clear_body.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/battle/ability/clear_body.c b/test/battle/ability/clear_body.c index 511cd2ab6f..e3cf2a5161 100644 --- a/test/battle/ability/clear_body.c +++ b/test/battle/ability/clear_body.c @@ -45,7 +45,8 @@ SINGLE_BATTLE_TEST("Clear Body prevents stat stage reduction from moves") ASSUME(gMovesInfo[MOVE_CONFIDE].effect == EFFECT_SPECIAL_ATTACK_DOWN); ASSUME(gMovesInfo[MOVE_FAKE_TEARS].effect == EFFECT_SPECIAL_DEFENSE_DOWN_2); ASSUME(gMovesInfo[MOVE_SCARY_FACE].effect == EFFECT_SPEED_DOWN_2); - ASSUME(gMovesInfo[MOVE_SWEET_SCENT].effect == (B_UPDATED_MOVE_DATA >= GEN_6 ? EFFECT_EVASION_DOWN_2 : EFFECT_EVASION_DOWN)); + ASSUME(B_UPDATED_MOVE_DATA >= GEN_6); + ASSUME(gMovesInfo[MOVE_SWEET_SCENT].effect == EFFECT_EVASION_DOWN_2); ASSUME(gMovesInfo[MOVE_SAND_ATTACK].effect == EFFECT_ACCURACY_DOWN); PLAYER(SPECIES_WOBBUFFET) OPPONENT(SPECIES_BELDUM) { Ability(ABILITY_CLEAR_BODY); } @@ -82,7 +83,7 @@ SINGLE_BATTLE_TEST("Clear Body prevents Sticky Web") SINGLE_BATTLE_TEST("Clear Body doesn't prevent stat stage reduction from moves used by the user") { GIVEN { - ASSUME(MoveHasAdditionalEffect(MOVE_SUPERPOWER, MOVE_EFFECT_ATK_DEF_DOWN) == TRUE); + ASSUME(MoveHasAdditionalEffectSelf(MOVE_SUPERPOWER, MOVE_EFFECT_ATK_DEF_DOWN) == TRUE); PLAYER(SPECIES_WOBBUFFET) OPPONENT(SPECIES_BELDUM) { Ability(ABILITY_CLEAR_BODY); } } WHEN { @@ -129,7 +130,8 @@ SINGLE_BATTLE_TEST("Mold Breaker, Teravolt, and Turboblaze ignore Clear Body") ASSUME(gMovesInfo[MOVE_CONFIDE].effect == EFFECT_SPECIAL_ATTACK_DOWN); ASSUME(gMovesInfo[MOVE_FAKE_TEARS].effect == EFFECT_SPECIAL_DEFENSE_DOWN_2); ASSUME(gMovesInfo[MOVE_SCARY_FACE].effect == EFFECT_SPEED_DOWN_2); - ASSUME(gMovesInfo[MOVE_SWEET_SCENT].effect == (B_UPDATED_MOVE_DATA >= GEN_6 ? EFFECT_EVASION_DOWN_2 : EFFECT_EVASION_DOWN)); + ASSUME(B_UPDATED_MOVE_DATA >= GEN_6); + ASSUME(gMovesInfo[MOVE_SWEET_SCENT].effect == EFFECT_EVASION_DOWN_2); ASSUME(gMovesInfo[MOVE_SAND_ATTACK].effect == EFFECT_ACCURACY_DOWN); PLAYER(SPECIES_WOBBUFFET) { Ability(ability); } OPPONENT(SPECIES_BELDUM) { Ability(ABILITY_CLEAR_BODY); } From 22ee823bc10e8f6c6f32e95a7b62a04202f39146 Mon Sep 17 00:00:00 2001 From: Pawkkie Date: Sun, 2 Jun 2024 12:43:21 -0400 Subject: [PATCH 06/21] Review feedback --- test/battle/ability/clear_body.c | 52 +++++++++++++++----------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/test/battle/ability/clear_body.c b/test/battle/ability/clear_body.c index e3cf2a5161..9dc6ab8147 100644 --- a/test/battle/ability/clear_body.c +++ b/test/battle/ability/clear_body.c @@ -97,32 +97,31 @@ SINGLE_BATTLE_TEST("Clear Body doesn't prevent stat stage reduction from moves u SINGLE_BATTLE_TEST("Mold Breaker, Teravolt, and Turboblaze ignore Clear Body") { - u16 move; - u16 ability; - PARAMETRIZE{ move = MOVE_GROWL; ability = ABILITY_MOLD_BREAKER; } - PARAMETRIZE{ move = MOVE_LEER; ability = ABILITY_MOLD_BREAKER; } - PARAMETRIZE{ move = MOVE_CONFIDE; ability = ABILITY_MOLD_BREAKER; } - PARAMETRIZE{ move = MOVE_FAKE_TEARS; ability = ABILITY_MOLD_BREAKER; } - PARAMETRIZE{ move = MOVE_SCARY_FACE; ability = ABILITY_MOLD_BREAKER; } - PARAMETRIZE{ move = MOVE_SWEET_SCENT; ability = ABILITY_MOLD_BREAKER; } - PARAMETRIZE{ move = MOVE_SAND_ATTACK; ability = ABILITY_MOLD_BREAKER; } - PARAMETRIZE{ move = MOVE_GROWL; ability = ABILITY_MOLD_BREAKER; } + u32 j, k; + u16 ability = ABILITY_NONE; + u16 move = ABILITY_NONE; + static const u16 breakerAbilities[] = { + ABILITY_MOLD_BREAKER, + ABILITY_TERAVOLT, + ABILITY_TURBOBLAZE, + }; + static const u16 statReductionMoves[] = { + MOVE_GROWL, + MOVE_LEER, + MOVE_CONFIDE, + MOVE_FAKE_TEARS, + MOVE_SCARY_FACE, + MOVE_SWEET_SCENT, + MOVE_SAND_ATTACK, + }; - PARAMETRIZE{ move = MOVE_LEER; ability = ABILITY_TERAVOLT; } - PARAMETRIZE{ move = MOVE_CONFIDE; ability = ABILITY_TERAVOLT; } - PARAMETRIZE{ move = MOVE_FAKE_TEARS; ability = ABILITY_TERAVOLT; } - PARAMETRIZE{ move = MOVE_SCARY_FACE; ability = ABILITY_TERAVOLT; } - PARAMETRIZE{ move = MOVE_SWEET_SCENT; ability = ABILITY_TERAVOLT; } - PARAMETRIZE{ move = MOVE_SAND_ATTACK; ability = ABILITY_TERAVOLT; } - PARAMETRIZE{ move = MOVE_GROWL; ability = ABILITY_TERAVOLT; } - - PARAMETRIZE{ move = MOVE_LEER; ability = ABILITY_TURBOBLAZE; } - PARAMETRIZE{ move = MOVE_CONFIDE; ability = ABILITY_TURBOBLAZE; } - PARAMETRIZE{ move = MOVE_FAKE_TEARS; ability = ABILITY_TURBOBLAZE; } - PARAMETRIZE{ move = MOVE_SCARY_FACE; ability = ABILITY_TURBOBLAZE; } - PARAMETRIZE{ move = MOVE_SWEET_SCENT; ability = ABILITY_TURBOBLAZE; } - PARAMETRIZE{ move = MOVE_SAND_ATTACK; ability = ABILITY_TURBOBLAZE; } - PARAMETRIZE{ move = MOVE_GROWL; ability = ABILITY_TURBOBLAZE; } + for (j = 0; j < ARRAY_COUNT(statReductionMoves); j++) + { + for (k = 0; k < ARRAY_COUNT(breakerAbilities); k++) + { + PARAMETRIZE{ move = statReductionMoves[j]; ability = breakerAbilities[k]; } + } + } GIVEN { ASSUME(gMovesInfo[MOVE_GROWL].effect == EFFECT_ATTACK_DOWN); @@ -159,8 +158,7 @@ SINGLE_BATTLE_TEST("Clear Body doesn't prevent Speed reduction from Iron Ball") if (heldItem == ITEM_IRON_BALL) { MESSAGE("Wobbuffet used Celebrate!"); MESSAGE("Foe Beldum used Celebrate!"); - } - else { + } else { MESSAGE("Foe Beldum used Celebrate!"); MESSAGE("Wobbuffet used Celebrate!"); } From 0fda9d6cd6c260bff15d55cf22e7da0c97a197c6 Mon Sep 17 00:00:00 2001 From: Bassoonian Date: Fri, 7 Jun 2024 21:04:03 +0200 Subject: [PATCH 07/21] Fix Hyper Potion price (#4737) --- src/data/items.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/items.h b/src/data/items.h index f35f10a16d..27103202a2 100644 --- a/src/data/items.h +++ b/src/data/items.h @@ -578,7 +578,7 @@ const struct Item gItemsInfo[] = [ITEM_HYPER_POTION] = { .name = _("Hyper Potion"), - .price = (I_PRICE >= GEN_2 || I_PRICE <= GEN_6) ? 1200 : 1500, + .price = (I_PRICE >= GEN_2 && I_PRICE <= GEN_6) ? 1200 : 1500, .holdEffectParam = 120, .description = COMPOUND_STRING( "Restores the HP of\n" From d6422da284115b90c20ec593082757c908d74a12 Mon Sep 17 00:00:00 2001 From: Bassoonian Date: Fri, 7 Jun 2024 21:05:16 +0200 Subject: [PATCH 08/21] Fix partner palette problem (#4736) --- asm/macros/battle_frontier/battle_tower.inc | 30 +++++++++---------- .../MossdeepCity_SpaceCenter_2F/scripts.inc | 2 +- include/battle.h | 1 - src/battle_controller_player_partner.c | 2 +- src/battle_main.c | 1 - src/battle_tower.c | 1 - 6 files changed, 16 insertions(+), 21 deletions(-) diff --git a/asm/macros/battle_frontier/battle_tower.inc b/asm/macros/battle_frontier/battle_tower.inc index 49e72e7446..b3c86955dd 100644 --- a/asm/macros/battle_frontier/battle_tower.inc +++ b/asm/macros/battle_frontier/battle_tower.inc @@ -98,7 +98,7 @@ waitstate .endm - .macro multi_do type:req, partnerId:req, partnerPicId:req + .macro multi_do type:req, partnerId:req special ReducePlayerPartyToSelectedMons setvar VAR_0x8004, FRONTIER_UTIL_FUNC_SET_DATA setvar VAR_0x8005, FRONTIER_DATA_SELECTED_MON_ORDER @@ -106,7 +106,6 @@ setvar VAR_0x8004, SPECIAL_BATTLE_MULTI setvar VAR_0x8005, \type | MULTI_BATTLE_CHOOSE_MONS setvar VAR_0x8006, \partnerId - setvar VAR_0x8007, \partnerPicId special DoSpecialTrainerBattle waitstate setvar VAR_0x8004, FRONTIER_UTIL_FUNC_SAVE_PARTY @@ -114,30 +113,29 @@ special LoadPlayerParty .endm - .macro multi_2_vs_2 trainer1Id:req, trainer1LoseText:req, trainer2Id:req, trainer2LoseText:req, partnerId:req, partnerPicId:req + .macro multi_2_vs_2 trainer1Id:req, trainer1LoseText:req, trainer2Id:req, trainer2LoseText:req, partnerId:req special SavePlayerParty trainerbattle TRAINER_BATTLE_SET_TRAINER_A, \trainer1Id, 0, NULL, \trainer1LoseText @ set first trainer mons trainerbattle TRAINER_BATTLE_SET_TRAINER_B, \trainer2Id, 0, NULL, \trainer2LoseText @ set second trainer mons - multi_do MULTI_BATTLE_2_VS_2, \partnerId, \partnerPicId + multi_do MULTI_BATTLE_2_VS_2, \partnerId .endm - .macro multi_2_vs_1 trainer1Id:req, trainer1LoseText:req, partnerId:req, partnerPicId:req + .macro multi_2_vs_1 trainer1Id:req, trainer1LoseText:req, partnerId:req special SavePlayerParty trainerbattle TRAINER_BATTLE_SET_TRAINER_A, \trainer1Id, 0, NULL, \trainer1LoseText @ set first trainer mons - multi_do MULTI_BATTLE_2_VS_1, \partnerId, \partnerPicId + multi_do MULTI_BATTLE_2_VS_1, \partnerId .endm @ Wild mons need to be assigned to gEnemyParty 0 and 3 slots, other slots need to be cleared out. - .macro multi_wild partnerId:req, partnerPicId:req + .macro multi_wild partnerId:req special SavePlayerParty - multi_do MULTI_BATTLE_2_VS_WILD, \partnerId, \partnerPicId + multi_do MULTI_BATTLE_2_VS_WILD, \partnerId .endm - .macro multi_do_fixed type:req, partnerId:req, partnerPicId:req + .macro multi_do_fixed type:req, partnerId:req setvar VAR_0x8004, SPECIAL_BATTLE_MULTI setvar VAR_0x8005, \type setvar VAR_0x8006, \partnerId - setvar VAR_0x8007, \partnerPicId special DoSpecialTrainerBattle waitstate setvar VAR_0x8004, FRONTIER_UTIL_FUNC_SAVE_PARTY @@ -145,21 +143,21 @@ special LoadPlayerParty .endm - .macro multi_fixed_2_vs_2 trainer1Id:req, trainer1LoseText:req, trainer2Id:req, trainer2LoseText:req, partnerId:req, partnerPicId:req + .macro multi_fixed_2_vs_2 trainer1Id:req, trainer1LoseText:req, trainer2Id:req, trainer2LoseText:req, partnerId:req special SavePlayerParty trainerbattle TRAINER_BATTLE_SET_TRAINER_A, \trainer1Id, 0, NULL, \trainer1LoseText @ set first trainer mons trainerbattle TRAINER_BATTLE_SET_TRAINER_B, \trainer2Id, 0, NULL, \trainer2LoseText @ set second trainer mons - multi_do_fixed MULTI_BATTLE_2_VS_2, \partnerId, \partnerPicId + multi_do_fixed MULTI_BATTLE_2_VS_2, \partnerId .endm - .macro multi_fixed_2_vs_1 trainer1Id:req, trainer1LoseText:req, partnerId:req, partnerPicId:req + .macro multi_fixed_2_vs_1 trainer1Id:req, trainer1LoseText:req, partnerId:req special SavePlayerParty trainerbattle TRAINER_BATTLE_SET_TRAINER_A, \trainer1Id, 0, NULL, \trainer1LoseText @ set first trainer mons - multi_do_fixed MULTI_BATTLE_2_VS_1, \partnerId, \partnerPicId + multi_do_fixed MULTI_BATTLE_2_VS_1, \partnerId .endm @ Wild mons need to be assigned to gEnemyParty 0 and 3 slots, other slots need to be cleared out. - .macro multi_fixed_wild partnerId:req, partnerPicId:req + .macro multi_fixed_wild partnerId:req special SavePlayerParty - multi_do_fixed MULTI_BATTLE_2_VS_WILD, \partnerId, \partnerPicId + multi_do_fixed MULTI_BATTLE_2_VS_WILD, \partnerId .endm diff --git a/data/maps/MossdeepCity_SpaceCenter_2F/scripts.inc b/data/maps/MossdeepCity_SpaceCenter_2F/scripts.inc index a4fcc0237c..4ec82003b5 100644 --- a/data/maps/MossdeepCity_SpaceCenter_2F/scripts.inc +++ b/data/maps/MossdeepCity_SpaceCenter_2F/scripts.inc @@ -257,7 +257,7 @@ MossdeepCity_SpaceCenter_2F_EventScript_ChoosePartyForMultiBattle:: goto MossdeepCity_SpaceCenter_2F_EventScript_ReadyForBattlePrompt MossdeepCity_SpaceCenter_2F_EventScript_DoStevenMultiBattle:: - multi_2_vs_2 TRAINER_MAXIE_MOSSDEEP, MossdeepCity_SpaceCenter_2F_Text_JustWantToExpandLand, TRAINER_TABITHA_MOSSDEEP, MossdeepCity_SpaceCenter_Text_TabithaDefeat, PARTNER_STEVEN, TRAINER_BACK_PIC_STEVEN + multi_2_vs_2 TRAINER_MAXIE_MOSSDEEP, MossdeepCity_SpaceCenter_2F_Text_JustWantToExpandLand, TRAINER_TABITHA_MOSSDEEP, MossdeepCity_SpaceCenter_Text_TabithaDefeat, PARTNER_STEVEN switch VAR_RESULT case 1, MossdeepCity_SpaceCenter_2F_EventScript_DefeatedMaxieTabitha fadescreen FADE_TO_BLACK diff --git a/include/battle.h b/include/battle.h index dc771a5d77..51d1a03bc3 100644 --- a/include/battle.h +++ b/include/battle.h @@ -1090,7 +1090,6 @@ extern u16 gMoveToLearn; extern u32 gFieldStatuses; extern struct FieldTimer gFieldTimers; extern u8 gBattlerAbility; -extern u16 gPartnerSpriteId; extern struct QueuedStatBoost gQueuedStatBoosts[MAX_BATTLERS_COUNT]; extern const struct BattleMoveEffect gBattleMoveEffects[]; diff --git a/src/battle_controller_player_partner.c b/src/battle_controller_player_partner.c index 5c3fd41762..b817adf097 100644 --- a/src/battle_controller_player_partner.c +++ b/src/battle_controller_player_partner.c @@ -435,7 +435,7 @@ static void PlayerPartnerHandleIntroTrainerBallThrow(u32 battler) const u32 *trainerPal; if (gPartnerTrainerId > TRAINER_PARTNER(PARTNER_NONE)) - trainerPal = gTrainerBacksprites[gPartnerSpriteId].palette.data; + trainerPal = gTrainerBacksprites[gBattlePartners[gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerPic].palette.data; else if (IsAiVsAiBattle()) trainerPal = gTrainerSprites[GetTrainerPicFromId(gPartnerTrainerId)].palette.data; else diff --git a/src/battle_main.c b/src/battle_main.c index 0ab3a67fa8..4d64ed46b2 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -220,7 +220,6 @@ EWRAM_DATA u16 gMoveToLearn = 0; EWRAM_DATA u32 gFieldStatuses = 0; EWRAM_DATA struct FieldTimer gFieldTimers = {0}; EWRAM_DATA u8 gBattlerAbility = 0; -EWRAM_DATA u16 gPartnerSpriteId = 0; EWRAM_DATA struct QueuedStatBoost gQueuedStatBoosts[MAX_BATTLERS_COUNT] = {0}; EWRAM_DATA bool8 gHasFetchedBall = FALSE; EWRAM_DATA u8 gLastUsedBall = 0; diff --git a/src/battle_tower.c b/src/battle_tower.c index cd94e7919b..266d7258b3 100644 --- a/src/battle_tower.c +++ b/src/battle_tower.c @@ -2148,7 +2148,6 @@ void DoSpecialTrainerBattle(void) gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_DOUBLE | BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_MULTI | BATTLE_TYPE_INGAME_PARTNER; } - gPartnerSpriteId = VarGet(gSpecialVar_0x8007); gPartnerTrainerId = VarGet(gSpecialVar_0x8006) + TRAINER_PARTNER(PARTNER_NONE); FillPartnerParty(gPartnerTrainerId); CreateTask(Task_StartBattleAfterTransition, 1); From dc742b30778f016ee0e48ded976a6d795e810857 Mon Sep 17 00:00:00 2001 From: sneed <56992013+Sneed69@users.noreply.github.com> Date: Fri, 7 Jun 2024 22:54:25 +0300 Subject: [PATCH 09/21] Fix Berserk, Angel Shell, Wimp Out, Emergency Exit HP threshold (#4724) * Fix HadMoreThanHalfHpNowHasLess * rename the functions * formatting --- src/battle_util.c | 14 +++--- test/battle/ability/anger_shell.c | 18 ++++---- test/battle/ability/berserk.c | 75 +++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 17 deletions(-) create mode 100644 test/battle/ability/berserk.c diff --git a/src/battle_util.c b/src/battle_util.c index 68cf7a1cef..8023bdb539 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -3996,14 +3996,12 @@ static inline uq4_12_t GetSupremeOverlordModifier(u32 battler) return UQ_4_12(1.0) + (UQ_4_12(0.1) * gBattleStruct->supremeOverlordCounter[battler]); } -static inline bool32 HadMoreThanHalfHpNowHasLess(u32 battler) +static inline bool32 HadMoreThanHalfHpNowDoesnt(u32 battler) { u32 cutoff = gBattleMons[battler].maxHP / 2; - if (gBattleMons[battler].maxHP % 2 == 1) - cutoff++; // Had more than half of hp before, now has less - return (gBattleStruct->hpBefore[battler] >= cutoff - && gBattleMons[battler].hp < cutoff); + return (gBattleStruct->hpBefore[battler] > cutoff + && gBattleMons[battler].hp <= cutoff); } u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 moveArg) @@ -5242,7 +5240,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) && TARGET_TURN_DAMAGED && IsBattlerAlive(battler) - && HadMoreThanHalfHpNowHasLess(battler) + && HadMoreThanHalfHpNowDoesnt(battler) && (gMultiHitCounter == 0 || gMultiHitCounter == 1) && !(TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)) && CompareStat(battler, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN)) @@ -5260,7 +5258,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && TARGET_TURN_DAMAGED && IsBattlerAlive(battler) // Had more than half of hp before, now has less - && HadMoreThanHalfHpNowHasLess(battler) + && HadMoreThanHalfHpNowDoesnt(battler) && (gMultiHitCounter == 0 || gMultiHitCounter == 1) && !(TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)) && (CanBattlerSwitch(battler) || !(gBattleTypeFlags & BATTLE_TYPE_TRAINER)) @@ -5700,7 +5698,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && TARGET_TURN_DAMAGED && (gMultiHitCounter == 0 || gMultiHitCounter == 1) // Activates after all hits from a multi-hit move. && IsBattlerAlive(gBattlerTarget) - && HadMoreThanHalfHpNowHasLess(gBattlerTarget) + && HadMoreThanHalfHpNowDoesnt(gBattlerTarget) && !(TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove))) { gBattlerAttacker = gBattlerTarget; diff --git a/test/battle/ability/anger_shell.c b/test/battle/ability/anger_shell.c index 3591c4077f..f0d11d7576 100644 --- a/test/battle/ability/anger_shell.c +++ b/test/battle/ability/anger_shell.c @@ -6,6 +6,7 @@ SINGLE_BATTLE_TEST("Anger Shell activates only if the target had more than 50% o bool32 activates = FALSE; u16 maxHp = 500, hp = 0; + PARAMETRIZE { hp = 250; activates = FALSE; } PARAMETRIZE { hp = 249; activates = FALSE; } PARAMETRIZE { hp = 100; activates = FALSE; } PARAMETRIZE { hp = 50; activates = FALSE; } @@ -41,7 +42,7 @@ SINGLE_BATTLE_TEST("Anger Shell lowers Def/Sp.Def by 1 and raises Atk/Sp.Atk/Spd u16 maxHp = 500; GIVEN { ASSUME(gMovesInfo[MOVE_TACKLE].power != 0); - PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_ANGER_SHELL); MaxHP(maxHp); HP(maxHp / 2 + 1); } + PLAYER(SPECIES_KLAWF) { Ability(ABILITY_ANGER_SHELL); MaxHP(maxHp); HP(maxHp / 2 + 1); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { TURN { MOVE(opponent, MOVE_TACKLE); } @@ -49,15 +50,15 @@ SINGLE_BATTLE_TEST("Anger Shell lowers Def/Sp.Def by 1 and raises Atk/Sp.Atk/Spd ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); ABILITY_POPUP(player, ABILITY_ANGER_SHELL); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); - MESSAGE("Wobbuffet's Defense fell!"); + MESSAGE("Klawf's Defense fell!"); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); - MESSAGE("Wobbuffet's Sp. Def fell!"); + MESSAGE("Klawf's Sp. Def fell!"); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); - MESSAGE("Wobbuffet's Attack rose!"); + MESSAGE("Klawf's Attack rose!"); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); - MESSAGE("Wobbuffet's Sp. Atk rose!"); + MESSAGE("Klawf's Sp. Atk rose!"); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); - MESSAGE("Wobbuffet's Speed rose!"); + MESSAGE("Klawf's Speed rose!"); } THEN { EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE - 1); EXPECT_EQ(player->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE - 1); @@ -73,13 +74,12 @@ SINGLE_BATTLE_TEST("Anger Shell activates after all hits from a multi-hit move") u16 maxHp = 500; GIVEN { ASSUME(gMovesInfo[MOVE_DOUBLE_SLAP].effect == EFFECT_MULTI_HIT); - PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_ANGER_SHELL); MaxHP(maxHp); HP(maxHp / 2 + 1); } + PLAYER(SPECIES_KLAWF) { Ability(ABILITY_ANGER_SHELL); MaxHP(maxHp); HP(maxHp / 2 + 1); } OPPONENT(SPECIES_SHELLDER) { Ability(ABILITY_SKILL_LINK); } // Always hits 5 times. } WHEN { TURN { MOVE(opponent, MOVE_DOUBLE_SLAP); } } SCENE { - for (j = 0; j < 4; j++) - { + for (j = 0; j < 4; j++) { ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_SLAP, opponent); NOT ABILITY_POPUP(player, ABILITY_ANGER_SHELL); } diff --git a/test/battle/ability/berserk.c b/test/battle/ability/berserk.c new file mode 100644 index 0000000000..3bf269e1ee --- /dev/null +++ b/test/battle/ability/berserk.c @@ -0,0 +1,75 @@ +#include "global.h" +#include "test/battle.h" + +SINGLE_BATTLE_TEST("Berserk activates only if the target had more than 50% of its hp") +{ + bool32 activates = FALSE; + u16 maxHp = 500, hp = 0; + + PARAMETRIZE { hp = 250; activates = FALSE; } + PARAMETRIZE { hp = 249; activates = FALSE; } + PARAMETRIZE { hp = 100; activates = FALSE; } + PARAMETRIZE { hp = 50; activates = FALSE; } + PARAMETRIZE { hp = 251; activates = TRUE; } + PARAMETRIZE { hp = 254; activates = TRUE; } + + GIVEN { + ASSUME(gMovesInfo[MOVE_TACKLE].power != 0); + PLAYER(SPECIES_DRAMPA) { Ability(ABILITY_BERSERK); MaxHP(maxHp); HP(hp); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_TACKLE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + if (activates) { + ABILITY_POPUP(player, ABILITY_BERSERK); + } else { + NOT ABILITY_POPUP(player, ABILITY_BERSERK); + } + } THEN { + if (activates) { + EXPECT_EQ(player->statStages[STAT_SPATK], DEFAULT_STAT_STAGE + 1); + } + } +} + +SINGLE_BATTLE_TEST("Berserk raises Sp.Atk by 1") +{ + u16 maxHp = 500; + GIVEN { + ASSUME(gMovesInfo[MOVE_TACKLE].power != 0); + PLAYER(SPECIES_DRAMPA) { Ability(ABILITY_BERSERK); MaxHP(maxHp); HP(maxHp / 2 + 1); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_TACKLE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + ABILITY_POPUP(player, ABILITY_BERSERK); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Drampa's Sp. Atk rose!"); + } THEN { + EXPECT_EQ(player->statStages[STAT_SPATK], DEFAULT_STAT_STAGE + 1); + } +} + +SINGLE_BATTLE_TEST("Berserk activates after all hits from a multi-hit move") +{ + u32 j; + u16 maxHp = 500; + GIVEN { + ASSUME(gMovesInfo[MOVE_DOUBLE_SLAP].effect == EFFECT_MULTI_HIT); + PLAYER(SPECIES_DRAMPA) { Ability(ABILITY_BERSERK); MaxHP(maxHp); HP(maxHp / 2 + 1); } + OPPONENT(SPECIES_SHELLDER) { Ability(ABILITY_SKILL_LINK); } // Always hits 5 times. + } WHEN { + TURN { MOVE(opponent, MOVE_DOUBLE_SLAP); } + } SCENE { + for (j = 0; j < 4; j++) { + ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_SLAP, opponent); + NOT ABILITY_POPUP(player, ABILITY_BERSERK); + } + ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_SLAP, opponent); + ABILITY_POPUP(player, ABILITY_BERSERK); + } THEN { + EXPECT_EQ(player->statStages[STAT_SPATK], DEFAULT_STAT_STAGE + 1); + } +} From 2cc2dc01ca667616b314ac810cc02cce2a007172 Mon Sep 17 00:00:00 2001 From: sneed <56992013+Sneed69@users.noreply.github.com> Date: Fri, 7 Jun 2024 22:54:58 +0300 Subject: [PATCH 10/21] Fix daycare move transferring between evolved mons and allow sharing moves between different forms of the same species (#4479) * Fix daycare move transferring between evolved mons Also allow sharing moves between different forms * Make sure Snorlax gets Snorlax's egg moves instead of Munchlax's * Use GET_BASE_SPECIES_ID * Actually fix Snorlax/Roselia/etc behavior * remove preproc checks * rename ambiguous GetEggMovesSpecies function * remove extra indentation, add incense breeding check * update comment * Update src/daycare.c --------- Co-authored-by: Bassoonian --- include/daycare.h | 2 +- src/daycare.c | 71 ++++++++++++++++++++++++----------------- src/pokedex_plus_hgss.c | 2 +- 3 files changed, 44 insertions(+), 31 deletions(-) diff --git a/include/daycare.h b/include/daycare.h index daea812bed..81e613b07c 100644 --- a/include/daycare.h +++ b/include/daycare.h @@ -32,7 +32,7 @@ void SetDaycareCompatibilityString(void); bool8 NameHasGenderSymbol(const u8 *name, u8 genderRatio); void ShowDaycareLevelMenu(void); void ChooseSendDaycareMon(void); -u8 GetEggMovesSpecies(u16 species, u16 *eggMoves); +u8 GetEggMovesBySpecies(u16 species, u16 *eggMoves); bool8 SpeciesCanLearnEggMove(u16 species, u16 move); #endif // GUARD_DAYCARE_H diff --git a/src/daycare.c b/src/daycare.c index c5a46c58b0..ae734b41a1 100644 --- a/src/daycare.c +++ b/src/daycare.c @@ -34,6 +34,7 @@ static void SetInitialEggData(struct Pokemon *mon, u16 species, struct DayCare * static void DaycarePrintMonInfo(u8 windowId, u32 daycareSlotId, u8 y); static u8 ModifyBreedingScoreForOvalCharm(u8 score); static u8 GetEggMoves(struct Pokemon *pokemon, u16 *eggMoves); +static u16 GetEggSpecies(u16 species); // RAM buffers used to assist with BuildEggMoveset() EWRAM_DATA static u16 sHatchedEggLevelUpMoves[EGG_LVL_UP_MOVES_ARRAY_COUNT] = {0}; @@ -86,6 +87,24 @@ static const struct ListMenuTemplate sDaycareListMenuLevelTemplate = .cursorKind = CURSOR_BLACK_ARROW }; +static const struct { + u16 currSpecies; + u16 item; + u16 babySpecies; +} sIncenseBabyTable[] = +{ + // Regular offspring, Item, Incense Offspring + { SPECIES_WOBBUFFET, ITEM_LAX_INCENSE, SPECIES_WYNAUT }, + { SPECIES_MARILL, ITEM_SEA_INCENSE, SPECIES_AZURILL }, + { SPECIES_SNORLAX, ITEM_FULL_INCENSE, SPECIES_MUNCHLAX }, + { SPECIES_CHANSEY, ITEM_LUCK_INCENSE, SPECIES_HAPPINY }, + { SPECIES_MR_MIME, ITEM_ODD_INCENSE, SPECIES_MIME_JR }, + { SPECIES_CHIMECHO, ITEM_PURE_INCENSE, SPECIES_CHINGLING }, + { SPECIES_SUDOWOODO, ITEM_ROCK_INCENSE, SPECIES_BONSLY }, + { SPECIES_ROSELIA, ITEM_ROSE_INCENSE, SPECIES_BUDEW }, + { SPECIES_MANTINE, ITEM_WAVE_INCENSE, SPECIES_MANTYKE }, +}; + static const u8 *const sCompatibilityMessages[] = { gDaycareText_GetAlongVeryWell, @@ -174,26 +193,42 @@ static void TransferEggMoves(void) { u32 i, j, k, l; u16 numEggMoves; - struct Pokemon mon; for (i = 0; i < DAYCARE_MON_COUNT; i++) { + u16 moveLearnerSpecies = GetBoxMonData(&gSaveBlock1Ptr->daycare.mons[i].mon, MON_DATA_SPECIES); + u16 eggSpecies = GetEggSpecies(moveLearnerSpecies); + if (!GetBoxMonData(&gSaveBlock1Ptr->daycare.mons[i].mon, MON_DATA_SANITY_HAS_SPECIES)) continue; - BoxMonToMon(&gSaveBlock1Ptr->daycare.mons[i].mon, &mon); + // Prevent non-baby species from learning incense baby egg moves + if (P_INCENSE_BREEDING < GEN_9 && eggSpecies != moveLearnerSpecies) + { + for (j = 0; j < ARRAY_COUNT(sIncenseBabyTable); j++) + { + if (sIncenseBabyTable[j].babySpecies == eggSpecies) + { + eggSpecies = sIncenseBabyTable[j].currSpecies; + break; + } + } + } + ClearHatchedEggMoves(); - numEggMoves = GetEggMoves(&mon, sHatchedEggEggMoves); + numEggMoves = GetEggMovesBySpecies(eggSpecies, sHatchedEggEggMoves); for (j = 0; j < numEggMoves; j++) { // Go through other Daycare mons for (k = 0; k < DAYCARE_MON_COUNT; k++) { + u16 moveTeacherSpecies = GetBoxMonData(&gSaveBlock1Ptr->daycare.mons[k].mon, MON_DATA_SPECIES); + if (k == i || !GetBoxMonData(&gSaveBlock1Ptr->daycare.mons[k].mon, MON_DATA_SANITY_HAS_SPECIES)) continue; // Check if you can inherit from them - if (GetBoxMonData(&gSaveBlock1Ptr->daycare.mons[k].mon, MON_DATA_SPECIES) != GetBoxMonData(&gSaveBlock1Ptr->daycare.mons[i].mon, MON_DATA_SPECIES) + if (GET_BASE_SPECIES_ID(moveTeacherSpecies) != GET_BASE_SPECIES_ID(moveLearnerSpecies) && (P_EGG_MOVE_TRANSFER < GEN_9 || GetBoxMonData(&gSaveBlock1Ptr->daycare.mons[i].mon, MON_DATA_HELD_ITEM) != ITEM_MIRROR_HERB) ) continue; @@ -770,7 +805,7 @@ static u8 GetEggMoves(struct Pokemon *pokemon, u16 *eggMoves) return numEggMoves; } -u8 GetEggMovesSpecies(u16 species, u16 *eggMoves) +u8 GetEggMovesBySpecies(u16 species, u16 *eggMoves) { u16 eggMoveIdx; u16 numEggMoves; @@ -954,26 +989,6 @@ void RejectEggFromDayCare(void) RemoveEggFromDayCare(&gSaveBlock1Ptr->daycare); } - -static const struct { - u16 currSpecies; - u16 item; - u16 babySpecies; -} sIncenseBabyTable[] = -{ - // Regular offspring, Item, Incense Offspring - { SPECIES_WOBBUFFET, ITEM_LAX_INCENSE, SPECIES_WYNAUT }, - { SPECIES_MARILL, ITEM_SEA_INCENSE, SPECIES_AZURILL }, - { SPECIES_SNORLAX, ITEM_FULL_INCENSE, SPECIES_MUNCHLAX }, - { SPECIES_CHANSEY, ITEM_LUCK_INCENSE, SPECIES_HAPPINY }, - { SPECIES_MR_MIME, ITEM_ODD_INCENSE, SPECIES_MIME_JR }, - { SPECIES_CHIMECHO, ITEM_PURE_INCENSE, SPECIES_CHINGLING }, - { SPECIES_SUDOWOODO, ITEM_ROCK_INCENSE, SPECIES_BONSLY }, - { SPECIES_ROSELIA, ITEM_ROSE_INCENSE, SPECIES_BUDEW }, - { SPECIES_MANTINE, ITEM_WAVE_INCENSE, SPECIES_MANTYKE }, -}; - -#if P_INCENSE_BREEDING < GEN_9 static void AlterEggSpeciesWithIncenseItem(u16 *species, struct DayCare *daycare) { u32 i; @@ -990,7 +1005,6 @@ static void AlterEggSpeciesWithIncenseItem(u16 *species, struct DayCare *daycare } } } -#endif static const struct { u16 offspring; @@ -1095,9 +1109,8 @@ static void _GiveEggFromDaycare(struct DayCare *daycare) bool8 isEgg; species = DetermineEggSpeciesAndParentSlots(daycare, parentSlots); -#if P_INCENSE_BREEDING < GEN_9 - AlterEggSpeciesWithIncenseItem(&species, daycare); -#endif + if (P_INCENSE_BREEDING < GEN_9) + AlterEggSpeciesWithIncenseItem(&species, daycare); SetInitialEggData(&egg, species, daycare); InheritIVs(&egg, daycare); InheritPokeball(&egg, &daycare->mons[parentSlots[1]].mon, &daycare->mons[parentSlots[0]].mon); diff --git a/src/pokedex_plus_hgss.c b/src/pokedex_plus_hgss.c index 41415053e7..9d89703226 100644 --- a/src/pokedex_plus_hgss.c +++ b/src/pokedex_plus_hgss.c @@ -5130,7 +5130,7 @@ static bool8 CalculateMoves(void) species = GetFormSpeciesId(species, 0); //Calculate amount of Egg and LevelUp moves - numEggMoves = GetEggMovesSpecies(species, statsMovesEgg); + numEggMoves = GetEggMovesBySpecies(species, statsMovesEgg); numLevelUpMoves = GetLevelUpMovesBySpecies(species, statsMovesLevelUp); //Egg moves From f1911dae5937dd832c5bccc1841df790d2673d96 Mon Sep 17 00:00:00 2001 From: sneed <56992013+Sneed69@users.noreply.github.com> Date: Sat, 8 Jun 2024 08:27:44 +0300 Subject: [PATCH 11/21] Fix mycelium might and ability shield (#4740) * Fix mycelium might and ability shield * fix check --- include/battle_util.h | 1 - src/battle_util.c | 24 ++------ test/battle/hold_effect/ability_shield.c | 72 ++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 19 deletions(-) diff --git a/include/battle_util.h b/include/battle_util.h index a5349a7c2a..6c4724c1d3 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -244,7 +244,6 @@ bool32 CanBeConfused(u32 battler); bool32 IsBattlerTerrainAffected(u32 battler, u32 terrainFlag); u32 GetBattlerAffectionHearts(u32 battler); u32 CountBattlerStatIncreases(u32 battler, bool32 countEvasionAcc); -bool32 IsMyceliumMightOnField(void); bool32 ChangeTypeBasedOnTerrain(u32 battler); void RemoveConfusionStatus(u32 battler); u8 GetBattlerGender(u32 battler); diff --git a/src/battle_util.c b/src/battle_util.c index 8023bdb539..f785b5d142 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -6174,26 +6174,16 @@ bool32 IsNeutralizingGasOnField(void) return FALSE; } -bool32 IsMyceliumMightOnField(void) -{ - u32 i; - - for (i = 0; i < gBattlersCount; i++) - { - if (IsBattlerAlive(i) && gBattleMons[i].ability == ABILITY_MYCELIUM_MIGHT && IS_MOVE_STATUS(gCurrentMove)) - return TRUE; - } - - return FALSE; -} - bool32 IsMoldBreakerTypeAbility(u32 ability) { - return (ability == ABILITY_MOLD_BREAKER || ability == ABILITY_TERAVOLT || ability == ABILITY_TURBOBLAZE); + return (ability == ABILITY_MOLD_BREAKER || ability == ABILITY_TERAVOLT || ability == ABILITY_TURBOBLAZE + || (ability == ABILITY_MYCELIUM_MIGHT && IS_MOVE_STATUS(gCurrentMove))); } u32 GetBattlerAbility(u32 battler) { + bool32 noAbilityShield = GetBattlerHoldEffectIgnoreAbility(battler, TRUE) != HOLD_EFFECT_ABILITY_SHIELD; + if (gAbilitiesInfo[gBattleMons[battler].ability].cantBeSuppressed) return gBattleMons[battler].ability; @@ -6202,16 +6192,14 @@ u32 GetBattlerAbility(u32 battler) if (IsNeutralizingGasOnField() && gBattleMons[battler].ability != ABILITY_NEUTRALIZING_GAS - && GetBattlerHoldEffectIgnoreAbility(battler, TRUE) != HOLD_EFFECT_ABILITY_SHIELD) - return ABILITY_NONE; - - if (IsMyceliumMightOnField()) + && noAbilityShield) return ABILITY_NONE; if (((IsMoldBreakerTypeAbility(gBattleMons[gBattlerAttacker].ability) && !(gStatuses3[gBattlerAttacker] & STATUS3_GASTRO_ACID)) || gMovesInfo[gCurrentMove].ignoresTargetAbility) && gAbilitiesInfo[gBattleMons[battler].ability].breakable + && noAbilityShield && gBattlerByTurnOrder[gCurrentTurnActionNumber] == gBattlerAttacker && gActionsByTurnOrder[gBattlerByTurnOrder[gBattlerAttacker]] == B_ACTION_USE_MOVE && gCurrentTurnActionNumber < gBattlersCount) diff --git a/test/battle/hold_effect/ability_shield.c b/test/battle/hold_effect/ability_shield.c index c84397abfa..ee84b2c5e0 100644 --- a/test/battle/hold_effect/ability_shield.c +++ b/test/battle/hold_effect/ability_shield.c @@ -32,3 +32,75 @@ SINGLE_BATTLE_TEST("Ability Shield prevents Neutralizing Gas") } } } + +SINGLE_BATTLE_TEST("Ability Shield protects against Mold Breaker") +{ + u32 item; + + PARAMETRIZE { item = ITEM_ABILITY_SHIELD; } + PARAMETRIZE { item = ITEM_NONE; } + + GIVEN { + PLAYER(SPECIES_SHEDINJA) { Ability(ABILITY_WONDER_GUARD); Item(item); } + OPPONENT(SPECIES_TINKATON) { Ability(ABILITY_MOLD_BREAKER); } + } WHEN { + TURN { MOVE(opponent, MOVE_GIGATON_HAMMER); } + } SCENE { + if (item == ITEM_ABILITY_SHIELD) { + NONE_OF { + MESSAGE("Shedinja fainted!"); + } + } else { + MESSAGE("Shedinja fainted!"); + } + } +} + +SINGLE_BATTLE_TEST("Ability Shield protects against Mycelium Might") +{ + u32 item; + + PARAMETRIZE { item = ITEM_ABILITY_SHIELD; } + PARAMETRIZE { item = ITEM_NONE; } + + GIVEN { + PLAYER(SPECIES_VIGOROTH) { Ability(ABILITY_VITAL_SPIRIT); Item(item); } + OPPONENT(SPECIES_TOEDSCOOL) { Ability(ABILITY_MYCELIUM_MIGHT); } + } WHEN { + TURN { MOVE(opponent, MOVE_SPORE); MOVE(player, MOVE_SPORE); } + } SCENE { + + if (item == ITEM_ABILITY_SHIELD) { + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SPORE, opponent); + STATUS_ICON(player, sleep: TRUE); + } + } else { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SPORE, opponent); + STATUS_ICON(player, sleep: TRUE); + } + } +} + +SINGLE_BATTLE_TEST("Ability Shield protects against Sunsteel Strike") +{ + u32 item; + + PARAMETRIZE { item = ITEM_ABILITY_SHIELD; } + PARAMETRIZE { item = ITEM_NONE; } + + GIVEN { + PLAYER(SPECIES_SHEDINJA) { Ability(ABILITY_WONDER_GUARD); Item(item); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SUNSTEEL_STRIKE); } + } SCENE { + if (item == ITEM_ABILITY_SHIELD) { + NONE_OF { + MESSAGE("Shedinja fainted!"); + } + } else { + MESSAGE("Shedinja fainted!"); + } + } +} From 568ce39c5dbfa9a471541af643a9e98fe0e5522d Mon Sep 17 00:00:00 2001 From: Bassoonian Date: Sat, 8 Jun 2024 07:36:39 +0200 Subject: [PATCH 12/21] Adds forbidden status parameter to FORM_CHANGE_ITEM_USE (#4738) --- include/constants/form_change_types.h | 2 ++ src/data/pokemon/form_change_tables.h | 2 +- src/pokemon.c | 18 +++++++++++------- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/include/constants/form_change_types.h b/include/constants/form_change_types.h index 30bb54d027..94f97639f8 100644 --- a/include/constants/form_change_types.h +++ b/include/constants/form_change_types.h @@ -24,6 +24,8 @@ // param2: time of day to check, optional. // - DAY if Form change that activates in the daytime. // - NIGHT if Form change that activates at nighttime. +// - 0 if irrelevant, but param3 is necessary. +// param3: illegal statuses to have, optional. #define FORM_CHANGE_ITEM_USE 2 // TODO: Form change that activates when the Pokémon learns or forgets the move. diff --git a/src/data/pokemon/form_change_tables.h b/src/data/pokemon/form_change_tables.h index 0b8eb485a9..84b7a86088 100644 --- a/src/data/pokemon/form_change_tables.h +++ b/src/data/pokemon/form_change_tables.h @@ -624,7 +624,7 @@ static const struct FormChange sGiratinaFormChangeTable[] = { #if P_FAMILY_SHAYMIN static const struct FormChange sShayminFormChangeTable[] = { - {FORM_CHANGE_ITEM_USE, SPECIES_SHAYMIN_SKY, ITEM_GRACIDEA, DAY}, + {FORM_CHANGE_ITEM_USE, SPECIES_SHAYMIN_SKY, ITEM_GRACIDEA, DAY, STATUS1_FREEZE | STATUS1_FROSTBITE}, {FORM_CHANGE_WITHDRAW, SPECIES_SHAYMIN_LAND}, {FORM_CHANGE_TIME_OF_DAY, SPECIES_SHAYMIN_LAND, NIGHT}, {FORM_CHANGE_STATUS, SPECIES_SHAYMIN_LAND, STATUS1_FREEZE | STATUS1_FROSTBITE}, diff --git a/src/pokemon.c b/src/pokemon.c index daa02077ce..763c044c76 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -6196,20 +6196,24 @@ u16 GetFormChangeTargetSpeciesBoxMon(struct BoxPokemon *boxMon, u16 method, u32 case FORM_CHANGE_ITEM_USE: if (arg == formChanges[i].param1) { + bool32 pass = TRUE; switch (formChanges[i].param2) { case DAY: - if (GetTimeOfDay() != TIME_NIGHT) - targetSpecies = formChanges[i].targetSpecies; + if (GetTimeOfDay() == TIME_NIGHT) + pass = FALSE; break; case NIGHT: - if (GetTimeOfDay() == TIME_NIGHT) - targetSpecies = formChanges[i].targetSpecies; - break; - default: - targetSpecies = formChanges[i].targetSpecies; + if (GetTimeOfDay() != TIME_NIGHT) + pass = FALSE; break; } + + if (formChanges[i].param3 != STATUS1_NONE && GetBoxMonData(boxMon, MON_DATA_STATUS, NULL) & formChanges[i].param3) + pass = FALSE; + + if (pass) + targetSpecies = formChanges[i].targetSpecies; } break; case FORM_CHANGE_ITEM_USE_MULTICHOICE: From b8e199ae9e810f5367c909f06717af43536e0129 Mon Sep 17 00:00:00 2001 From: Pawkkie Date: Sat, 8 Jun 2024 12:37:59 -0400 Subject: [PATCH 13/21] Review feedback --- test/battle/ability/clear_body.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/test/battle/ability/clear_body.c b/test/battle/ability/clear_body.c index 9dc6ab8147..c05a78c45b 100644 --- a/test/battle/ability/clear_body.c +++ b/test/battle/ability/clear_body.c @@ -155,6 +155,7 @@ SINGLE_BATTLE_TEST("Clear Body doesn't prevent Speed reduction from Iron Ball") } WHEN { TURN { } } SCENE { + NOT ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); if (heldItem == ITEM_IRON_BALL) { MESSAGE("Wobbuffet used Celebrate!"); MESSAGE("Foe Beldum used Celebrate!"); @@ -174,6 +175,7 @@ SINGLE_BATTLE_TEST("Clear Body doesn't prevent Speed reduction from paralysis") TURN { MOVE(player, MOVE_THUNDER_WAVE); } TURN { MOVE(player, MOVE_THUNDER_WAVE); } } SCENE { + NOT ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); MESSAGE("Foe Beldum used Celebrate!"); MESSAGE("Wobbuffet used Thunder Wave!"); MESSAGE("Wobbuffet used Thunder Wave!"); @@ -196,6 +198,7 @@ SINGLE_BATTLE_TEST("Clear Body doesn't prevent Attack reduction from burn", s16 } WHEN { TURN { MOVE(opponent, MOVE_TACKLE); } } SCENE { + NOT ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); HP_BAR(player, captureDamage: &results[i].damage); } FINALLY { EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage); @@ -214,6 +217,7 @@ SINGLE_BATTLE_TEST("Clear Body doesn't prevent receiving negative stat changes f TURN { MOVE(player, MOVE_SCARY_FACE); MOVE(opponent, MOVE_BATON_PASS); SEND_OUT(opponent, 1); } TURN { MOVE(player, MOVE_SCARY_FACE); } } SCENE { + NOT ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); MESSAGE("Wobbuffet used Scary Face!"); MESSAGE("Foe Beldum used Celebrate!"); } @@ -233,6 +237,7 @@ SINGLE_BATTLE_TEST("Clear Body doesn't prevent Topsy-Turvy") TURN { MOVE(player, MOVE_TOPSY_TURVY); } TURN { MOVE(player, MOVE_SCARY_FACE); } } SCENE { + NOT ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); MESSAGE("Wobbuffet used Topsy-Turvy!"); MESSAGE("Foe Beldum used Celebrate!"); MESSAGE("Foe Beldum used Celebrate!"); @@ -245,18 +250,19 @@ SINGLE_BATTLE_TEST("Clear Body doesn't prevent Spectral Thief from resetting pos GIVEN { ASSUME(MoveHasAdditionalEffect(MOVE_SPECTRAL_THIEF, MOVE_EFFECT_SPECTRAL_THIEF) == TRUE); ASSUME(gMovesInfo[MOVE_AGILITY].effect == EFFECT_SPEED_UP_2); - PLAYER(SPECIES_WOBBUFFET) { Speed(4); Moves(MOVE_SPECTRAL_THIEF, MOVE_CELEBRATE); } - OPPONENT(SPECIES_BELDUM) { Speed(5); Ability(ABILITY_CLEAR_BODY); Moves(MOVE_AGILITY, MOVE_CELEBRATE); } + PLAYER(SPECIES_WOBBUFFET) { Speed(4); } + OPPONENT(SPECIES_METANG) { Speed(5); Ability(ABILITY_CLEAR_BODY); } } WHEN { TURN{ MOVE(opponent, MOVE_AGILITY); } TURN{ MOVE(player, MOVE_SPECTRAL_THIEF); } TURN{ } } SCENE { - MESSAGE("Foe Beldum used Agility!"); + NOT ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); + MESSAGE("Foe Metang used Agility!"); MESSAGE("Wobbuffet used Celebrate!"); - MESSAGE("Foe Beldum used Celebrate!"); + MESSAGE("Foe Metang used Celebrate!"); MESSAGE("Wobbuffet used SpectrlThief!"); MESSAGE("Wobbuffet used Celebrate!"); - MESSAGE("Foe Beldum used Celebrate!"); + MESSAGE("Foe Metang used Celebrate!"); } } From db15190508be2a61c02e0c031e45a21e7a33c976 Mon Sep 17 00:00:00 2001 From: sneed <56992013+Sneed69@users.noreply.github.com> Date: Sat, 8 Jun 2024 23:58:37 +0300 Subject: [PATCH 14/21] Use GetBattlerAbility instead of the ability field in more places (#4746) * Fix Skill Link ignoring gastro acid, neutralising gas * Fix own tempo stopping berserk gene confusion when disabled --- src/battle_util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/battle_util.c b/src/battle_util.c index f785b5d142..ccb669e2a4 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -3580,7 +3580,7 @@ u8 AtkCanceller_UnableToUseMove(u32 moveType) case CANCELLER_MULTIHIT_MOVES: if (gMovesInfo[gCurrentMove].effect == EFFECT_MULTI_HIT) { - u16 ability = gBattleMons[gBattlerAttacker].ability; + u32 ability = GetBattlerAbility(gBattlerAttacker); if (ability == ABILITY_SKILL_LINK) { @@ -11170,7 +11170,7 @@ void RemoveConfusionStatus(u32 battler) static bool32 CanBeInfinitelyConfused(u32 battler) { - if (gBattleMons[battler].ability == ABILITY_OWN_TEMPO + if (GetBattlerAbility(battler) == ABILITY_OWN_TEMPO || IsBattlerTerrainAffected(battler, STATUS_FIELD_MISTY_TERRAIN) || gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD) { From a7a89df80fd6174f875430dd4439f1e654598e94 Mon Sep 17 00:00:00 2001 From: Pawkkie Date: Sat, 8 Jun 2024 20:32:57 -0400 Subject: [PATCH 15/21] Review feedback --- test/battle/ability/clear_body.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/test/battle/ability/clear_body.c b/test/battle/ability/clear_body.c index c05a78c45b..16a419d8c4 100644 --- a/test/battle/ability/clear_body.c +++ b/test/battle/ability/clear_body.c @@ -45,7 +45,7 @@ SINGLE_BATTLE_TEST("Clear Body prevents stat stage reduction from moves") ASSUME(gMovesInfo[MOVE_CONFIDE].effect == EFFECT_SPECIAL_ATTACK_DOWN); ASSUME(gMovesInfo[MOVE_FAKE_TEARS].effect == EFFECT_SPECIAL_DEFENSE_DOWN_2); ASSUME(gMovesInfo[MOVE_SCARY_FACE].effect == EFFECT_SPEED_DOWN_2); - ASSUME(B_UPDATED_MOVE_DATA >= GEN_6); + ASSUME(B_UPDATED_MOVE_DATA >= GEN_6); // For Sweet Scent ASSUME(gMovesInfo[MOVE_SWEET_SCENT].effect == EFFECT_EVASION_DOWN_2); ASSUME(gMovesInfo[MOVE_SAND_ATTACK].effect == EFFECT_ACCURACY_DOWN); PLAYER(SPECIES_WOBBUFFET) @@ -90,7 +90,8 @@ SINGLE_BATTLE_TEST("Clear Body doesn't prevent stat stage reduction from moves u TURN { MOVE(opponent, MOVE_SUPERPOWER); } } SCENE { NONE_OF { - ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); MESSAGE("Foe Beldum's Clear Body prevents stat loss!"); + ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); + MESSAGE("Foe Beldum's Clear Body prevents stat loss!"); } } } @@ -129,7 +130,7 @@ SINGLE_BATTLE_TEST("Mold Breaker, Teravolt, and Turboblaze ignore Clear Body") ASSUME(gMovesInfo[MOVE_CONFIDE].effect == EFFECT_SPECIAL_ATTACK_DOWN); ASSUME(gMovesInfo[MOVE_FAKE_TEARS].effect == EFFECT_SPECIAL_DEFENSE_DOWN_2); ASSUME(gMovesInfo[MOVE_SCARY_FACE].effect == EFFECT_SPEED_DOWN_2); - ASSUME(B_UPDATED_MOVE_DATA >= GEN_6); + ASSUME(B_UPDATED_MOVE_DATA >= GEN_6); // For Sweet Scent ASSUME(gMovesInfo[MOVE_SWEET_SCENT].effect == EFFECT_EVASION_DOWN_2); ASSUME(gMovesInfo[MOVE_SAND_ATTACK].effect == EFFECT_ACCURACY_DOWN); PLAYER(SPECIES_WOBBUFFET) { Ability(ability); } @@ -138,7 +139,8 @@ SINGLE_BATTLE_TEST("Mold Breaker, Teravolt, and Turboblaze ignore Clear Body") TURN { MOVE(player, move); } } SCENE { NONE_OF { - ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); MESSAGE("Foe Beldum's Clear Body prevents stat loss!"); + ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); + MESSAGE("Foe Beldum's Clear Body prevents stat loss!"); } } } From 55a2c85d9511bea0df5b949ac4533e2490676ea0 Mon Sep 17 00:00:00 2001 From: Pawkkie Date: Sat, 8 Jun 2024 20:47:19 -0400 Subject: [PATCH 16/21] Review feedback --- test/battle/ability/clear_body.c | 6 ++---- test/battle/hold_effect/clear_amulet.c | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/test/battle/ability/clear_body.c b/test/battle/ability/clear_body.c index 16a419d8c4..f265c4ea5c 100644 --- a/test/battle/ability/clear_body.c +++ b/test/battle/ability/clear_body.c @@ -45,8 +45,7 @@ SINGLE_BATTLE_TEST("Clear Body prevents stat stage reduction from moves") ASSUME(gMovesInfo[MOVE_CONFIDE].effect == EFFECT_SPECIAL_ATTACK_DOWN); ASSUME(gMovesInfo[MOVE_FAKE_TEARS].effect == EFFECT_SPECIAL_DEFENSE_DOWN_2); ASSUME(gMovesInfo[MOVE_SCARY_FACE].effect == EFFECT_SPEED_DOWN_2); - ASSUME(B_UPDATED_MOVE_DATA >= GEN_6); // For Sweet Scent - ASSUME(gMovesInfo[MOVE_SWEET_SCENT].effect == EFFECT_EVASION_DOWN_2); + ASSUME(gMovesInfo[MOVE_SWEET_SCENT].effect == (B_UPDATED_MOVE_DATA >= GEN_6 ? EFFECT_EVASION_DOWN_2 : EFFECT_EVASION_DOWN)); ASSUME(gMovesInfo[MOVE_SAND_ATTACK].effect == EFFECT_ACCURACY_DOWN); PLAYER(SPECIES_WOBBUFFET) OPPONENT(SPECIES_BELDUM) { Ability(ABILITY_CLEAR_BODY); } @@ -130,8 +129,7 @@ SINGLE_BATTLE_TEST("Mold Breaker, Teravolt, and Turboblaze ignore Clear Body") ASSUME(gMovesInfo[MOVE_CONFIDE].effect == EFFECT_SPECIAL_ATTACK_DOWN); ASSUME(gMovesInfo[MOVE_FAKE_TEARS].effect == EFFECT_SPECIAL_DEFENSE_DOWN_2); ASSUME(gMovesInfo[MOVE_SCARY_FACE].effect == EFFECT_SPEED_DOWN_2); - ASSUME(B_UPDATED_MOVE_DATA >= GEN_6); // For Sweet Scent - ASSUME(gMovesInfo[MOVE_SWEET_SCENT].effect == EFFECT_EVASION_DOWN_2); + ASSUME(gMovesInfo[MOVE_SWEET_SCENT].effect == (B_UPDATED_MOVE_DATA >= GEN_6 ? EFFECT_EVASION_DOWN_2 : EFFECT_EVASION_DOWN)); ASSUME(gMovesInfo[MOVE_SAND_ATTACK].effect == EFFECT_ACCURACY_DOWN); PLAYER(SPECIES_WOBBUFFET) { Ability(ability); } OPPONENT(SPECIES_BELDUM) { Ability(ABILITY_CLEAR_BODY); } diff --git a/test/battle/hold_effect/clear_amulet.c b/test/battle/hold_effect/clear_amulet.c index 9500419540..f2059a0285 100644 --- a/test/battle/hold_effect/clear_amulet.c +++ b/test/battle/hold_effect/clear_amulet.c @@ -47,8 +47,7 @@ SINGLE_BATTLE_TEST("Clear Amulet prevents stat reducing effects") ASSUME(gMovesInfo[MOVE_CONFIDE].effect == EFFECT_SPECIAL_ATTACK_DOWN); ASSUME(gMovesInfo[MOVE_FAKE_TEARS].effect == EFFECT_SPECIAL_DEFENSE_DOWN_2); ASSUME(gMovesInfo[MOVE_SCARY_FACE].effect == EFFECT_SPEED_DOWN_2); - ASSUME(B_UPDATED_MOVE_DATA >= GEN_6); - ASSUME(gMovesInfo[MOVE_SWEET_SCENT].effect == EFFECT_EVASION_DOWN_2); + ASSUME(gMovesInfo[MOVE_SWEET_SCENT].effect == (B_UPDATED_MOVE_DATA >= GEN_6 ? EFFECT_EVASION_DOWN_2 : EFFECT_EVASION_DOWN)); ASSUME(gMovesInfo[MOVE_SAND_ATTACK].effect == EFFECT_ACCURACY_DOWN); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_CLEAR_AMULET); }; From 1ca4676c4c6e5546c5e0c514e831cc6614929c85 Mon Sep 17 00:00:00 2001 From: sneed Date: Sun, 9 Jun 2024 22:30:49 +0300 Subject: [PATCH 17/21] fix ai crit calculations --- include/battle_script_commands.h | 2 +- src/battle_ai_util.c | 16 +++++++++++---- src/battle_script_commands.c | 34 ++++++++++++++++++++------------ 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/include/battle_script_commands.h b/include/battle_script_commands.h index 540390bb53..5075d52be7 100644 --- a/include/battle_script_commands.h +++ b/include/battle_script_commands.h @@ -24,7 +24,7 @@ struct PickupItem s32 CalcCritChanceStageArgs(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, u32 abilityAtk, u32 abilityDef, u32 holdEffectAtk); s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility); -s32 GetCritHitChance(s32 critChanceIndex); +s32 GetCritHitOdds(s32 critChanceIndex); u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect); u8 GetBattlerTurnOrderNum(u8 battlerId); bool32 NoAliveMonsForPlayer(void); diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 4524e3b25b..f8275d417a 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -515,15 +515,23 @@ s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectivenes aiData->abilities[battlerAtk], aiData->abilities[battlerDef]); critChanceIndex = CalcCritChanceStageArgs(battlerAtk, battlerDef, move, FALSE, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], aiData->holdEffects[battlerAtk]); - if (critChanceIndex > 1) // Consider crit damage only if a move has at least +1 crit chance + if (critChanceIndex > 1) // Consider crit damage only if a move has at least +2 crit chance { s32 critDmg = CalculateMoveDamageVars(move, battlerAtk, battlerDef, moveType, fixedBasePower, effectivenessMultiplier, weather, TRUE, aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef], aiData->abilities[battlerAtk], aiData->abilities[battlerDef]); - u32 critChance = GetCritHitChance(critChanceIndex); - // With critChance getting closer to 1, dmg gets closer to critDmg. - dmg = LowestRollDmg((critDmg + normalDmg * (critChance - 1)) / (critChance)); + u32 critOdds = GetCritHitOdds(critChanceIndex); // Crit chance is 1/critOdds + // With critOdds getting closer to 1, dmg gets closer to critDmg. + dmg = LowestRollDmg((critDmg + normalDmg * (critOdds - 1)) / (critOdds)); + } + else if (critChanceIndex == -2) // Guaranteed critical + { + s32 critDmg = CalculateMoveDamageVars(move, battlerAtk, battlerDef, moveType, fixedBasePower, + effectivenessMultiplier, weather, TRUE, + aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef], + aiData->abilities[battlerAtk], aiData->abilities[battlerDef]); + dmg = LowestRollDmg(critDmg); } else { diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index e967923931..d227456224 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1905,11 +1905,11 @@ static void Cmd_ppreduce(void) // The chance is 1/N for each stage. #if B_CRIT_CHANCE >= GEN_7 - static const u8 sCriticalHitChance[] = {24, 8, 2, 1, 1}; + static const u8 sCriticalHitOdds[] = {24, 8, 2, 1, 1}; #elif B_CRIT_CHANCE == GEN_6 - static const u8 sCriticalHitChance[] = {16, 8, 2, 1, 1}; + static const u8 sCriticalHitOdds[] = {16, 8, 2, 1, 1}; #else - static const u8 sCriticalHitChance[] = {16, 8, 4, 3, 2}; // Gens 2,3,4,5 + static const u8 sCriticalHitOdds[] = {16, 8, 4, 3, 2}; // Gens 2,3,4,5 #endif // B_CRIT_CHANCE #define BENEFITS_FROM_LEEK(battler, holdEffect)((holdEffect == HOLD_EFFECT_LEEK) && (GET_BASE_SPECIES_ID(gBattleMons[battler].species) == SPECIES_FARFETCHD || gBattleMons[battler].species == SPECIES_SIRFETCHD)) @@ -1917,8 +1917,7 @@ s32 CalcCritChanceStageArgs(u32 battlerAtk, u32 battlerDef, u32 move, bool32 rec { s32 critChance = 0; - if (gSideStatuses[battlerDef] & SIDE_STATUS_LUCKY_CHANT - || abilityDef == ABILITY_BATTLE_ARMOR || abilityDef == ABILITY_SHELL_ARMOR) + if (gSideStatuses[battlerDef] & SIDE_STATUS_LUCKY_CHANT) { critChance = -1; } @@ -1940,12 +1939,21 @@ s32 CalcCritChanceStageArgs(u32 battlerAtk, u32 battlerDef, u32 move, bool32 rec + (abilityAtk == ABILITY_SUPER_LUCK) + gBattleStruct->bonusCritStages[gBattlerAttacker]; - // Record ability only if move had at least +3 chance to get a crit - if (critChance >= 3 && recordAbility && (abilityDef == ABILITY_BATTLE_ARMOR || abilityDef == ABILITY_SHELL_ARMOR)) - RecordAbilityBattle(battlerDef, abilityDef); + if (critChance >= ARRAY_COUNT(sCriticalHitOdds)) + critChance = ARRAY_COUNT(sCriticalHitOdds) - 1; + } - if (critChance >= ARRAY_COUNT(sCriticalHitChance)) - critChance = ARRAY_COUNT(sCriticalHitChance) - 1; + if (critChance != -1 && (abilityDef == ABILITY_BATTLE_ARMOR || abilityDef == ABILITY_SHELL_ARMOR)) + { + // Record ability only if move had 100% chance to get a crit + if (recordAbility) + { + if (critChance == -2) + RecordAbilityBattle(battlerDef, abilityDef); + else if (sCriticalHitOdds[critChance] == 1) + RecordAbilityBattle(battlerDef, abilityDef); + } + critChance = -1; } return critChance; @@ -1960,12 +1968,12 @@ s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordA } #undef BENEFITS_FROM_LEEK -s32 GetCritHitChance(s32 critChanceIndex) +s32 GetCritHitOdds(s32 critChanceIndex) { if (critChanceIndex < 0) return -1; else - return sCriticalHitChance[critChanceIndex]; + return sCriticalHitOdds[critChanceIndex]; } static void Cmd_critcalc(void) @@ -1983,7 +1991,7 @@ static void Cmd_critcalc(void) else if (critChance == -2) gIsCriticalHit = TRUE; else - gIsCriticalHit = RandomWeighted(RNG_CRITICAL_HIT, sCriticalHitChance[critChance] - 1, 1); + gIsCriticalHit = RandomWeighted(RNG_CRITICAL_HIT, sCriticalHitOdds[critChance] - 1, 1); // Counter for EVO_CRITICAL_HITS. partySlot = gBattlerPartyIndexes[gBattlerAttacker]; From aa50bfef28795b9a8caca0248cd274bbef5395ff Mon Sep 17 00:00:00 2001 From: sneed Date: Sun, 9 Jun 2024 23:41:12 +0300 Subject: [PATCH 18/21] add test --- test/battle/ai.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/battle/ai.c b/test/battle/ai.c index 28e541befd..819eb2edaa 100644 --- a/test/battle/ai.c +++ b/test/battle/ai.c @@ -955,3 +955,26 @@ AI_DOUBLE_BATTLE_TEST("AI will the see a corresponding absorbing ability on part TURN { EXPECT_MOVE(opponentLeft, MOVE_TACKLE); } } } + +AI_SINGLE_BATTLE_TEST("AI calculates guaranteed criticals and detects critical immunity") +{ + u32 ability; + PARAMETRIZE { ability = ABILITY_SWIFT_SWIM; } + PARAMETRIZE { ability = ABILITY_SHELL_ARMOR; } + + GIVEN { + ASSUME(gMovesInfo[MOVE_STORM_THROW].alwaysCriticalHit); + ASSUME(gMovesInfo[MOVE_STORM_THROW].power == 60); + ASSUME(gMovesInfo[MOVE_BRICK_BREAK].power == 75); + ASSUME(gMovesInfo[MOVE_STORM_THROW].type == gMovesInfo[MOVE_BRICK_BREAK].type); + ASSUME(gMovesInfo[MOVE_STORM_THROW].category == gMovesInfo[MOVE_BRICK_BREAK].category); + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT); + PLAYER(SPECIES_OMASTAR) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_STORM_THROW, MOVE_BRICK_BREAK); } + } WHEN { + if (ability == ABILITY_SHELL_ARMOR) + TURN { EXPECT_MOVE(opponent, MOVE_BRICK_BREAK); } + else + TURN { EXPECT_MOVE(opponent, MOVE_STORM_THROW); } + } +} From d8685bb3b105d59d995ad6837f75bd4e01aaa82a Mon Sep 17 00:00:00 2001 From: sneed Date: Mon, 10 Jun 2024 22:02:36 +0300 Subject: [PATCH 19/21] tar shot works properly --- src/battle_util.c | 4 +-- test/battle/move_effect/tar_shot.c | 45 ++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 test/battle/move_effect/tar_shot.c diff --git a/src/battle_util.c b/src/battle_util.c index ccb669e2a4..8a077ffb4e 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -10039,8 +10039,6 @@ static inline void MulByTypeEffectiveness(uq4_12_t *modifier, u32 move, u32 move mod = UQ_4_12(2.0); if (moveType == TYPE_GROUND && defType == TYPE_FLYING && IsBattlerGrounded(battlerDef) && mod == UQ_4_12(0.0)) mod = UQ_4_12(1.0); - if (moveType == TYPE_FIRE && gDisableStructs[battlerDef].tarShot) - mod = UQ_4_12(2.0); // B_WEATHER_STRONG_WINDS weakens Super Effective moves against Flying-type Pokémon if (gBattleWeather & B_WEATHER_STRONG_WINDS && WEATHER_HAS_EFFECT) @@ -10097,6 +10095,8 @@ static inline uq4_12_t CalcTypeEffectivenessMultiplierInternal(u32 move, u32 mov if (GetBattlerType(battlerDef, 2) != TYPE_MYSTERY && GetBattlerType(battlerDef, 2) != GetBattlerType(battlerDef, 1) && GetBattlerType(battlerDef, 2) != GetBattlerType(battlerDef, 0)) MulByTypeEffectiveness(&modifier, move, moveType, battlerDef, GetBattlerType(battlerDef, 2), battlerAtk, recordAbilities); + if (moveType == TYPE_FIRE && gDisableStructs[battlerDef].tarShot) + modifier = uq4_12_multiply(modifier, UQ_4_12(2.0)); if (recordAbilities && (illusionSpecies = GetIllusionMonSpecies(battlerDef))) TryNoticeIllusionInTypeEffectiveness(move, moveType, battlerAtk, battlerDef, modifier, illusionSpecies); diff --git a/test/battle/move_effect/tar_shot.c b/test/battle/move_effect/tar_shot.c new file mode 100644 index 0000000000..863a794889 --- /dev/null +++ b/test/battle/move_effect/tar_shot.c @@ -0,0 +1,45 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gMovesInfo[MOVE_TAR_SHOT].effect == EFFECT_TAR_SHOT); +} + +SINGLE_BATTLE_TEST("Tar Shot doubles the effectiveness of Fire-type moves used on the target") +{ + s16 damage[2]; + u32 species; + + PARAMETRIZE { species = SPECIES_WOBBUFFET; } + PARAMETRIZE { species = SPECIES_OMASTAR; } // Dual type with double resists + + ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] == TYPE_PSYCHIC); + ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[1] == TYPE_PSYCHIC); + ASSUME(gSpeciesInfo[SPECIES_OMASTAR].types[0] == TYPE_ROCK); + ASSUME(gSpeciesInfo[SPECIES_OMASTAR].types[1] == TYPE_WATER); + ASSUME(gMovesInfo[MOVE_EMBER].type == TYPE_FIRE); + + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(species); + } WHEN { + //TURN { MOVE(player, MOVE_FORESTS_CURSE); } // Adds third type + TURN { MOVE(player, MOVE_EMBER); } + TURN { MOVE(player, MOVE_TAR_SHOT); } + TURN { MOVE(player, MOVE_EMBER); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, player); + HP_BAR(opponent, captureDamage: &damage[0]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TAR_SHOT, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, player); + HP_BAR(opponent, captureDamage: &damage[1]); + if (species != SPECIES_OMASTAR) + MESSAGE("It's super effective!"); + else + MESSAGE("It's not very effective…"); + } THEN { + EXPECT_MUL_EQ(damage[0], Q_4_12(2.0), damage[1]); + } +} + From 178568e05d3901624b0eec738dd0df1a584a1734 Mon Sep 17 00:00:00 2001 From: sneed <56992013+Sneed69@users.noreply.github.com> Date: Mon, 10 Jun 2024 22:15:39 +0300 Subject: [PATCH 20/21] Update test/battle/move_effect/tar_shot.c Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com> --- test/battle/move_effect/tar_shot.c | 1 - 1 file changed, 1 deletion(-) diff --git a/test/battle/move_effect/tar_shot.c b/test/battle/move_effect/tar_shot.c index 863a794889..61aca1bec1 100644 --- a/test/battle/move_effect/tar_shot.c +++ b/test/battle/move_effect/tar_shot.c @@ -24,7 +24,6 @@ SINGLE_BATTLE_TEST("Tar Shot doubles the effectiveness of Fire-type moves used o PLAYER(SPECIES_WOBBUFFET); OPPONENT(species); } WHEN { - //TURN { MOVE(player, MOVE_FORESTS_CURSE); } // Adds third type TURN { MOVE(player, MOVE_EMBER); } TURN { MOVE(player, MOVE_TAR_SHOT); } TURN { MOVE(player, MOVE_EMBER); } From 02ad63784997cb2aeb8507962ccdedda200785ad Mon Sep 17 00:00:00 2001 From: Pawkkie Date: Mon, 10 Jun 2024 21:40:42 -0400 Subject: [PATCH 21/21] Review feedback --- test/battle/ability/clear_body.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/test/battle/ability/clear_body.c b/test/battle/ability/clear_body.c index f265c4ea5c..1117bac3d3 100644 --- a/test/battle/ability/clear_body.c +++ b/test/battle/ability/clear_body.c @@ -53,6 +53,7 @@ SINGLE_BATTLE_TEST("Clear Body prevents stat stage reduction from moves") TURN { MOVE(player, move); } } SCENE { NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, move, player); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); } ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); @@ -88,6 +89,7 @@ SINGLE_BATTLE_TEST("Clear Body doesn't prevent stat stage reduction from moves u } WHEN { TURN { MOVE(opponent, MOVE_SUPERPOWER); } } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SUPERPOWER, opponent); NONE_OF { ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); MESSAGE("Foe Beldum's Clear Body prevents stat loss!"); @@ -136,6 +138,7 @@ SINGLE_BATTLE_TEST("Mold Breaker, Teravolt, and Turboblaze ignore Clear Body") } WHEN { TURN { MOVE(player, move); } } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, player); NONE_OF { ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); MESSAGE("Foe Beldum's Clear Body prevents stat loss!"); @@ -175,9 +178,10 @@ SINGLE_BATTLE_TEST("Clear Body doesn't prevent Speed reduction from paralysis") TURN { MOVE(player, MOVE_THUNDER_WAVE); } TURN { MOVE(player, MOVE_THUNDER_WAVE); } } SCENE { - NOT ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); MESSAGE("Foe Beldum used Celebrate!"); MESSAGE("Wobbuffet used Thunder Wave!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_THUNDER_WAVE, player); + NOT ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); MESSAGE("Wobbuffet used Thunder Wave!"); ONE_OF { MESSAGE("Foe Beldum used Celebrate!"); @@ -217,8 +221,9 @@ SINGLE_BATTLE_TEST("Clear Body doesn't prevent receiving negative stat changes f TURN { MOVE(player, MOVE_SCARY_FACE); MOVE(opponent, MOVE_BATON_PASS); SEND_OUT(opponent, 1); } TURN { MOVE(player, MOVE_SCARY_FACE); } } SCENE { - NOT ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); MESSAGE("Wobbuffet used Scary Face!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCARY_FACE, player); + ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); MESSAGE("Foe Beldum used Celebrate!"); } } @@ -237,11 +242,14 @@ SINGLE_BATTLE_TEST("Clear Body doesn't prevent Topsy-Turvy") TURN { MOVE(player, MOVE_TOPSY_TURVY); } TURN { MOVE(player, MOVE_SCARY_FACE); } } SCENE { - NOT ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); MESSAGE("Wobbuffet used Topsy-Turvy!"); + NOT ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TOPSY_TURVY, player); MESSAGE("Foe Beldum used Celebrate!"); MESSAGE("Foe Beldum used Celebrate!"); MESSAGE("Wobbuffet used Scary Face!"); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_SCARY_FACE, player); + ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); } } @@ -257,11 +265,13 @@ SINGLE_BATTLE_TEST("Clear Body doesn't prevent Spectral Thief from resetting pos TURN{ MOVE(player, MOVE_SPECTRAL_THIEF); } TURN{ } } SCENE { - NOT ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); MESSAGE("Foe Metang used Agility!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_AGILITY, opponent); MESSAGE("Wobbuffet used Celebrate!"); MESSAGE("Foe Metang used Celebrate!"); MESSAGE("Wobbuffet used SpectrlThief!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SPECTRAL_THIEF, player); + NOT ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); MESSAGE("Wobbuffet used Celebrate!"); MESSAGE("Foe Metang used Celebrate!"); }