From 03915524c5912c1c1d4e68406dcac01252ab5291 Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Mon, 20 Feb 2023 12:42:06 +0100 Subject: [PATCH 1/7] Fix switch-in abilities activating on empty field --- include/battle.h | 1 + include/battle_script_commands.h | 1 + src/battle_script_commands.c | 72 +++++++++++++++++++++++--------- src/battle_util.c | 17 +++++++- src/data/trainer_parties.h | 12 +++--- test/ability_intimidate.c | 50 ++++++++++++++++++++-- test/test_runner.c | 2 +- 7 files changed, 124 insertions(+), 31 deletions(-) diff --git a/include/battle.h b/include/battle.h index 8be922384f..46c9340823 100644 --- a/include/battle.h +++ b/include/battle.h @@ -644,6 +644,7 @@ struct BattleStruct struct StolenItem itemStolen[PARTY_SIZE]; // Player's team that had items stolen (two bytes per party member) u8 blunderPolicy:1; // should blunder policy activate u8 swapDamageCategory:1; // Photon Geyser, Shell Side Arm, Light That Burns the Sky + u8 switchInAbilityPostponed:4; // To not activate against an empty field, each bit for battler u8 ballSpriteIds[2]; // item gfx, window gfx u8 stickyWebUser; u8 appearedInBattle; // Bitfield to track which Pokemon appeared in battle. Used for Burmy's form change diff --git a/include/battle_script_commands.h b/include/battle_script_commands.h index 60fd9b156b..c3d6831e95 100644 --- a/include/battle_script_commands.h +++ b/include/battle_script_commands.h @@ -44,6 +44,7 @@ u16 GetSecretPowerMoveEffect(void); void StealTargetItem(u8 battlerStealer, u8 battlerItem); u8 GetCatchingBattler(void); u32 GetHighestStatId(u32 battlerId); +bool32 DoSwitchInAbilitiesItems(u32 battlerId); extern void (* const gBattleScriptingCommandsTable[])(void); extern const u8 gBattlePalaceNatureToMoveGroupLikelihood[NUM_NATURES][4]; diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 8b8d4f1e94..9555111b4d 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -6900,6 +6900,35 @@ static void SetDmgHazardsBattlescript(u8 battlerId, u8 multistringId) gBattlescriptCurrInstr = BattleScript_DmgHazardsOnFaintedBattler; } +bool32 DoSwitchInAbilitiesItems(u32 battlerId) +{ + return (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, battlerId, 0, 0, 0) + || (gBattleWeather & B_WEATHER_ANY && WEATHER_HAS_EFFECT && AbilityBattleEffects(ABILITYEFFECT_ON_WEATHER, battlerId, 0, 0, 0)) + || (gFieldStatuses & STATUS_FIELD_TERRAIN_ANY && AbilityBattleEffects(ABILITYEFFECT_ON_TERRAIN, battlerId, 0, 0, 0)) + || ItemBattleEffects(ITEMEFFECT_ON_SWITCH_IN, battlerId, FALSE) + || AbilityBattleEffects(ABILITYEFFECT_TRACE2, 0, 0, 0, 0)); +} + +bool32 ShouldPostponeSwitchInAbilities(u32 battlerId) +{ + bool32 aliveOpposing1 = IsBattlerAlive(BATTLE_OPPOSITE(battlerId)); + bool32 aliveOpposing2 = IsBattlerAlive(BATTLE_PARTNER(BATTLE_OPPOSITE(battlerId))); + // No pokemon on opposing side - postopone. + if (!aliveOpposing1 && !aliveOpposing2) + return TRUE; + + // Checks for double battle, so abilities like Intimidate wait until all battlers are switched-in before activating. + if (IsDoubleBattle()) + { + if (aliveOpposing1 && !aliveOpposing2 && !HasNoMonsToSwitch(BATTLE_OPPOSITE(battlerId), PARTY_SIZE, PARTY_SIZE)) + return TRUE; + if (!aliveOpposing1 && aliveOpposing2 && !HasNoMonsToSwitch(BATTLE_PARTNER(BATTLE_OPPOSITE(battlerId)), PARTY_SIZE, PARTY_SIZE)) + return TRUE; + } + + return FALSE; +} + static void Cmd_switchineffects(void) { CMD_ARGS(u8 battler); @@ -7016,12 +7045,17 @@ static void Cmd_switchineffects(void) gDisableStructs[gActiveBattler].truantSwitchInHack = 0; - if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, gActiveBattler, 0, 0, 0) - || (gBattleWeather & B_WEATHER_ANY && WEATHER_HAS_EFFECT && AbilityBattleEffects(ABILITYEFFECT_ON_WEATHER, gActiveBattler, 0, 0, 0)) - || (gFieldStatuses & STATUS_FIELD_TERRAIN_ANY && AbilityBattleEffects(ABILITYEFFECT_ON_TERRAIN, gActiveBattler, 0, 0, 0)) - || ItemBattleEffects(ITEMEFFECT_ON_SWITCH_IN, gActiveBattler, FALSE) - || AbilityBattleEffects(ABILITYEFFECT_TRACE2, 0, 0, 0, 0)) - return; + // Don't activate switch-in abilities if the opposing field is empty. + // This could happen when a mon uses explosion and causes everyone to faint. + if (ShouldPostponeSwitchInAbilities(gActiveBattler) || gBattleStruct->switchInAbilityPostponed) + { + gBattleStruct->switchInAbilityPostponed |= gBitTable[gActiveBattler]; + } + else + { + if (DoSwitchInAbilitiesItems(gActiveBattler)) + return; + } gSideStatuses[GetBattlerSide(gActiveBattler)] &= ~(SIDE_STATUS_SPIKES_DAMAGED | SIDE_STATUS_TOXIC_SPIKES_DAMAGED | SIDE_STATUS_STEALTH_ROCK_DAMAGED | SIDE_STATUS_STICKY_WEB_DAMAGED); @@ -11016,21 +11050,21 @@ static void Cmd_various(void) return; } case VARIOUS_JUMP_IF_NO_VALID_TARGETS: - { - VARIOUS_ARGS(const u8 *jumpInstr); - u32 count = 0; + { + VARIOUS_ARGS(const u8 *jumpInstr); + u32 count = 0; - for (i = 0; i < gBattlersCount; i++) - { - if (GetBattlerSide(i) != GetBattlerSide(gBattlerAttacker) && IsBattlerAlive(i)) - count++; - } - if (count == 0) - gBattlescriptCurrInstr = cmd->jumpInstr; - else - gBattlescriptCurrInstr = cmd->nextInstr; - return; + for (i = 0; i < gBattlersCount; i++) + { + if (GetBattlerSide(i) != GetBattlerSide(gBattlerAttacker) && IsBattlerAlive(i)) + count++; } + if (count == 0) + gBattlescriptCurrInstr = cmd->jumpInstr; + else + gBattlescriptCurrInstr = cmd->nextInstr; + return; + } case VARIOUS_JUMP_IF_EMERGENCY_EXITED: { VARIOUS_ARGS(const u8 *jumpInstr); diff --git a/src/battle_util.c b/src/battle_util.c index 25ba83093c..1855754110 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -3301,7 +3301,7 @@ bool8 HandleWishPerishSongOnTurnEnd(void) return FALSE; } -#define FAINTED_ACTIONS_MAX_CASE 7 +#define FAINTED_ACTIONS_MAX_CASE 8 bool8 HandleFaintedMonActions(void) { @@ -3386,7 +3386,19 @@ bool8 HandleFaintedMonActions(void) else gBattleStruct->faintedActionsState = 4; break; - case 6: + case 6: // All battlers switch-in abilities happen here to prevent them happening against an empty field. + for (i = 0; i < gBattlersCount; i++) + { + if (gBattleStruct->switchInAbilityPostponed & gBitTable[i]) + { + if (DoSwitchInAbilitiesItems(i)) + return TRUE; + gBattleStruct->switchInAbilityPostponed &= ~(gBitTable[i]); + } + } + gBattleStruct->faintedActionsState++; + break; + case 7: if (ItemBattleEffects(ITEMEFFECT_NORMAL, 0, TRUE)) return TRUE; gBattleStruct->faintedActionsState++; @@ -4749,6 +4761,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move case ABILITY_INTIMIDATE: if (!gSpecialStatuses[battler].switchInAbilityDone) { + gBattlerAttacker = battler; gSpecialStatuses[battler].switchInAbilityDone = TRUE; SET_STATCHANGER(STAT_ATK, 1, TRUE); BattleScriptPushCursorAndCallback(BattleScript_IntimidateActivates); diff --git a/src/data/trainer_parties.h b/src/data/trainer_parties.h index 1759120b7f..de2d1e8977 100644 --- a/src/data/trainer_parties.h +++ b/src/data/trainer_parties.h @@ -400,17 +400,17 @@ static const struct TrainerMonNoItemDefaultMoves sParty_Rose1[] = { { .iv = 0, .lvl = 14, - .species = SPECIES_ROSELIA, + .species = SPECIES_PORYGON, }, { .iv = 0, .lvl = 14, - .species = SPECIES_SHROOMISH, + .species = SPECIES_PORYGON, }, { .iv = 0, .lvl = 14, - .species = SPECIES_ROSELIA, + .species = SPECIES_PORYGON, } }; @@ -9631,17 +9631,17 @@ static const struct TrainerMonNoItemDefaultMoves sParty_Deandre[] = { { .iv = 0, .lvl = 14, - .species = SPECIES_ZIGZAGOON, + .species = SPECIES_PORYGON, }, { .iv = 0, .lvl = 14, - .species = SPECIES_ARON, + .species = SPECIES_PORYGON, }, { .iv = 0, .lvl = 14, - .species = SPECIES_ELECTRIKE, + .species = SPECIES_PORYGON, } }; diff --git a/test/ability_intimidate.c b/test/ability_intimidate.c index 450ca64029..a0f48776ca 100644 --- a/test/ability_intimidate.c +++ b/test/ability_intimidate.c @@ -30,13 +30,12 @@ SINGLE_BATTLE_TEST("Intimidate (opponent) lowers player's attack after switch ou SINGLE_BATTLE_TEST("Intimidate (opponent) lowers player's attack after KO", s16 damage) { u32 ability; - KNOWN_FAILING; PARAMETRIZE { ability = ABILITY_INTIMIDATE; } PARAMETRIZE { ability = ABILITY_RECKLESS; } GIVEN { - PLAYER(SPECIES_WOBBUFFET) { Speed(2); }; + PLAYER(SPECIES_WOBBUFFET) { Speed(2); Attack(120) ; }; OPPONENT(SPECIES_WOBBUFFET) { HP(1); Speed(1); }; - OPPONENT(SPECIES_STARAPTOR) { Ability(ABILITY_INTIMIDATE); Speed(1); }; + OPPONENT(SPECIES_STARAPTOR) { Ability(ability); Speed(1); }; } WHEN { TURN { MOVE(player, MOVE_TACKLE); SEND_OUT(opponent, 1); } TURN { MOVE(player, MOVE_TACKLE); } @@ -48,3 +47,48 @@ SINGLE_BATTLE_TEST("Intimidate (opponent) lowers player's attack after KO", s16 EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage); } } + +DOUBLE_BATTLE_TEST("Intimidate doesn't activate on an empty field in a double battle") +{ + GIVEN { + ASSUME(gBattleMoves[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + PLAYER(SPECIES_WOBBUFFET) { }; + PLAYER(SPECIES_WOBBUFFET) { HP(1); }; + PLAYER(SPECIES_STARAVIA) { Ability(ABILITY_INTIMIDATE); }; + PLAYER(SPECIES_ABRA); + OPPONENT(SPECIES_WOBBUFFET) { HP(1); }; + OPPONENT(SPECIES_WOBBUFFET) { HP(1); }; + OPPONENT(SPECIES_STARAPTOR) { Ability(ABILITY_INTIMIDATE); }; + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(playerLeft, MOVE_EXPLOSION); SEND_OUT(playerLeft, 2); SEND_OUT(opponentLeft, 2); SEND_OUT(playerRight, 3); SEND_OUT(opponentRight, 3); } + TURN { MOVE(playerLeft, MOVE_CELEBRATE);} + } SCENE { + HP_BAR(playerLeft, hp: 0); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, playerLeft); + // Leaving these messages as they're not that important to the test, to not exceed MAX_QUEUED_EVENTS. + /* + MESSAGE("Foe Wobbuffet fainted!"); + MESSAGE("Wobbuffet fainted!"); + MESSAGE("Foe Wobbuffet fainted!"); + MESSAGE("Wobbuffet fainted!"); + */ + + MESSAGE("Go! Staravia!"); + MESSAGE("2 sent out Staraptor!"); + MESSAGE("Go! Abra!"); + MESSAGE("2 sent out Wynaut!"); + + ABILITY_POPUP(playerLeft, ABILITY_INTIMIDATE); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft); + MESSAGE("Staravia's Intimidate cuts Foe Staraptor's ATTACK!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight); + MESSAGE("Staravia's Intimidate cuts Foe Wynaut's ATTACK!"); + + ABILITY_POPUP(opponentLeft, ABILITY_INTIMIDATE); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft); + MESSAGE("Foe Staraptor's Intimidate cuts Staravia's ATTACK!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight); + MESSAGE("Foe Staraptor's Intimidate cuts Abra's ATTACK!"); + } +} diff --git a/test/test_runner.c b/test/test_runner.c index 3cb1f7c213..c4befb35f2 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -7,7 +7,7 @@ #include "test.h" #include "test_runner.h" -#define TIMEOUT_SECONDS 30 +#define TIMEOUT_SECONDS 49 void CB2_TestRunner(void); From a8c0e1ebeb13de3bb037942d21b8a8c151b90d6c Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Mon, 20 Feb 2023 13:15:08 +0100 Subject: [PATCH 2/7] fix intimidate --- src/data/trainer_parties.h | 12 ++++++------ test/ability_download.c | 29 +++++++++++++++++++++++++++++ test/ability_intimidate.c | 11 ++++++++++- 3 files changed, 45 insertions(+), 7 deletions(-) create mode 100644 test/ability_download.c diff --git a/src/data/trainer_parties.h b/src/data/trainer_parties.h index de2d1e8977..1759120b7f 100644 --- a/src/data/trainer_parties.h +++ b/src/data/trainer_parties.h @@ -400,17 +400,17 @@ static const struct TrainerMonNoItemDefaultMoves sParty_Rose1[] = { { .iv = 0, .lvl = 14, - .species = SPECIES_PORYGON, + .species = SPECIES_ROSELIA, }, { .iv = 0, .lvl = 14, - .species = SPECIES_PORYGON, + .species = SPECIES_SHROOMISH, }, { .iv = 0, .lvl = 14, - .species = SPECIES_PORYGON, + .species = SPECIES_ROSELIA, } }; @@ -9631,17 +9631,17 @@ static const struct TrainerMonNoItemDefaultMoves sParty_Deandre[] = { { .iv = 0, .lvl = 14, - .species = SPECIES_PORYGON, + .species = SPECIES_ZIGZAGOON, }, { .iv = 0, .lvl = 14, - .species = SPECIES_PORYGON, + .species = SPECIES_ARON, }, { .iv = 0, .lvl = 14, - .species = SPECIES_PORYGON, + .species = SPECIES_ELECTRIKE, } }; diff --git a/test/ability_download.c b/test/ability_download.c new file mode 100644 index 0000000000..8380487cee --- /dev/null +++ b/test/ability_download.c @@ -0,0 +1,29 @@ +#include "global.h" +#include "test_battle.h" + +ASSUMPTIONS +{ + ASSUME(gBattleMoves[MOVE_TACKLE].split == SPLIT_PHYSICAL); +} + +SINGLE_BATTLE_TEST("Download raises Attack if enemy has greater Atk than Sp.Atk", s16 damage) +{ + u32 ability; + PARAMETRIZE { ability = ABILITY_TRACE; } + PARAMETRIZE { ability = ABILITY_DOWNLOAD; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_PORYGON) { Ability(ability); }; + } WHEN { + TURN { MOVE(opponent, MOVE_TACKLE); } + } SCENE { + if (ability == ABILITY_DOWNLOAD) + { + ABILITY_POPUP(opponent, ABILITY_DOWNLOAD); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + } + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage); + } +} diff --git a/test/ability_intimidate.c b/test/ability_intimidate.c index a0f48776ca..29acfe6f93 100644 --- a/test/ability_intimidate.c +++ b/test/ability_intimidate.c @@ -20,7 +20,11 @@ SINGLE_BATTLE_TEST("Intimidate (opponent) lowers player's attack after switch ou TURN { MOVE(player, MOVE_TACKLE); } } SCENE { if (ability == ABILITY_INTIMIDATE) + { ABILITY_POPUP(opponent, ABILITY_INTIMIDATE); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Foe Staraptor's Intimidate cuts Wobbuffet's ATTACK!"); + } HP_BAR(opponent, captureDamage: &results[i].damage); } FINALLY { EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage); @@ -33,15 +37,20 @@ SINGLE_BATTLE_TEST("Intimidate (opponent) lowers player's attack after KO", s16 PARAMETRIZE { ability = ABILITY_INTIMIDATE; } PARAMETRIZE { ability = ABILITY_RECKLESS; } GIVEN { - PLAYER(SPECIES_WOBBUFFET) { Speed(2); Attack(120) ; }; + PLAYER(SPECIES_WOBBUFFET) { Speed(2); }; OPPONENT(SPECIES_WOBBUFFET) { HP(1); Speed(1); }; OPPONENT(SPECIES_STARAPTOR) { Ability(ability); Speed(1); }; } WHEN { TURN { MOVE(player, MOVE_TACKLE); SEND_OUT(opponent, 1); } TURN { MOVE(player, MOVE_TACKLE); } } SCENE { + HP_BAR(opponent); if (ability == ABILITY_INTIMIDATE) + { ABILITY_POPUP(opponent, ABILITY_INTIMIDATE); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Foe Staraptor's Intimidate cuts Wobbuffet's ATTACK!"); + } HP_BAR(opponent, captureDamage: &results[i].damage); } FINALLY { EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage); From a6f6c205c9fce128b76bcd56c03317c490ee8456 Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Mon, 20 Feb 2023 15:41:22 +0100 Subject: [PATCH 3/7] add tests for download --- test/ability_download.c | 72 +++++++++++++++++++++++++++++++++++++-- test/ability_intimidate.c | 8 +---- 2 files changed, 70 insertions(+), 10 deletions(-) diff --git a/test/ability_download.c b/test/ability_download.c index 8380487cee..77d090a306 100644 --- a/test/ability_download.c +++ b/test/ability_download.c @@ -4,16 +4,17 @@ ASSUMPTIONS { ASSUME(gBattleMoves[MOVE_TACKLE].split == SPLIT_PHYSICAL); + ASSUME(gBattleMoves[MOVE_TRI_ATTACK].split == SPLIT_PHYSICAL); } -SINGLE_BATTLE_TEST("Download raises Attack if enemy has greater Atk than Sp.Atk", s16 damage) +SINGLE_BATTLE_TEST("Download raises Attack if player has lower Def than Sp.Def", s16 damage) { u32 ability; PARAMETRIZE { ability = ABILITY_TRACE; } PARAMETRIZE { ability = ABILITY_DOWNLOAD; } GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_PORYGON) { Ability(ability); }; + PLAYER(SPECIES_WOBBUFFET) {Defense(100); SpDefense(200); }; + OPPONENT(SPECIES_PORYGON) { Ability(ability); Attack(100); }; } WHEN { TURN { MOVE(opponent, MOVE_TACKLE); } } SCENE { @@ -21,9 +22,74 @@ SINGLE_BATTLE_TEST("Download raises Attack if enemy has greater Atk than Sp.Atk" { ABILITY_POPUP(opponent, ABILITY_DOWNLOAD); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + MESSAGE("Foe Porygon's Download raised its attack!"); + } + HP_BAR(player, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Download raises Sp.Attack if enemy has lower Sp.Def than Def", s16 damage) +{ + u32 ability; + PARAMETRIZE { ability = ABILITY_TRACE; } + PARAMETRIZE { ability = ABILITY_DOWNLOAD; } + GIVEN { + PLAYER(SPECIES_PORYGON) { Ability(ability); SpAttack(100); }; + OPPONENT(SPECIES_WOBBUFFET) {Defense(200); SpDefense(100); }; + } WHEN { + TURN { MOVE(player, MOVE_TRI_ATTACK); } + } SCENE { + if (ability == ABILITY_DOWNLOAD) + { + ABILITY_POPUP(player, ABILITY_DOWNLOAD); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Porygon's Download raised its sp. attack!"); } HP_BAR(opponent, captureDamage: &results[i].damage); } FINALLY { EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage); } } + +SINGLE_BATTLE_TEST("Download doesn't activate if target hasn't been sent out yet", s16 damagePhysical, s16 damageSpecial) +{ + u32 ability; + PARAMETRIZE { ability = ABILITY_TRACE; } + PARAMETRIZE { ability = ABILITY_DOWNLOAD; } + GIVEN { + ASSUME(gBattleMoves[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + PLAYER(SPECIES_WOBBUFFET) { Speed(100); }; + PLAYER(SPECIES_PORYGON) { Ability(ability); Defense(400); SpDefense(300); Speed(300); Attack(100); }; + OPPONENT(SPECIES_WOBBUFFET) { HP(1); Speed(100); }; + OPPONENT(SPECIES_PORYGON2) { Ability(ability); Defense(100); SpDefense(200); Speed(200); }; + } WHEN { + TURN { MOVE(player, MOVE_EXPLOSION); SEND_OUT(player, 1); SEND_OUT(opponent, 1); } + TURN { MOVE(player, MOVE_TACKLE); MOVE(opponent, MOVE_TRI_ATTACK);} + } SCENE { + HP_BAR(player, hp: 0); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, player); + // Everyone faints. + + MESSAGE("Go! Porygon!"); + MESSAGE("2 sent out Porygon2!"); + + if (ability == ABILITY_DOWNLOAD) + { + ABILITY_POPUP(player, ABILITY_DOWNLOAD); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Porygon's Download raised its attack!"); + ABILITY_POPUP(opponent, ABILITY_DOWNLOAD); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + MESSAGE("Foe Porygon2's Download raised its sp. attack!"); + } + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player); + HP_BAR(opponent, captureDamage: &results[i].damagePhysical); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TRI_ATTACK, opponent); + HP_BAR(player, captureDamage: &results[i].damageSpecial); + } FINALLY { + EXPECT_MUL_EQ(results[0].damagePhysical, Q_4_12(1.5), results[1].damagePhysical); + EXPECT_MUL_EQ(results[0].damageSpecial, Q_4_12(1.5), results[1].damageSpecial); + } +} diff --git a/test/ability_intimidate.c b/test/ability_intimidate.c index 29acfe6f93..f978b80ab0 100644 --- a/test/ability_intimidate.c +++ b/test/ability_intimidate.c @@ -75,13 +75,7 @@ DOUBLE_BATTLE_TEST("Intimidate doesn't activate on an empty field in a double ba } SCENE { HP_BAR(playerLeft, hp: 0); ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, playerLeft); - // Leaving these messages as they're not that important to the test, to not exceed MAX_QUEUED_EVENTS. - /* - MESSAGE("Foe Wobbuffet fainted!"); - MESSAGE("Wobbuffet fainted!"); - MESSAGE("Foe Wobbuffet fainted!"); - MESSAGE("Wobbuffet fainted!"); - */ + // Everyone faints. MESSAGE("Go! Staravia!"); MESSAGE("2 sent out Staraptor!"); From 7d23d5433b68e104621073021afae493f632511f Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Mon, 20 Feb 2023 16:38:37 +0100 Subject: [PATCH 4/7] try fix tests failing --- test/test_runner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_runner.c b/test/test_runner.c index c4befb35f2..f64dffacb2 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -7,7 +7,7 @@ #include "test.h" #include "test_runner.h" -#define TIMEOUT_SECONDS 49 +#define TIMEOUT_SECONDS 55 void CB2_TestRunner(void); From 1e2eeb4d797aaba2324dfbaa41a283fa6ac9fa86 Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Tue, 21 Feb 2023 16:26:49 +0100 Subject: [PATCH 5/7] fix wrong assumption --- test/ability_download.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ability_download.c b/test/ability_download.c index 77d090a306..132c0eb5ba 100644 --- a/test/ability_download.c +++ b/test/ability_download.c @@ -4,7 +4,7 @@ ASSUMPTIONS { ASSUME(gBattleMoves[MOVE_TACKLE].split == SPLIT_PHYSICAL); - ASSUME(gBattleMoves[MOVE_TRI_ATTACK].split == SPLIT_PHYSICAL); + ASSUME(gBattleMoves[MOVE_TRI_ATTACK].split == SPLIT_SPECIAL); } SINGLE_BATTLE_TEST("Download raises Attack if player has lower Def than Sp.Def", s16 damage) From bca47a0891a7e69781425cb7b30d3573dee88aeb Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Wed, 22 Feb 2023 09:17:23 +0100 Subject: [PATCH 6/7] Update src/battle_script_commands.c Co-authored-by: LOuroboros --- src/battle_script_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index ce9ea50f70..344c5091bb 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -6914,7 +6914,7 @@ bool32 ShouldPostponeSwitchInAbilities(u32 battlerId) { bool32 aliveOpposing1 = IsBattlerAlive(BATTLE_OPPOSITE(battlerId)); bool32 aliveOpposing2 = IsBattlerAlive(BATTLE_PARTNER(BATTLE_OPPOSITE(battlerId))); - // No pokemon on opposing side - postopone. + // No pokemon on opposing side - postpone. if (!aliveOpposing1 && !aliveOpposing2) return TRUE; From 31138455ded2fd6d711777b4ee19cadd5245e1b2 Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Wed, 22 Feb 2023 09:28:12 +0100 Subject: [PATCH 7/7] remove unneeded VARIOUS_JUMP_IF_NO_VALID_TARGETS --- asm/macros/battle_script.inc | 5 ----- data/battle_scripts_1.s | 1 - include/constants/battle_script_commands.h | 7 +++---- src/battle_script_commands.c | 16 ---------------- 4 files changed, 3 insertions(+), 26 deletions(-) diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 7c94f06ffe..03a4d6222d 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -2049,11 +2049,6 @@ various \battler, VARIOUS_ACTIVATE_TERRAIN_CHANGE_ABILITIES .endm - .macro jumpifnovalidtargets jumpInstr:req - various BS_ATTACKER, VARIOUS_JUMP_IF_NO_VALID_TARGETS - .4byte \jumpInstr - .endm - @ helpful macros .macro setstatchanger stat:req, stages:req, down:req setbyte sSTATCHANGER, \stat | \stages << 3 | \down << 7 diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 239d221093..036d662e8e 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -8573,7 +8573,6 @@ BattleScript_TryAdrenalineOrbRet: return BattleScript_IntimidateActivates:: - jumpifnovalidtargets BattleScript_IntimidateEnd showabilitypopup BS_ATTACKER pause B_WAIT_TIME_LONG destroyabilitypopup diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 0b71c22db9..9699a29211 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -255,10 +255,9 @@ #define VARIOUS_TRY_WIND_RIDER_POWER 163 #define VARIOUS_ACTIVATE_WEATHER_CHANGE_ABILITIES 164 #define VARIOUS_ACTIVATE_TERRAIN_CHANGE_ABILITIES 165 -#define VARIOUS_JUMP_IF_NO_VALID_TARGETS 166 -#define VARIOUS_JUMP_IF_EMERGENCY_EXITED 167 -#define VARIOUS_STORE_HEALING_WISH 168 -#define VARIOUS_HIT_SWITCH_TARGET_FAILED 169 +#define VARIOUS_JUMP_IF_EMERGENCY_EXITED 166 +#define VARIOUS_STORE_HEALING_WISH 167 +#define VARIOUS_HIT_SWITCH_TARGET_FAILED 168 // Cmd_manipulatedamage #define DMG_CHANGE_SIGN 0 diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 344c5091bb..e0f0116ffd 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -11068,22 +11068,6 @@ static void Cmd_various(void) AbilityBattleEffects(ABILITYEFFECT_ON_TERRAIN, gActiveBattler, 0, 0, 0); return; } - case VARIOUS_JUMP_IF_NO_VALID_TARGETS: - { - VARIOUS_ARGS(const u8 *jumpInstr); - u32 count = 0; - - for (i = 0; i < gBattlersCount; i++) - { - if (GetBattlerSide(i) != GetBattlerSide(gBattlerAttacker) && IsBattlerAlive(i)) - count++; - } - if (count == 0) - gBattlescriptCurrInstr = cmd->jumpInstr; - else - gBattlescriptCurrInstr = cmd->nextInstr; - return; - } case VARIOUS_JUMP_IF_EMERGENCY_EXITED: { VARIOUS_ARGS(const u8 *jumpInstr);