From 5cceea312074e78fccaf6bf7fe0f4a5133aa18ed Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 28 Nov 2023 20:56:12 +0100 Subject: [PATCH 1/4] Gen 9 configs for Protean/Libero, Intrepid Sword and Dauntless Sword --- include/battle.h | 3 ++ include/config/battle.h | 3 ++ src/battle_script_commands.c | 3 ++ src/battle_util.c | 14 +++++--- test/battle/ability/dauntless_shield.c | 47 ++++++++++++++++++++++++++ test/battle/ability/intrepid_sword.c | 47 ++++++++++++++++++++++++++ test/battle/ability/protean.c | 34 +++++++++++++++++++ 7 files changed, 147 insertions(+), 4 deletions(-) create mode 100644 test/battle/ability/dauntless_shield.c create mode 100644 test/battle/ability/intrepid_sword.c create mode 100644 test/battle/ability/protean.c diff --git a/include/battle.h b/include/battle.h index 9d83e0d9f881..9943e79f4e3e 100644 --- a/include/battle.h +++ b/include/battle.h @@ -110,6 +110,7 @@ struct DisableStruct u8 steelSurgeDone:1; u8 weatherAbilityDone:1; u8 terrainAbilityDone:1; + u8 usedProteanLibero:1; }; struct ProtectStruct @@ -732,6 +733,8 @@ struct BattleStruct bool8 transformZeroToHero[PARTY_SIZE][NUM_BATTLE_SIDES]; u8 pledgeMove:1; bool8 isSkyBattle:1; + bool8 intrepidSwordBoost[PARTY_SIZE][NUM_BATTLE_SIDES]; + bool8 dauntlessShieldBoost[PARTY_SIZE][NUM_BATTLE_SIDES]; }; // The palaceFlags member of struct BattleStruct contains 1 flag per move to indicate which moves the AI should consider, diff --git a/include/config/battle.h b/include/config/battle.h index 503ce9328e74..9dcfebd82a42 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -130,6 +130,9 @@ #define B_TRANSISTOR_BOOST GEN_LATEST // In Gen9+, Transistor will only boost Electric-type moves by 1.3x as opposed to 1.5x. #define B_ILLUMINATE_EFFECT GEN_LATEST // In Gen9+, Illuminate prevents accuracy reductions and ignores the target's evasion. #define B_WEAK_ARMOR_SPEED GEN_LATEST // In Gen7+, Weak Armor raises Speed by 2 stages instead of 1 when hit by a physical move. +#define B_PROTEAN_LIBERO GEN_LATEST // In Gen7+, Weak Armor raises Speed by 2 stages instead of 1 when hit by a physical move. +#define B_INTREPID_SWORD GEN_LATEST // In Gen9+, Intrepid Sword raises Attack by one stage only once per Battle. +#define B_DAUNTLESS_SHIELD GEN_LATEST // In Gen9+, Dauntless Shield raises Defense by one stage only once per Battle. // Item settings #define B_HP_BERRIES GEN_LATEST // In Gen4+, berries which restore HP activate immediately after HP drops to half. In Gen3, the effect occurs at the end of the turn. diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 6d8769f747f7..6a71c99f8e57 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1246,6 +1246,7 @@ static bool32 TryAegiFormChange(void) bool32 ProteanTryChangeType(u32 battler, u32 ability, u32 move, u32 moveType) { if ((ability == ABILITY_PROTEAN || ability == ABILITY_LIBERO) + && !gDisableStructs[gBattlerAttacker].usedProteanLibero && (gBattleMons[battler].type1 != moveType || gBattleMons[battler].type2 != moveType || (gBattleMons[battler].type3 != moveType && gBattleMons[battler].type3 != TYPE_MYSTERY)) && move != MOVE_STRUGGLE) @@ -1326,6 +1327,8 @@ static void Cmd_attackcanceler(void) // Check Protean activation. if (ProteanTryChangeType(gBattlerAttacker, attackerAbility, gCurrentMove, moveType)) { + if (B_PROTEAN_LIBERO == GEN_9) + gDisableStructs[gBattlerAttacker].usedProteanLibero = TRUE; PREPARE_TYPE_BUFFER(gBattleTextBuff1, moveType); gBattlerAbility = gBattlerAttacker; BattleScriptPushCursor(); diff --git a/src/battle_util.c b/src/battle_util.c index 475b38c78b4b..5ec0ae579981 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -4706,20 +4706,26 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 } break; case ABILITY_INTREPID_SWORD: - if (!gSpecialStatuses[battler].switchInAbilityDone && CompareStat(battler, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN)) + if (!gSpecialStatuses[battler].switchInAbilityDone && CompareStat(battler, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN) + && !gBattleStruct->intrepidSwordBoost[gBattlerPartyIndexes[battler]][GetBattlerSide(battler)]) { gBattlerAttacker = battler; - gSpecialStatuses[battler].switchInAbilityDone = TRUE; + if (B_INTREPID_SWORD == GEN_9) + gSpecialStatuses[battler].switchInAbilityDone = TRUE; + gBattleStruct->intrepidSwordBoost[gBattlerPartyIndexes[battler]][GetBattlerSide(battler)] = TRUE; SET_STATCHANGER(STAT_ATK, 1, FALSE); BattleScriptPushCursorAndCallback(BattleScript_BattlerAbilityStatRaiseOnSwitchIn); effect++; } break; case ABILITY_DAUNTLESS_SHIELD: - if (!gSpecialStatuses[battler].switchInAbilityDone && CompareStat(battler, STAT_DEF, MAX_STAT_STAGE, CMP_LESS_THAN)) + if (!gSpecialStatuses[battler].switchInAbilityDone && CompareStat(battler, STAT_DEF, MAX_STAT_STAGE, CMP_LESS_THAN) + && !gBattleStruct->dauntlessShieldBoost[gBattlerPartyIndexes[battler]][GetBattlerSide(battler)]) { gBattlerAttacker = battler; - gSpecialStatuses[battler].switchInAbilityDone = TRUE; + if (B_DAUNTLESS_SHIELD == GEN_9) + gSpecialStatuses[battler].switchInAbilityDone = TRUE; + gBattleStruct->dauntlessShieldBoost[gBattlerPartyIndexes[battler]][GetBattlerSide(battler)] = TRUE; SET_STATCHANGER(STAT_DEF, 1, FALSE); BattleScriptPushCursorAndCallback(BattleScript_BattlerAbilityStatRaiseOnSwitchIn); effect++; diff --git a/test/battle/ability/dauntless_shield.c b/test/battle/ability/dauntless_shield.c new file mode 100644 index 000000000000..eb7b5c15cb18 --- /dev/null +++ b/test/battle/ability/dauntless_shield.c @@ -0,0 +1,47 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(P_GEN_8_POKEMON == TRUE); + ASSUME(B_PROTEAN_LIBERO == GEN_9); +} + +SINGLE_BATTLE_TEST("Dauntless Shield raises Attack by one stage") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_ZAMAZENTA) { Ability(ABILITY_DAUNTLESS_SHIELD); } + } WHEN { + TURN { } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_DAUNTLESS_SHIELD); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + MESSAGE("Foe Zamazenta's Dauntless Shield raised its Defense!"); + } THEN { + EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 1); + } +} + +SINGLE_BATTLE_TEST("Dauntless Shield raises Attack by one stage only once per battle") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_ZAMAZENTA) { Ability(ABILITY_DAUNTLESS_SHIELD); } + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { SWITCH(opponent, 1); } + TURN { SWITCH(opponent, 0); } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_DAUNTLESS_SHIELD); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + MESSAGE("Foe Zamazenta's Dauntless Shield raised its Defense!"); + NONE_OF { + ABILITY_POPUP(opponent, ABILITY_DAUNTLESS_SHIELD); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + MESSAGE("Foe Zamazenta's Dauntless Shield raised its Defense!"); + } + } THEN { + EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE); + } +} diff --git a/test/battle/ability/intrepid_sword.c b/test/battle/ability/intrepid_sword.c new file mode 100644 index 000000000000..88228bbe784a --- /dev/null +++ b/test/battle/ability/intrepid_sword.c @@ -0,0 +1,47 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(P_GEN_8_POKEMON == TRUE); + ASSUME(B_INTREPID_SWORD == GEN_9); +} + +SINGLE_BATTLE_TEST("Intrepid Sword raises Attack by one stage") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_ZACIAN) { Ability(ABILITY_INTREPID_SWORD); } + } WHEN { + TURN { } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_INTREPID_SWORD); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + MESSAGE("Foe Zacian's Intrepid Sword raised its Attack!"); + } THEN { + EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 1); + } +} + +SINGLE_BATTLE_TEST("Intrepid Sword raises Attack by one stage only once per battle") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_ZACIAN) { Ability(ABILITY_INTREPID_SWORD); } + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { SWITCH(opponent, 1); } + TURN { SWITCH(opponent, 0); } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_INTREPID_SWORD); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + MESSAGE("Foe Zacian's Intrepid Sword raised its Attack!"); + NONE_OF { + ABILITY_POPUP(opponent, ABILITY_INTREPID_SWORD); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + MESSAGE("Foe Zacian's Intrepid Sword raised its Attack!"); + } + } THEN { + EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE); + } +} diff --git a/test/battle/ability/protean.c b/test/battle/ability/protean.c new file mode 100644 index 000000000000..936c341f8992 --- /dev/null +++ b/test/battle/ability/protean.c @@ -0,0 +1,34 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(B_PROTEAN_LIBERO == GEN_9); +} + +SINGLE_BATTLE_TEST("Protean changes the type of the user only once per switch in") +{ + GIVEN { + PLAYER(SPECIES_REGIROCK); + OPPONENT(SPECIES_KECLEON) { Ability(ABILITY_PROTEAN); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_WATER_GUN); } + TURN { MOVE(opponent, MOVE_TACKLE); } + TURN { SWITCH(opponent, 1); } + TURN { SWITCH(opponent, 0); } + TURN { MOVE(opponent, MOVE_WATER_GUN); } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_PROTEAN); + MESSAGE("Foe Kecleon transformed into the Water type!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, opponent); + NONE_OF { + ABILITY_POPUP(opponent, ABILITY_PROTEAN); + MESSAGE("Foe Kecleon transformed into the Normal type!"); + } + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + ABILITY_POPUP(opponent, ABILITY_PROTEAN); + MESSAGE("Foe Kecleon transformed into the Water type!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, opponent); + } +} From 9fc4ca65d02a27a159d56aff6704600563a3b184 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 29 Nov 2023 17:04:22 +0100 Subject: [PATCH 2/4] use bitfield --- include/battle.h | 18 +++++----- include/config/battle.h | 3 ++ src/battle_script_commands.c | 4 ++- src/battle_util.c | 16 ++++----- test/battle/move_effect/protect.c | 55 ++++++++++++++++++++++++++++++- 5 files changed, 77 insertions(+), 19 deletions(-) diff --git a/include/battle.h b/include/battle.h index 9943e79f4e3e..c9c5b031315e 100644 --- a/include/battle.h +++ b/include/battle.h @@ -719,22 +719,22 @@ struct BattleStruct uq4_12_t supremeOverlordModifier[MAX_BATTLERS_COUNT]; u8 itemPartyIndex[MAX_BATTLERS_COUNT]; u8 itemMoveIndex[MAX_BATTLERS_COUNT]; - bool8 trainerSlideHalfHpMsgDone; + u8 trainerSlideHalfHpMsgDone:1; u8 trainerSlideFirstCriticalHitMsgState:2; u8 trainerSlideFirstSuperEffectiveHitMsgState:2; u8 trainerSlideFirstSTABMoveMsgState:2; u8 trainerSlidePlayerMonUnaffectedMsgState:2; - bool8 trainerSlideMegaEvolutionMsgDone; - bool8 trainerSlideZMoveMsgDone; - bool8 trainerSlideBeforeFirstTurnMsgDone; - bool8 trainerSlideDynamaxMsgDone; + u8 trainerSlideMegaEvolutionMsgDone:1; + u8 trainerSlideZMoveMsgDone:1; + u8 trainerSlideBeforeFirstTurnMsgDone:1; + u8 trainerSlideDynamaxMsgDone:1; u32 aiDelayTimer; // Counts number of frames AI takes to choose an action. u32 aiDelayFrames; // Number of frames it took to choose an action. - bool8 transformZeroToHero[PARTY_SIZE][NUM_BATTLE_SIDES]; + u8 transformZeroToHero[NUM_BATTLE_SIDES]; u8 pledgeMove:1; - bool8 isSkyBattle:1; - bool8 intrepidSwordBoost[PARTY_SIZE][NUM_BATTLE_SIDES]; - bool8 dauntlessShieldBoost[PARTY_SIZE][NUM_BATTLE_SIDES]; + u8 isSkyBattle:1; + u8 intrepidSwordBoost[NUM_BATTLE_SIDES]; + u8 dauntlessShieldBoost[NUM_BATTLE_SIDES]; }; // The palaceFlags member of struct BattleStruct contains 1 flag per move to indicate which moves the AI should consider, diff --git a/include/config/battle.h b/include/config/battle.h index 9dcfebd82a42..fba460a9b3dd 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -109,6 +109,9 @@ #define B_TRANSFORM_SHINY GEN_LATEST // In Gen4+, Transform will copy the shiny state of the opponent instead of maintaining its own shiny state. #define B_TRANSFORM_FORM_CHANGES GEN_LATEST // In Gen5+, Transformed Pokemon cannot change forms. +#define B_WIDE_GUARD GEN_LATEST // In Gen5 only, Quick Guard has a chance to fail if used consecutively. +#define B_QUICK_GUARD GEN_LATEST // In Gen5 only, Wide Guard has a chance to fail if used consecutively. + // Ability settings #define B_EXPANDED_ABILITY_NAMES TRUE // If TRUE, ability names are increased from 12 characters to 16 characters. #define B_ABILITY_WEATHER GEN_LATEST // In Gen6+, ability-induced weather lasts 5 turns. Before, it lasted until the battle ended or until it was changed by a move or a different weather-affecting ability. diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 6a71c99f8e57..17cd41dcd71b 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -10673,7 +10673,9 @@ static void Cmd_setprotectlike(void) if (gCurrentTurnActionNumber == (gBattlersCount - 1)) notLastTurn = FALSE; - if (sProtectSuccessRates[gDisableStructs[gBattlerAttacker].protectUses] >= Random() && notLastTurn) + if ((sProtectSuccessRates[gDisableStructs[gBattlerAttacker].protectUses] >= Random() && notLastTurn) + || (gCurrentMove == MOVE_WIDE_GUARD && B_WIDE_GUARD != GEN_5) + || (gCurrentMove == MOVE_QUICK_GUARD && B_QUICK_GUARD != GEN_5)) { if (!gBattleMoves[gCurrentMove].argument) // Protects one mon only. { diff --git a/src/battle_util.c b/src/battle_util.c index 5ec0ae579981..47b96d9b1145 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -4707,12 +4707,12 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 break; case ABILITY_INTREPID_SWORD: if (!gSpecialStatuses[battler].switchInAbilityDone && CompareStat(battler, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN) - && !gBattleStruct->intrepidSwordBoost[gBattlerPartyIndexes[battler]][GetBattlerSide(battler)]) + && !(gBattleStruct->intrepidSwordBoost[GetBattlerSide(battler)] & gBitTable[gBattlerPartyIndexes[battler]])) { gBattlerAttacker = battler; if (B_INTREPID_SWORD == GEN_9) - gSpecialStatuses[battler].switchInAbilityDone = TRUE; - gBattleStruct->intrepidSwordBoost[gBattlerPartyIndexes[battler]][GetBattlerSide(battler)] = TRUE; + gBattleStruct->intrepidSwordBoost[GetBattlerSide(battler)] |= gBitTable[gBattlerPartyIndexes[battler]]; + gSpecialStatuses[battler].switchInAbilityDone = TRUE; SET_STATCHANGER(STAT_ATK, 1, FALSE); BattleScriptPushCursorAndCallback(BattleScript_BattlerAbilityStatRaiseOnSwitchIn); effect++; @@ -4720,12 +4720,12 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 break; case ABILITY_DAUNTLESS_SHIELD: if (!gSpecialStatuses[battler].switchInAbilityDone && CompareStat(battler, STAT_DEF, MAX_STAT_STAGE, CMP_LESS_THAN) - && !gBattleStruct->dauntlessShieldBoost[gBattlerPartyIndexes[battler]][GetBattlerSide(battler)]) + && !(gBattleStruct->dauntlessShieldBoost[GetBattlerSide(battler)] & gBitTable[gBattlerPartyIndexes[battler]])) { gBattlerAttacker = battler; if (B_DAUNTLESS_SHIELD == GEN_9) - gSpecialStatuses[battler].switchInAbilityDone = TRUE; - gBattleStruct->dauntlessShieldBoost[gBattlerPartyIndexes[battler]][GetBattlerSide(battler)] = TRUE; + gBattleStruct->dauntlessShieldBoost[GetBattlerSide(battler)] |= gBitTable[gBattlerPartyIndexes[battler]]; + gSpecialStatuses[battler].switchInAbilityDone = TRUE; SET_STATCHANGER(STAT_DEF, 1, FALSE); BattleScriptPushCursorAndCallback(BattleScript_BattlerAbilityStatRaiseOnSwitchIn); effect++; @@ -4824,10 +4824,10 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 if (!gSpecialStatuses[battler].switchInAbilityDone && GetMonData(mon, MON_DATA_SPECIES) == SPECIES_PALAFIN_HERO - && !gBattleStruct->transformZeroToHero[gBattlerPartyIndexes[battler]][side]) + && !(gBattleStruct->transformZeroToHero[side] & gBitTable[gBattlerPartyIndexes[battler]])) { gSpecialStatuses[battler].switchInAbilityDone = TRUE; - gBattleStruct->transformZeroToHero[gBattlerPartyIndexes[battler]][side] = TRUE; + gBattleStruct->transformZeroToHero[side] |= gBitTable[gBattlerPartyIndexes[battler]]; BattleScriptPushCursorAndCallback(BattleScript_ZeroToHeroActivates); effect++; } diff --git a/test/battle/move_effect/protect.c b/test/battle/move_effect/protect.c index dd9f57b3562c..08c489d14656 100644 --- a/test/battle/move_effect/protect.c +++ b/test/battle/move_effect/protect.c @@ -295,7 +295,7 @@ DOUBLE_BATTLE_TEST("Wide Guard protects self and ally from multi-target moves") OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { MOVE(opponentLeft, MOVE_WIDE_GUARD); MOVE(playerLeft, move, target:opponentLeft); } + TURN { MOVE(opponentLeft, MOVE_WIDE_GUARD); MOVE(playerLeft, move, target: opponentLeft); } TURN {} } SCENE { MESSAGE("Foe Wobbuffet used Wide Guard!"); @@ -320,6 +320,34 @@ DOUBLE_BATTLE_TEST("Wide Guard protects self and ally from multi-target moves") } } +DOUBLE_BATTLE_TEST("Wide Guard can not fail on consecutive turns") +{ + u8 turns; + + PASSES_RANDOMLY(2, 2); + GIVEN { + ASSUME(gBattleMoves[MOVE_HYPER_VOICE].target == MOVE_TARGET_BOTH); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponentLeft, MOVE_WIDE_GUARD); MOVE(playerLeft, MOVE_HYPER_VOICE, target: opponentLeft); } + TURN { MOVE(opponentLeft, MOVE_WIDE_GUARD); MOVE(playerLeft, MOVE_HYPER_VOICE, target: opponentLeft); } + TURN {} + } SCENE { + for (turns = 0; turns < 2; turns++ ) { + MESSAGE("Foe Wobbuffet used Wide Guard!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_WIDE_GUARD, opponentLeft); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_HYPER_VOICE, playerLeft); + MESSAGE("Foe Wobbuffet protected itself!"); + NOT HP_BAR(opponentLeft); + MESSAGE("Foe Wobbuffet protected itself!"); + NOT HP_BAR(opponentRight); + } + } +} + DOUBLE_BATTLE_TEST("Quick Guard protects self and ally from priority moves") { u16 move = MOVE_NONE; @@ -355,6 +383,31 @@ DOUBLE_BATTLE_TEST("Quick Guard protects self and ally from priority moves") } } +DOUBLE_BATTLE_TEST("Quick Guard can not fail on consecutive turns") +{ + u8 turns; + + PASSES_RANDOMLY(2, 2); + GIVEN { + ASSUME(gBattleMoves[MOVE_QUICK_ATTACK].priority == 1); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponentLeft, MOVE_QUICK_GUARD); MOVE(playerLeft, MOVE_QUICK_ATTACK, target: opponentRight); } + TURN { MOVE(opponentLeft, MOVE_QUICK_GUARD); MOVE(playerLeft, MOVE_QUICK_ATTACK, target: opponentRight); } + } SCENE { + for (turns = 0; turns < 2; turns++ ) { + MESSAGE("Foe Wobbuffet used Quick Guard!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_QUICK_GUARD, opponentLeft); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_QUICK_ATTACK, playerLeft); + MESSAGE("Foe Wobbuffet protected itself!"); + NOT HP_BAR(opponentRight); + } + } +} + DOUBLE_BATTLE_TEST("Crafty Shield protects self and ally from status moves") { u16 move = MOVE_NONE; From 0ce8b42dd6cccd25fd6ef67bad21ee050bd0cfc7 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 3 Dec 2023 16:39:58 +0100 Subject: [PATCH 3/4] battler fix --- 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 17cd41dcd71b..0780cd6a9dd4 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1251,7 +1251,7 @@ bool32 ProteanTryChangeType(u32 battler, u32 ability, u32 move, u32 moveType) || (gBattleMons[battler].type3 != moveType && gBattleMons[battler].type3 != TYPE_MYSTERY)) && move != MOVE_STRUGGLE) { - SET_BATTLER_TYPE(gBattlerAttacker, moveType); + SET_BATTLER_TYPE(battler, moveType); return TRUE; } return FALSE; From fd663fd2a6a09c3e73fc32dba8a8a526a8f69a27 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 3 Dec 2023 21:34:48 +0100 Subject: [PATCH 4/4] fields --- include/battle.h | 10 +++++----- test/battle/move_effect/protect.c | 14 +++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/battle.h b/include/battle.h index c9c5b031315e..576d1fb79819 100644 --- a/include/battle.h +++ b/include/battle.h @@ -697,10 +697,10 @@ struct BattleStruct u16 changedSpecies[NUM_BATTLE_SIDES][PARTY_SIZE]; // For forms when multiple mons can change into the same pokemon. u8 quickClawBattlerId; struct LostItem itemLost[PARTY_SIZE]; // Player's team that had items consumed or 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 forcedSwitch:4; // For each battler u8 switchInAbilityPostponed:4; // To not activate against an empty field, each bit for battler + u8 blunderPolicy:1; // should blunder policy activate + u8 swapDamageCategory:1; // Photon Geyser, Shell Side Arm, Light That Burns the Sky u8 ballSpriteIds[2]; // item gfx, window gfx u8 appearedInBattle; // Bitfield to track which Pokemon appeared in battle. Used for Burmy's form change u8 skyDropTargets[MAX_BATTLERS_COUNT]; // For Sky Drop, to account for if multiple Pokemon use Sky Drop in a double battle. @@ -719,20 +719,20 @@ struct BattleStruct uq4_12_t supremeOverlordModifier[MAX_BATTLERS_COUNT]; u8 itemPartyIndex[MAX_BATTLERS_COUNT]; u8 itemMoveIndex[MAX_BATTLERS_COUNT]; - u8 trainerSlideHalfHpMsgDone:1; u8 trainerSlideFirstCriticalHitMsgState:2; u8 trainerSlideFirstSuperEffectiveHitMsgState:2; u8 trainerSlideFirstSTABMoveMsgState:2; u8 trainerSlidePlayerMonUnaffectedMsgState:2; + u8 trainerSlideHalfHpMsgDone:1; u8 trainerSlideMegaEvolutionMsgDone:1; u8 trainerSlideZMoveMsgDone:1; u8 trainerSlideBeforeFirstTurnMsgDone:1; u8 trainerSlideDynamaxMsgDone:1; + u8 pledgeMove:1; + u8 isSkyBattle:1; u32 aiDelayTimer; // Counts number of frames AI takes to choose an action. u32 aiDelayFrames; // Number of frames it took to choose an action. u8 transformZeroToHero[NUM_BATTLE_SIDES]; - u8 pledgeMove:1; - u8 isSkyBattle:1; u8 intrepidSwordBoost[NUM_BATTLE_SIDES]; u8 dauntlessShieldBoost[NUM_BATTLE_SIDES]; }; diff --git a/test/battle/move_effect/protect.c b/test/battle/move_effect/protect.c index 08c489d14656..c187d6d5739f 100644 --- a/test/battle/move_effect/protect.c +++ b/test/battle/move_effect/protect.c @@ -124,13 +124,13 @@ SINGLE_BATTLE_TEST("Spiky Shield does 1/8 dmg of max hp of attackers making cont u16 usedMove = MOVE_NONE; u16 hp = 400, maxHp = 400; - PARAMETRIZE { usedMove = MOVE_TACKLE; hp = 1;} - PARAMETRIZE { usedMove = MOVE_TACKLE;} - PARAMETRIZE { usedMove = MOVE_LEER;} - PARAMETRIZE { usedMove = MOVE_WATER_GUN;} + PARAMETRIZE { usedMove = MOVE_TACKLE; hp = 1; } + PARAMETRIZE { usedMove = MOVE_TACKLE; } + PARAMETRIZE { usedMove = MOVE_LEER; } + PARAMETRIZE { usedMove = MOVE_WATER_GUN; } GIVEN { - PLAYER(SPECIES_WOBBUFFET) {HP(hp); MaxHP(maxHp); } + PLAYER(SPECIES_WOBBUFFET) { HP(hp); MaxHP(maxHp); } PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -336,7 +336,7 @@ DOUBLE_BATTLE_TEST("Wide Guard can not fail on consecutive turns") TURN { MOVE(opponentLeft, MOVE_WIDE_GUARD); MOVE(playerLeft, MOVE_HYPER_VOICE, target: opponentLeft); } TURN {} } SCENE { - for (turns = 0; turns < 2; turns++ ) { + for (turns = 0; turns < 2; turns++) { MESSAGE("Foe Wobbuffet used Wide Guard!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_WIDE_GUARD, opponentLeft); NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_HYPER_VOICE, playerLeft); @@ -398,7 +398,7 @@ DOUBLE_BATTLE_TEST("Quick Guard can not fail on consecutive turns") TURN { MOVE(opponentLeft, MOVE_QUICK_GUARD); MOVE(playerLeft, MOVE_QUICK_ATTACK, target: opponentRight); } TURN { MOVE(opponentLeft, MOVE_QUICK_GUARD); MOVE(playerLeft, MOVE_QUICK_ATTACK, target: opponentRight); } } SCENE { - for (turns = 0; turns < 2; turns++ ) { + for (turns = 0; turns < 2; turns++) { MESSAGE("Foe Wobbuffet used Quick Guard!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_QUICK_GUARD, opponentLeft); NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_QUICK_ATTACK, playerLeft);