diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 4f831b427a..a1ee84a529 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1330,7 +1330,7 @@ .byte \stat .endm - .macro jumpifoppositegenders jumpInstr:req + .macro jumpifcaptivateaffected jumpInstr:req .byte 0xfc .4byte \jumpInstr .endm diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s index 4d78eea5c7..4f09416d79 100644 --- a/data/battle_anim_scripts.s +++ b/data/battle_anim_scripts.s @@ -12326,8 +12326,6 @@ gBattleAnimMove_NaturesMadness:: loadspritegfx ANIM_TAG_SPARKLE_2 @stars PinkStarsTemplate loadspritegfx ANIM_TAG_PINK_PETAL @pink PinkRingTemplate, PinkStarsTemplate loadspritegfx ANIM_TAG_ICE_CHUNK @blue green CrystalsTemplate - loadspritegfx ANIM_TAG_CIRCLE_OF_LIGHT @charge - loadspritegfx ANIM_TAG_TEAL_ALERT @charge particles monbg ANIM_ATTACKER setalpha 14, 8 delay 0x1 @@ -12374,6 +12372,8 @@ gBattleAnimMove_NaturesMadness:: createsprite gNaturesMadnessGrayRingTemplate, ANIM_ATTACKER, 40, 0x0, 0x0, 0x1, 0x0 playsewithpan SE_M_HEAL_BELL, SOUND_PAN_ATTACKER waitforvisualfinish + unloadspritegfx ANIM_TAG_ECLIPSING_ORB + loadspritegfx ANIM_TAG_SPARKLE_2 playsewithpan SE_M_EXPLOSION, SOUND_PAN_ATTACKER createsprite gNaturesMadnessPinkRingTemplate, ANIM_ATTACKER, 3, 0x0, 0x0, 0x1, 0x0, 0x1F, 0x8 createsprite gNaturesMadnessPinkStarsTemplate, ANIM_ATTACKER, 2, 0xa, 0xa, 0x19, 0x1 @@ -16168,7 +16168,6 @@ SandsearStormFireSpin: gBattleAnimMove_LunarBlessing:: loadspritegfx ANIM_TAG_BLUE_STAR loadspritegfx ANIM_TAG_MOON - loadspritegfx ANIM_TAG_SPARKLE_2 loadspritegfx ANIM_TAG_GUARD_RING loadspritegfx ANIM_TAG_SMALL_EMBER @Yellow colour for ring monbg ANIM_ATK_PARTNER @@ -31487,13 +31486,15 @@ gBattleAnimMove_BlackHoleEclipse:: delay 0x8 createsprite gBlackHoleEclipseHoleShrinkSpriteTemplate, ANIM_ATTACKER, 2, 0x0, 0x0, ANIM_TARGET, 0x0 waitforvisualfinish + unloadspritegfx ANIM_TAG_THIN_RING + unloadspritegfx ANIM_TAG_ICE_CHUNK loadspritegfx ANIM_TAG_SPARKLE_4 @detect createsprite gTargetTwinkleSpriteTemplate, ANIM_ATTACKER, 13, 0x0, 0x0, ANIM_TARGET @detect star delay 0x2 + unloadspritegfx ANIM_TAG_VERTICAL_HEX @red unloadspritegfx ANIM_TAG_SHADOW_BALL - unloadspritegfx ANIM_TAG_THIN_RING - unloadspritegfx ANIM_TAG_ICE_CHUNK unloadspritegfx ANIM_TAG_BLACK_BALL_2 + unloadspritegfx ANIM_TAG_FOCUS_ENERGY loadspritegfx ANIM_TAG_EXPLOSION_2 call BlackHoleEclipseExplosion createvisualtask AnimTask_BlendBattleAnimPal, 0xa, (F_PAL_BG | F_PAL_BATTLERS_2), 0x1, 0x0, 0x10, 0x7fff @ bg to white pal diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index d99330572c..d67b32faf2 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -2713,6 +2713,7 @@ BattleScript_EffectGravity:: attackstring ppreduce setgravity BattleScript_ButItFailed + savetarget attackanimation waitanimation BattleScript_EffectGravitySuccess:: @@ -2730,6 +2731,7 @@ BattleScript_GravityLoopDrop: BattleScript_GravityLoopEnd: moveendcase MOVEEND_TARGET_VISIBLE jumpifnexttargetvalid BattleScript_GravityLoop + restoretarget goto BattleScript_MoveEnd BattleScript_EffectRoost:: @@ -2743,11 +2745,13 @@ BattleScript_EffectRoost:: BattleScript_EffectCaptivate:: setstatchanger STAT_SPATK, 2, TRUE attackcanceler - jumpifsubstituteblocks BattleScript_FailedFromAtkString - jumpifoppositegenders BattleScript_CaptivateCheckAcc - goto BattleScript_FailedFromAtkString + attackstring + ppreduce + jumpifsubstituteblocks BattleScript_ButItFailed + jumpifcaptivateaffected BattleScript_CaptivateCheckAcc + goto BattleScript_ButItFailed BattleScript_CaptivateCheckAcc: - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE goto BattleScript_StatDownFromAttackString BattleScript_EffectHealBlock:: @@ -4179,6 +4183,7 @@ BattleScript_EffectPerishSong:: attackstring ppreduce trysetperishsong BattleScript_ButItFailed + savetarget attackanimation waitanimation printstring STRINGID_FAINTINTHREE @@ -4190,6 +4195,7 @@ BattleScript_PerishSongLoop:: BattleScript_PerishSongLoopIncrement:: addbyte gBattlerTarget, 1 jumpifbytenotequal gBattlerTarget, gBattlersCount, BattleScript_PerishSongLoop + restoretarget goto BattleScript_MoveEnd BattleScript_PerishSongBlocked:: @@ -5965,7 +5971,6 @@ BattleScript_RoarSuccessSwitch_Ret: swapattackerwithtarget @ continuation of RedCardActivates restoretarget restoreattacker - restoresavedmove setbyte sSWITCH_CASE, B_SWITCH_NORMAL return @@ -7057,7 +7062,6 @@ BattleScript_MoveUsedIsAsleep:: goto BattleScript_MoveEnd BattleScript_MoveUsedWokeUp:: - bicword gHitMarker, HITMARKER_WAKE_UP_CLEAR printfromtable gWokeUpStringIds waitmessage B_WAIT_TIME_LONG updatestatusicon BS_ATTACKER @@ -9491,7 +9495,6 @@ BattleScript_RedCardActivationNoSwitch:: removeitem BS_SCRIPTING restoretarget restoreattacker - restoresavedmove return BattleScript_RedCardActivates:: @@ -9514,6 +9517,7 @@ BattleScript_RedCardIngrainContinue: waitmessage B_WAIT_TIME_LONG removeitem BS_SCRIPTING restoretarget + restoreattacker return BattleScript_RedCardSuctionCups: printstring STRINGID_PKMNANCHORSITSELFWITH diff --git a/include/battle.h b/include/battle.h index c2e69682d6..2c4e0cfbb2 100644 --- a/include/battle.h +++ b/include/battle.h @@ -815,7 +815,6 @@ struct BattleStruct u8 usedMicleBerry; struct MessageStatus slideMessageStatus; u8 trainerSlideSpriteIds[MAX_BATTLERS_COUNT]; - u16 savedMove; // backup current move for mid-turn switching, e.g. Red Card u16 opponentMonCanTera:6; u16 opponentMonCanDynamax:6; u16 padding:4; diff --git a/include/constants/battle.h b/include/constants/battle.h index fc1127b8c8..305315d919 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -196,7 +196,7 @@ #define STATUS4_SYRUP_BOMB (1 << 5) #define STATUS4_GLAIVE_RUSH (1 << 6) -#define HITMARKER_WAKE_UP_CLEAR (1 << 4) // Cleared when waking up. Never set or checked. +#define HITMARKER_UNUSED_1 (1 << 4) #define HITMARKER_IGNORE_BIDE (1 << 5) #define HITMARKER_DESTINYBOND (1 << 6) #define HITMARKER_NO_ANIMATIONS (1 << 7) // set from battleSceneOff. Never changed during battle @@ -204,16 +204,16 @@ #define HITMARKER_NO_ATTACKSTRING (1 << 9) #define HITMARKER_ATTACKSTRING_PRINTED (1 << 10) #define HITMARKER_NO_PPDEDUCT (1 << 11) -#define HITMARKER_SWAP_ATTACKER_TARGET (1 << 12) +#define HITMARKER_UNUSED_2 (1 << 12) #define HITMARKER_STATUS_ABILITY_EFFECT (1 << 13) #define HITMARKER_SYNCHRONISE_EFFECT (1 << 14) #define HITMARKER_RUN (1 << 15) #define HITMARKER_IGNORE_DISGUISE (1 << 16) #define HITMARKER_DISABLE_ANIMATION (1 << 17) // disable animations during battle scripts, e.g. for Bug Bite -// 3 free spots because of change in handling of UNDERGROUND/UNDERWATER/ON AIR +#define HITMARKER_UNUSED_3 (1 << 18) #define HITMARKER_UNABLE_TO_USE_MOVE (1 << 19) #define HITMARKER_PASSIVE_DAMAGE (1 << 20) -#define HITMARKER_DISOBEDIENT_MOVE (1 << 21) +#define HITMARKER_UNUSED_4 (1 << 21) #define HITMARKER_PLAYER_FAINTED (1 << 22) #define HITMARKER_ALLOW_NO_PP (1 << 23) #define HITMARKER_GRUDGE (1 << 24) diff --git a/include/move.h b/include/move.h index ecf972da6e..b13878a58a 100644 --- a/include/move.h +++ b/include/move.h @@ -158,7 +158,7 @@ struct MoveInfo const u8 *battleAnimScript; }; -extern const struct MoveInfo gMovesInfo[]; +extern const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL]; extern const u8 gNotDoneYetDescription[]; extern const struct BattleMoveEffect gBattleMoveEffects[]; @@ -175,19 +175,19 @@ static inline const u8 *GetMoveName(u32 moveId) return gMovesInfo[SanitizeMoveId(moveId)].name; } -static inline const u8 *GetMoveDescription(u32 moveId) -{ - moveId = SanitizeMoveId(moveId); - if (gMovesInfo[moveId].effect == EFFECT_PLACEHOLDER) - return gNotDoneYetDescription; - return gMovesInfo[moveId].description; -} - static inline enum BattleMoveEffects GetMoveEffect(u32 moveId) { return gMovesInfo[SanitizeMoveId(moveId)].effect; } +static inline const u8 *GetMoveDescription(u32 moveId) +{ + moveId = SanitizeMoveId(moveId); + if (GetMoveEffect(moveId) == EFFECT_PLACEHOLDER) + return gNotDoneYetDescription; + return gMovesInfo[moveId].description; +} + static inline u32 GetMoveType(u32 moveId) { return gMovesInfo[SanitizeMoveId(moveId)].type; @@ -453,6 +453,11 @@ static inline bool32 IsMoveSketchBanned(u32 moveId) return gMovesInfo[SanitizeMoveId(moveId)].sketchBanned; } +static inline bool32 IsValidApprenticeMove(u32 moveId) +{ + return gMovesInfo[SanitizeMoveId(moveId)].validApprenticeMove; +} + static inline u32 GetMoveTwoTurnAttackStringId(u32 moveId) { return gMovesInfo[SanitizeMoveId(moveId)].argument.twoTurnAttack.stringId; @@ -550,12 +555,12 @@ static inline const u8 *GetMoveAnimationScript(u32 moveId) static inline const u8 *GetMoveBattleScript(u32 moveId) { moveId = SanitizeMoveId(moveId); - if (gBattleMoveEffects[gMovesInfo[moveId].effect].battleScript == NULL) + if (gBattleMoveEffects[GetMoveEffect(moveId)].battleScript == NULL) { DebugPrintfLevel(MGBA_LOG_WARN, "No effect for moveId=%u", moveId); return gBattleMoveEffects[EFFECT_PLACEHOLDER].battleScript; } - return gBattleMoveEffects[gMovesInfo[moveId].effect].battleScript; + return gBattleMoveEffects[GetMoveEffect(moveId)].battleScript; } #endif // GUARD_MOVES_H diff --git a/src/apprentice.c b/src/apprentice.c index 7769dde6e3..7dcca7b28b 100644 --- a/src/apprentice.c +++ b/src/apprentice.c @@ -411,7 +411,7 @@ static u16 GetRandomAlternateMove(u8 monId) if (TrySetMove(monId, moveId)) { - if (gMovesInfo[moveId].validApprenticeMove) + if (IsValidApprenticeMove(moveId)) break; i++; } diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 3d030707bf..b9645b2ba3 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -1529,7 +1529,7 @@ bool32 IsConfusionMoveEffect(enum BattleMoveEffects moveEffect) bool32 IsHazardMove(u32 move) { // Hazard setting moves like Stealth Rock, Spikes, etc. - u32 i, moveEffect = gMovesInfo[move].effect; + u32 i, moveEffect = GetMoveEffect(move); switch (moveEffect) { case EFFECT_SPIKES: @@ -1555,7 +1555,7 @@ bool32 IsHazardMove(u32 move) bool32 IsHazardClearingMove(u32 move) { // Hazard clearing effects like Rapid Spin, Tidy Up, etc. - u32 i, moveEffect = gMovesInfo[move].effect; + u32 i, moveEffect = GetMoveEffect(move); switch (moveEffect) { case EFFECT_RAPID_SPIN: diff --git a/src/battle_anim_effects_1.c b/src/battle_anim_effects_1.c index 8e1e39d629..96e0aad14a 100644 --- a/src/battle_anim_effects_1.c +++ b/src/battle_anim_effects_1.c @@ -6914,11 +6914,11 @@ static void AnimTask_AllySwitchDataSwap(u8 taskId) SWAP(gMoveSelectionCursor[battlerAtk], gMoveSelectionCursor[battlerPartner], temp); // Swap turn order, so that all the battlers take action SWAP(gChosenActionByBattler[battlerAtk], gChosenActionByBattler[battlerPartner], temp); - for (i = 0; i < MAX_BATTLERS_COUNT; i++) + for (i = 0; i < gBattlersCount; i++) { if (gBattlerByTurnOrder[i] == battlerAtk || gBattlerByTurnOrder[i] == battlerPartner) { - for (j = i + 1; j < MAX_BATTLERS_COUNT; j++) + for (j = i + 1; j < gBattlersCount; j++) { if (gBattlerByTurnOrder[j] == battlerAtk || gBattlerByTurnOrder[j] == battlerPartner) break; @@ -6938,9 +6938,13 @@ static void AnimTask_AllySwitchDataSwap(u8 taskId) TrySwapWishBattlerIds(battlerAtk, battlerPartner); // For Snipe Shot and abilities Stalwart/Propeller Tail - keep the original target. - for (i = 0; i < MAX_BATTLERS_COUNT; i++) + for (i = 0; i < gBattlersCount; i++) { u16 ability = GetBattlerAbility(i); + // if not targeting a slot that got switched, continue + if (!IsBattlerAlly(gBattleStruct->moveTarget[i], battlerAtk)) + continue; + if (gChosenMoveByBattler[i] == MOVE_SNIPE_SHOT || ability == ABILITY_PROPELLER_TAIL || ability == ABILITY_STALWART) gBattleStruct->moveTarget[i] ^= BIT_FLANK; } diff --git a/src/battle_end_turn.c b/src/battle_end_turn.c index 8bee265cfe..ab6de8449e 100644 --- a/src/battle_end_turn.c +++ b/src/battle_end_turn.c @@ -562,7 +562,7 @@ static bool32 HandleEndTurnLeechSeed(u32 battler) gBattleScripting.animArg1 = gBattlerTarget; gBattleScripting.animArg2 = gBattlerAttacker; gBattleStruct->moveDamage[gBattlerAttacker] = max(1, GetNonDynamaxMaxHP(battler) / 8); - gBattleStruct->moveDamage[gBattlerTarget] = GetDrainedBigRootHp(gBattlerAttacker, gBattleStruct->moveDamage[gBattlerAttacker]); + gBattleStruct->moveDamage[gBattlerTarget] = GetDrainedBigRootHp(gBattlerTarget, gBattleStruct->moveDamage[gBattlerAttacker]); gHitMarker |= HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_DAMAGE; if (GetBattlerAbility(battler) == ABILITY_LIQUID_OOZE) { diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index b46a412011..29ae4a5917 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -598,7 +598,7 @@ static void Cmd_trainerslideout(void); static void Cmd_settelekinesis(void); static void Cmd_swapstatstages(void); static void Cmd_averagestats(void); -static void Cmd_jumpifoppositegenders(void); +static void Cmd_jumpifcaptivateaffected(void); static void Cmd_unused(void); static void Cmd_tryworryseed(void); static void Cmd_callnative(void); @@ -835,8 +835,8 @@ void (* const gBattleScriptingCommandsTable[])(void) = Cmd_jumpifhasnohp, //0xE3 Cmd_jumpifnotcurrentmoveargtype, //0xE4 Cmd_pickup, //0xE5 - Cmd_unused_0xE6, //0xE6 - Cmd_unused_0xE7, //0xE7 + Cmd_unused_0xE6, //0xE6 + Cmd_unused_0xE7, //0xE7 Cmd_settypebasedhalvers, //0xE8 Cmd_jumpifsubstituteblocks, //0xE9 Cmd_tryrecycleitem, //0xEA @@ -857,7 +857,7 @@ void (* const gBattleScriptingCommandsTable[])(void) = Cmd_settelekinesis, //0xF9 Cmd_swapstatstages, //0xFA Cmd_averagestats, //0xFB - Cmd_jumpifoppositegenders, //0xFC + Cmd_jumpifcaptivateaffected, //0xFC Cmd_unused, //0xFD Cmd_tryworryseed, //0xFE Cmd_callnative, //0xFF @@ -2498,7 +2498,7 @@ static void Cmd_attackanimation(void) } // handle special move animations - if (gMovesInfo[gCurrentMove].effect == EFFECT_EXPANDING_FORCE && moveTarget & MOVE_TARGET_BOTH && CountAliveMonsInBattle(BATTLE_ALIVE_SIDE, BATTLE_OPPOSITE(gBattlerAttacker) > 1)) + if (GetMoveEffect(gCurrentMove) == EFFECT_EXPANDING_FORCE && moveTarget & MOVE_TARGET_BOTH && CountAliveMonsInBattle(BATTLE_ALIVE_SIDE, BATTLE_OPPOSITE(gBattlerAttacker) > 1)) gBattleScripting.animTurn = 1; if (!(moveResultFlags & MOVE_RESULT_NO_EFFECT)) @@ -3759,8 +3759,8 @@ void SetMoveEffect(bool32 primary, bool32 certain) flags = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN; else flags = 0; - if (mirrorArmorReflected) - flags |= (STAT_CHANGE_ALLOW_PTR * !affectsUser); + if (mirrorArmorReflected && !affectsUser) + flags |= STAT_CHANGE_ALLOW_PTR; else flags |= STAT_CHANGE_UPDATE_MOVE_EFFECT; @@ -3814,9 +3814,12 @@ void SetMoveEffect(bool32 primary, bool32 certain) flags = 0; if (mirrorArmorReflected && !affectsUser) flags |= STAT_CHANGE_ALLOW_PTR; + else + flags |= STAT_CHANGE_UPDATE_MOVE_EFFECT; + if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(2) | STAT_BUFF_NEGATIVE, gBattleScripting.moveEffect - MOVE_EFFECT_ATK_MINUS_2 + 1, - flags | STAT_CHANGE_UPDATE_MOVE_EFFECT, gBattlescriptCurrInstr + 1) == STAT_CHANGE_DIDNT_WORK) + flags, gBattlescriptCurrInstr + 1) == STAT_CHANGE_DIDNT_WORK) { if (!mirrorArmorReflected) gBattlescriptCurrInstr++; @@ -5414,6 +5417,7 @@ bool32 NoAliveMonsForPlayer(void) u32 i; u32 maxI = PARTY_SIZE; u32 HP_count = 0; + u32 ineligibleMonsCount = 0; if (B_MULTI_BATTLE_WHITEOUT < GEN_4 && gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_INGAME_PARTNER)) maxI = MULTI_PARTY_SIZE; @@ -5426,6 +5430,28 @@ bool32 NoAliveMonsForPlayer(void) { HP_count += GetMonData(&gPlayerParty[i], MON_DATA_HP); } + + // Get the number of fainted mons or eggs (not empty slots) in the first three party slots. + if (i < 3 && ((GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) && !GetMonData(&gPlayerParty[i], MON_DATA_HP)) + || GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG))) + ineligibleMonsCount++; + } + + // Get the number of inelligible slots in the saved player party. + if (B_MULTI_BATTLE_WHITEOUT > GEN_3 && gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_INGAME_PARTNER) + && !(gBattleTypeFlags & BATTLE_TYPE_ARENA)) + { + for (i = 0; i < PARTY_SIZE; i++) + { + if (!GetMonData(&gSaveBlock1Ptr->playerParty[i], MON_DATA_SPECIES) + || !GetMonData(&gSaveBlock1Ptr->playerParty[i], MON_DATA_HP) + || GetMonData(&gSaveBlock1Ptr->playerParty[i], MON_DATA_IS_EGG)) + ineligibleMonsCount++; + } + + // If the total number of ineligible mons is 6 or more, lose the battle. + if (ineligibleMonsCount >= 6) + return TRUE; } return (HP_count == 0); @@ -6669,7 +6695,7 @@ static void Cmd_moveend(void) gBattleScripting.moveendState++; break; } - else if (gMovesInfo[gCurrentMove].effect == EFFECT_RECOIL_IF_MISS + else if (GetMoveEffect(gCurrentMove) == EFFECT_RECOIL_IF_MISS && (!IsBattlerTurnDamaged(gBattlerTarget) || gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT) && !gBattleStruct->noTargetPresent && IsBattlerAlive(gBattlerAttacker)) @@ -6901,6 +6927,7 @@ static void Cmd_moveend(void) && IsBattlerTurnDamaged(gBattlerTarget) && IsBattlerAlive(gBattlerTarget) && IsBattlerAlive(gBattlerAttacker) + && !(gStatuses3[BATTLE_PARTNER(gBattlerTarget)] & STATUS3_COMMANDER) && gSpecialStatuses[gBattlerAttacker].parentalBondState != PARENTAL_BOND_1ST_HIT) { u32 targetAbility = GetBattlerAbility(gBattlerTarget); @@ -7034,12 +7061,13 @@ static void Cmd_moveend(void) } } - if (gHitMarker & HITMARKER_SWAP_ATTACKER_TARGET) + // After swapattackerwithtarget is used for snatch the correct battlers have to be restored so data is stored correctly + if (gBattleStruct->snatchedMoveIsUsed) { - u8 temp; + u32 temp; SWAP(gBattlerAttacker, gBattlerTarget, temp); - gHitMarker &= ~HITMARKER_SWAP_ATTACKER_TARGET; } + if (!gSpecialStatuses[gBattlerAttacker].dancerUsedMove) { gDisableStructs[gBattlerAttacker].usedMoves |= 1u << gCurrMovePos; @@ -7389,7 +7417,6 @@ static void Cmd_moveend(void) gLastUsedItem = gBattleMons[battler].item; SaveBattlerTarget(battler); // save battler with red card SaveBattlerAttacker(gBattlerAttacker); - gBattleStruct->savedMove = gCurrentMove; gBattleScripting.battler = battler; gEffectBattler = gBattlerAttacker; if (moveEffect == EFFECT_HIT_ESCAPE) @@ -7602,7 +7629,11 @@ static void Cmd_moveend(void) gBattleScripting.moveendState++; break; case MOVEEND_DANCER: - if (IsDanceMove(gCurrentMove) && !gBattleStruct->snatchedMoveIsUsed) + if (gCurrentMove == MOVE_NONE) + originallyUsedMove = gChosenMove; // Fallback to chosen move in case attacker is switched out in the middle of an attack resolution (eg red card) + else + originallyUsedMove = gCurrentMove; + if (IsDanceMove(originallyUsedMove) && !gBattleStruct->snatchedMoveIsUsed) { u32 battler, nextDancer = 0; bool32 hasDancerTriggered = FALSE; @@ -7636,7 +7667,7 @@ static void Cmd_moveend(void) nextDancer = battler | 0x4; } } - if (nextDancer && AbilityBattleEffects(ABILITYEFFECT_MOVE_END_OTHER, nextDancer & 0x3, 0, 0, 0)) + if (nextDancer && AbilityBattleEffects(ABILITYEFFECT_MOVE_END_OTHER, nextDancer & 0x3, 0, 0, originallyUsedMove)) effect = TRUE; } } @@ -9011,14 +9042,8 @@ static void Cmd_swapattackerwithtarget(void) { CMD_ARGS(); - u8 temp; + u32 temp; SWAP(gBattlerAttacker, gBattlerTarget, temp); - - if (gHitMarker & HITMARKER_SWAP_ATTACKER_TARGET) - gHitMarker &= ~HITMARKER_SWAP_ATTACKER_TARGET; - else - gHitMarker |= HITMARKER_SWAP_ATTACKER_TARGET; - gBattlescriptCurrInstr = cmd->nextInstr; } @@ -16684,14 +16709,24 @@ static void Cmd_averagestats(void) gBattlescriptCurrInstr = cmd->nextInstr; } -static void Cmd_jumpifoppositegenders(void) +static void Cmd_jumpifcaptivateaffected(void) { CMD_ARGS(const u8 *jumpInstr); - if (AreBattlersOfOppositeGender(gBattlerAttacker, gBattlerTarget)) + if (GetBattlerAbility(gBattlerTarget) == ABILITY_OBLIVIOUS) + { + gBattlescriptCurrInstr = BattleScript_NotAffectedAbilityPopUp; + gLastUsedAbility = ABILITY_OBLIVIOUS; + RecordAbilityBattle(gBattlerTarget, ABILITY_OBLIVIOUS); + } + else if (AreBattlersOfOppositeGender(gBattlerAttacker, gBattlerTarget)) + { gBattlescriptCurrInstr = cmd->jumpInstr; + } else + { gBattlescriptCurrInstr = cmd->nextInstr; + } } static void Cmd_unused(void) @@ -18028,6 +18063,7 @@ void BS_TryActivateGulpMissile(void) if (!(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT) && !gProtectStructs[gBattlerAttacker].confusionSelfDmg + && IsBattlerAlive(gBattlerAttacker) && IsBattlerTurnDamaged(gBattlerTarget) && gBattleMons[gBattlerTarget].species != SPECIES_CRAMORANT && GetBattlerAbility(gBattlerTarget) == ABILITY_GULP_MISSILE) @@ -18811,18 +18847,6 @@ void BS_SetSteelsurge(void) } } -void BS_RestoreSavedMove(void) -{ - NATIVE_ARGS(); - - if (gBattleStruct->savedMove == MOVE_NONE) - DebugPrintfLevel(MGBA_LOG_WARN, "restoresavedmove was called with no move saved!"); - - gCurrentMove = gBattleStruct->savedMove; - gBattleStruct->savedMove = MOVE_NONE; - gBattlescriptCurrInstr = cmd->nextInstr; -} - void BS_JumpIfCanGigantamax(void) { NATIVE_ARGS(u8 battler, const u8 *jumpInstr); diff --git a/src/battle_util.c b/src/battle_util.c index cd2f29d603..55304318c0 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -352,7 +352,7 @@ bool32 HandleMoveTargetRedirection(void) // Functions void HandleAction_UseMove(void) { - u32 i; + u32 i, moveTarget; gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; if (gBattleStruct->battlerState[gBattlerAttacker].absent @@ -436,9 +436,10 @@ void HandleAction_UseMove(void) gCurrentMove = gChosenMove = GetMaxMove(gBattlerAttacker, gCurrentMove); } + moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove); + if (!HandleMoveTargetRedirection()) { - u32 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove); if (IsDoubleBattle() && moveTarget & MOVE_TARGET_RANDOM) { gBattlerTarget = SetRandomTarget(gBattlerAttacker); @@ -450,7 +451,7 @@ void HandleAction_UseMove(void) } else if (moveTarget == MOVE_TARGET_ALLY) { - if (IsBattlerAlive(BATTLE_PARTNER(gBattlerAttacker))) + if (IsBattlerAlive(BATTLE_PARTNER(gBattlerAttacker)) && !gProtectStructs[BATTLE_PARTNER(gBattlerAttacker)].usedAllySwitch) gBattlerTarget = BATTLE_PARTNER(gBattlerAttacker); else gBattlerTarget = gBattlerAttacker; @@ -465,6 +466,10 @@ void HandleAction_UseMove(void) break; } } + else if (moveTarget == MOVE_TARGET_USER) + { + gBattlerTarget = gBattlerAttacker; + } else { gBattlerTarget = *(gBattleStruct->moveTarget + gBattlerAttacker); @@ -498,8 +503,13 @@ void HandleAction_UseMove(void) } } - if ((IsBattlerAlly(gBattlerAttacker, gBattlerTarget)) - && (!IsBattlerAlive(gBattlerTarget) || gProtectStructs[BATTLE_PARTNER(gBattlerAttacker)].usedAllySwitch)) + if (IsBattlerAlly(gBattlerAttacker, gBattlerTarget) && !IsBattlerAlive(gBattlerTarget)) + { + gBattlescriptCurrInstr = BattleScript_FailedFromAtkCanceler; + } + // If originally targetting an ally but now targetting user due to Ally Switch + else if (moveTarget & MOVE_TARGET_ALLY && gBattlerAttacker == gBattlerTarget + && gProtectStructs[BATTLE_PARTNER(gBattlerAttacker)].usedAllySwitch) { gBattlescriptCurrInstr = BattleScript_FailedFromAtkCanceler; } @@ -824,7 +834,7 @@ void HandleAction_NothingIsFainted(void) gCurrentActionFuncId = gActionsByTurnOrder[gCurrentTurnActionNumber]; gHitMarker &= ~(HITMARKER_DESTINYBOND | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_ATTACKSTRING_PRINTED | HITMARKER_NO_PPDEDUCT | HITMARKER_STATUS_ABILITY_EFFECT | HITMARKER_PASSIVE_DAMAGE - | HITMARKER_OBEYS | HITMARKER_WAKE_UP_CLEAR | HITMARKER_SYNCHRONISE_EFFECT + | HITMARKER_OBEYS | HITMARKER_SYNCHRONISE_EFFECT | HITMARKER_CHARGING | HITMARKER_NEVER_SET); } @@ -838,7 +848,7 @@ void HandleAction_ActionFinished(void) SpecialStatusesClear(); gHitMarker &= ~(HITMARKER_DESTINYBOND | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_ATTACKSTRING_PRINTED | HITMARKER_NO_PPDEDUCT | HITMARKER_STATUS_ABILITY_EFFECT | HITMARKER_PASSIVE_DAMAGE - | HITMARKER_OBEYS | HITMARKER_WAKE_UP_CLEAR | HITMARKER_SYNCHRONISE_EFFECT + | HITMARKER_OBEYS | HITMARKER_SYNCHRONISE_EFFECT | HITMARKER_CHARGING | HITMARKER_NEVER_SET | HITMARKER_IGNORE_DISGUISE); // check if Stellar type boost should be used up @@ -1994,7 +2004,6 @@ static void CancellerObedience(u32 *effect) SetAtkCancellerForCalledMove(); gBattlescriptCurrInstr = BattleScript_IgnoresAndUsesRandomMove; gBattlerTarget = GetBattleMoveTarget(gCalledMove, NO_TARGET_OVERRIDE); - gHitMarker |= HITMARKER_DISOBEDIENT_MOVE; gHitMarker |= HITMARKER_OBEYS; break; } @@ -4083,6 +4092,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 case ABILITY_COMMANDER: partner = BATTLE_PARTNER(battler); if (!gSpecialStatuses[battler].switchInAbilityDone + && IsBattlerAlive(partner) + && IsBattlerAlive(battler) && gBattleStruct->commanderActive[partner] == SPECIES_NONE && gBattleMons[partner].species == SPECIES_DONDOZO && GET_BASE_SPECIES_ID(GetMonData(GetPartyBattlerData(battler), MON_DATA_SPECIES)) == SPECIES_TATSUGIRI) @@ -4814,7 +4825,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 if (!(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT) && !gProtectStructs[gBattlerAttacker].confusionSelfDmg && IsBattlerTurnDamaged(gBattlerTarget) - && IsBattlerAlive(battler) + && IsBattlerAlive(gBattlerAttacker) && gBattleMons[gBattlerTarget].species != SPECIES_CRAMORANT) { if (GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD) @@ -4994,7 +5005,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 { case ABILITY_DANCER: if (IsBattlerAlive(battler) - && IsDanceMove(gCurrentMove) + && IsDanceMove(move) && !gSpecialStatuses[battler].dancerUsedMove && gBattlerAttacker != battler) { @@ -5002,7 +5013,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 gSpecialStatuses[battler].dancerUsedMove = TRUE; gSpecialStatuses[battler].dancerOriginalTarget = gBattleStruct->moveTarget[battler] | 0x4; gBattlerAttacker = gBattlerAbility = battler; - gCalledMove = gCurrentMove; + gCalledMove = move; // Set the target to the original target of the mon that first used a Dance move gBattlerTarget = gBattleScripting.savedBattler & 0x3; diff --git a/test/battle/ability/color_change.c b/test/battle/ability/color_change.c index 668cb01b62..42932a7d58 100644 --- a/test/battle/ability/color_change.c +++ b/test/battle/ability/color_change.c @@ -5,7 +5,7 @@ SINGLE_BATTLE_TEST("Color Change changes the type of a Pokemon being hit by a mo { GIVEN { ASSUME(gSpeciesInfo[SPECIES_KECLEON].types[0] != TYPE_PSYCHIC && gSpeciesInfo[SPECIES_KECLEON].types[1] != TYPE_PSYCHIC); - ASSUME(gMovesInfo[MOVE_PSYWAVE].type == TYPE_PSYCHIC); + ASSUME(GetMoveType(MOVE_PSYWAVE) == TYPE_PSYCHIC); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_KECLEON) { Ability(ABILITY_COLOR_CHANGE); } } WHEN { @@ -21,7 +21,7 @@ SINGLE_BATTLE_TEST("Color Change does not change the type when hit by a move tha { GIVEN { ASSUME(gSpeciesInfo[SPECIES_KECLEON].types[0] == TYPE_NORMAL || gSpeciesInfo[SPECIES_KECLEON].types[1] == TYPE_NORMAL); - ASSUME(gMovesInfo[MOVE_TACKLE].type == TYPE_NORMAL); + ASSUME(GetMoveType(MOVE_TACKLE) == TYPE_NORMAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_KECLEON) { Ability(ABILITY_COLOR_CHANGE); } } WHEN { @@ -47,7 +47,7 @@ SINGLE_BATTLE_TEST("Color Change does not change the type of a dual-type Pokemon ANIMATION(ANIM_TYPE_MOVE, MOVE_PSYCHO_CUT, player); NONE_OF { ABILITY_POPUP(opponent, ABILITY_COLOR_CHANGE); - MESSAGE("The opposing Xatu's Color Change made it the Psychic type!"); + MESSAGE("The opposing Slowbro's Color Change made it the Psychic type!"); } } } diff --git a/test/battle/ability/commander.c b/test/battle/ability/commander.c index d4b31f23b8..a50eba7b8c 100644 --- a/test/battle/ability/commander.c +++ b/test/battle/ability/commander.c @@ -421,3 +421,37 @@ DOUBLE_BATTLE_TEST("Commander Tatsugiri does not get hit by Dragon Darts when co NOT HP_BAR(playerLeft); } } + +DOUBLE_BATTLE_TEST("Commander will not activate if Dondozo fainted right before Tatsugiri came in") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_DONDOZO) { HP(1); } + PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponentRight, MOVE_TACKLE, target: playerRight); MOVE(playerLeft, MOVE_SHED_TAIL); SEND_OUT(playerLeft, 2); SEND_OUT(playerRight, 3); } + } SCENE { + NOT ABILITY_POPUP(playerLeft, ABILITY_COMMANDER); + } +} + +DOUBLE_BATTLE_TEST("Commander prevent Dondozo from switch out by Dragon Tail") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_DRAGON_TAIL) == EFFECT_HIT_SWITCH_TARGET); + PLAYER(SPECIES_DONDOZO); + PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponentLeft, MOVE_DRAGON_TAIL, target: playerLeft); } + } SCENE { + ABILITY_POPUP(playerRight, ABILITY_COMMANDER); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_TAIL, opponentLeft); + NOT MESSAGE("Wobbuffet was dragged out!"); + } +} diff --git a/test/battle/ability/gulp_missile.c b/test/battle/ability/gulp_missile.c index 72e826b252..76d66c4fb8 100644 --- a/test/battle/ability/gulp_missile.c +++ b/test/battle/ability/gulp_missile.c @@ -190,3 +190,13 @@ SINGLE_BATTLE_TEST("(Gulp Missile) Transformed Cramorant Gulping lowers defense HP_BAR(opponent); } } + +SINGLE_BATTLE_TEST("Gulp Missile triggered by explosion doesn't freeze the game") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_CRAMORANT); + } WHEN { + TURN { MOVE(opponent, MOVE_SURF); MOVE(player, MOVE_EXPLOSION); } + } +} diff --git a/test/battle/ability/intimidate.c b/test/battle/ability/intimidate.c index 61b53f42e1..dd1f761dee 100644 --- a/test/battle/ability/intimidate.c +++ b/test/battle/ability/intimidate.c @@ -379,7 +379,7 @@ DOUBLE_BATTLE_TEST("Intimidate will correctly decrease the attack of the second SINGLE_BATTLE_TEST("Intimdate does not lose timing after mega evolution and switch out by a hit escape move") { GIVEN { - ASSUME(gMovesInfo[MOVE_U_TURN].effect == EFFECT_HIT_ESCAPE); + ASSUME(GetMoveEffect(MOVE_U_TURN) == EFFECT_HIT_ESCAPE); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_MANECTRIC) { Item(ITEM_MANECTITE); } OPPONENT(SPECIES_ARBOK) { Ability(ABILITY_INTIMIDATE); } diff --git a/test/battle/ability/mirror_armor.c b/test/battle/ability/mirror_armor.c index 5aa2b55ef3..0918682d76 100644 --- a/test/battle/ability/mirror_armor.c +++ b/test/battle/ability/mirror_armor.c @@ -211,3 +211,18 @@ SINGLE_BATTLE_TEST("Mirror Armor reflects Tangling Hair speed drop") ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); } } + +SINGLE_BATTLE_TEST("Mirror Armor reflects Obstruct defense drop") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_CORVIKNIGHT) { Ability(ABILITY_MIRROR_ARMOR); } + } WHEN { + TURN { MOVE(player, MOVE_OBSTRUCT); MOVE(opponent, MOVE_TACKLE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_OBSTRUCT, player); + NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + ABILITY_POPUP(opponent, ABILITY_MIRROR_ARMOR); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + } +} diff --git a/test/battle/ability/neutralizing_gas.c b/test/battle/ability/neutralizing_gas.c index ef83483d32..ae11c458f7 100644 --- a/test/battle/ability/neutralizing_gas.c +++ b/test/battle/ability/neutralizing_gas.c @@ -51,7 +51,7 @@ DOUBLE_BATTLE_TEST("Neutralizing Gas prevents ally's switch-in ability from acti DOUBLE_BATTLE_TEST("Neutralizing Gas ignores all battlers' ability effects") { GIVEN { - ASSUME(gMovesInfo[MOVE_SURF].target == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveTarget(MOVE_SURF) == MOVE_TARGET_FOES_AND_ALLY); PLAYER(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); } PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_TELEPATHY); } OPPONENT(SPECIES_LANTURN) { Ability(ABILITY_WATER_ABSORB); } @@ -87,7 +87,7 @@ SINGLE_BATTLE_TEST("Neutralizing Gas ignores multipliers from attacker's ability PARAMETRIZE { ability = ABILITY_NEUTRALIZING_GAS; } PARAMETRIZE { ability = ABILITY_LEVITATE; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WEEZING) { Ability(ability); } OPPONENT(SPECIES_AZUMARILL) { Ability(ABILITY_HUGE_POWER); } } WHEN { @@ -106,8 +106,8 @@ SINGLE_BATTLE_TEST("Neutralizing Gas ignores multipliers from target's ability", PARAMETRIZE { ability = ABILITY_NEUTRALIZING_GAS; } PARAMETRIZE { ability = ABILITY_LEVITATE; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact == TRUE); - ASSUME(gMovesInfo[MOVE_TACKLE].type == TYPE_NORMAL); + ASSUME(MoveMakesContact(MOVE_TACKLE) == TRUE); + ASSUME(GetMoveType(MOVE_TACKLE) == TYPE_NORMAL); PLAYER(SPECIES_WEEZING) { Ability(ability); } OPPONENT(SPECIES_BEWEAR) { Ability(ABILITY_FLUFFY); } } WHEN { @@ -146,7 +146,7 @@ DOUBLE_BATTLE_TEST("Neutralizing Gas ignores multipliers from ally's ability", s PARAMETRIZE { ability = ABILITY_NEUTRALIZING_GAS; } PARAMETRIZE { ability = ABILITY_LEVITATE; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WEEZING) { Ability(ability); } PLAYER(SPECIES_WO_CHIEN) { Ability(ABILITY_TABLETS_OF_RUIN); } OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_TELEPATHY); } diff --git a/test/battle/ability/oblivious.c b/test/battle/ability/oblivious.c index 3ac979a271..a787ec6578 100644 --- a/test/battle/ability/oblivious.c +++ b/test/battle/ability/oblivious.c @@ -23,7 +23,7 @@ SINGLE_BATTLE_TEST("Oblivious prevents Captivate") PLAYER(SPECIES_SLOWPOKE) { Ability(ABILITY_OBLIVIOUS); Gender(MON_MALE); } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_FEMALE); } } WHEN { - TURN { MOVE(opponent, MOVE_ATTRACT); } + TURN { MOVE(opponent, MOVE_CAPTIVATE); } } SCENE { ABILITY_POPUP(player, ABILITY_OBLIVIOUS); NONE_OF { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); } diff --git a/test/battle/ability/thermal_exchange.c b/test/battle/ability/thermal_exchange.c index 57f4256d7a..7484fa207c 100644 --- a/test/battle/ability/thermal_exchange.c +++ b/test/battle/ability/thermal_exchange.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Thermal Exchange makes Will-O-Wisp fail") { GIVEN { - ASSUME(gMovesInfo[MOVE_WILL_O_WISP].effect == EFFECT_WILL_O_WISP); + ASSUME(GetMoveEffect(MOVE_WILL_O_WISP) == EFFECT_WILL_O_WISP); PLAYER(SPECIES_BAXCALIBUR) { Ability(ABILITY_THERMAL_EXCHANGE); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -37,8 +37,8 @@ SINGLE_BATTLE_TEST("Thermal Exchange prevents the user from getting burned when SINGLE_BATTLE_TEST("Thermal Exchange cures burns when acquired") { GIVEN { - ASSUME(gMovesInfo[MOVE_WILL_O_WISP].effect == EFFECT_WILL_O_WISP); - ASSUME(gMovesInfo[MOVE_SKILL_SWAP].effect == EFFECT_SKILL_SWAP); + ASSUME(GetMoveEffect(MOVE_WILL_O_WISP) == EFFECT_WILL_O_WISP); + ASSUME(GetMoveEffect(MOVE_SKILL_SWAP) == EFFECT_SKILL_SWAP); PLAYER(SPECIES_BAXCALIBUR) { Ability(ABILITY_THERMAL_EXCHANGE); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -56,7 +56,7 @@ SINGLE_BATTLE_TEST("Thermal Exchange cures burns when acquired") SINGLE_BATTLE_TEST("Thermal Exchange burn prevention can be bypassed with Mold Breaker but is cured after") { GIVEN { - ASSUME(gMovesInfo[MOVE_WILL_O_WISP].effect == EFFECT_WILL_O_WISP); + ASSUME(GetMoveEffect(MOVE_WILL_O_WISP) == EFFECT_WILL_O_WISP); PLAYER(SPECIES_BAXCALIBUR) { Ability(ABILITY_THERMAL_EXCHANGE); } OPPONENT(SPECIES_RAMPARDOS) { Ability(ABILITY_MOLD_BREAKER); } } WHEN { @@ -73,7 +73,7 @@ SINGLE_BATTLE_TEST("Thermal Exchange burn prevention can be bypassed with Mold B SINGLE_BATTLE_TEST("Thermal Exchange boosts attack if hit by a damaging fire type move") { GIVEN { - ASSUME(gMovesInfo[MOVE_EMBER].type == TYPE_FIRE); + ASSUME(GetMoveType(MOVE_EMBER) == TYPE_FIRE); PLAYER(SPECIES_BAXCALIBUR) { Ability(ABILITY_THERMAL_EXCHANGE); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/ai/ai.c b/test/battle/ai/ai.c index bf97361c68..c67095b5e9 100644 --- a/test/battle/ai/ai.c +++ b/test/battle/ai/ai.c @@ -835,8 +835,8 @@ AI_SINGLE_BATTLE_TEST("AI stays choice locked into moves in spite of the player' AI_SINGLE_BATTLE_TEST("AI won't use Sucker Punch if it expects a move of the same priority bracket and the opponent is faster") { GIVEN { - ASSUME(gMovesInfo[MOVE_QUICK_ATTACK].priority == 1); - ASSUME(gMovesInfo[MOVE_SUCKER_PUNCH].priority == 1); + ASSUME(GetMovePriority(MOVE_QUICK_ATTACK) == 1); + ASSUME(GetMovePriority(MOVE_SUCKER_PUNCH) == 1); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET) { Speed(300); Moves(MOVE_QUICK_ATTACK); } OPPONENT(SPECIES_WOBBUFFET) { Speed(100); Moves(MOVE_SUCKER_PUNCH, MOVE_TACKLE); } diff --git a/test/battle/hold_effect/big_root.c b/test/battle/hold_effect/big_root.c index 0b3d9b4af6..41dd09adc0 100644 --- a/test/battle/hold_effect/big_root.c +++ b/test/battle/hold_effect/big_root.c @@ -30,8 +30,6 @@ SINGLE_BATTLE_TEST("Big Root increases healing from absorbing moves", s16 damage SINGLE_BATTLE_TEST("Big Root increases the damage restored from Leech Seed, Ingrain and Aqua Ring", s16 heal, s16 damage) { - KNOWN_FAILING; - u32 item; u32 move; @@ -53,9 +51,9 @@ SINGLE_BATTLE_TEST("Big Root increases the damage restored from Leech Seed, Ingr HP_BAR(player, captureDamage: &results[i].heal); } FINALLY { EXPECT_EQ(results[0].damage, results[1].damage); // Damage is unaffected - EXPECT_MUL_EQ(results[1].heal, Q_4_12(5234 / 4096), results[0].heal); - EXPECT_MUL_EQ(results[3].heal, Q_4_12(5234 / 4096), results[2].heal); - EXPECT_MUL_EQ(results[5].heal, Q_4_12(5234 / 4096), results[4].heal); + EXPECT_MUL_EQ(results[0].heal, Q_4_12(1.3), results[1].heal); + EXPECT_MUL_EQ(results[2].heal, Q_4_12(1.3), results[3].heal); + EXPECT_MUL_EQ(results[4].heal, Q_4_12(1.3), results[5].heal); } } diff --git a/test/battle/hold_effect/shell_bell.c b/test/battle/hold_effect/shell_bell.c index f669c55081..8e91011865 100644 --- a/test/battle/hold_effect/shell_bell.c +++ b/test/battle/hold_effect/shell_bell.c @@ -208,7 +208,7 @@ DOUBLE_BATTLE_TEST("Shell Bell heals accumulated damage for spread moves") const u16 maxHp = 200; const u16 initHp = 1; GIVEN { - ASSUME(gMovesInfo[MOVE_DISCHARGE].target == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveTarget(MOVE_DISCHARGE) == MOVE_TARGET_FOES_AND_ALLY); PLAYER(SPECIES_ARIADOS) { MaxHP(maxHp); HP(initHp); Item(ITEM_SHELL_BELL); } PLAYER(SPECIES_WOBBUFFET) {} OPPONENT(SPECIES_GYARADOS) {} diff --git a/test/battle/move_effect/acupressure.c b/test/battle/move_effect/acupressure.c index d59a3faee3..02be60725d 100644 --- a/test/battle/move_effect/acupressure.c +++ b/test/battle/move_effect/acupressure.c @@ -16,20 +16,40 @@ DOUBLE_BATTLE_TEST("Acupressure fails on the user if it targeted its ally but sw OPPONENT(SPECIES_KADABRA); OPPONENT(SPECIES_ABRA); } WHEN { - TURN { MOVE(playerLeft, MOVE_ALLY_SWITCH); MOVE(playerRight, MOVE_ACUPRESSURE, target:playerLeft); } + TURN { MOVE(playerLeft, MOVE_ALLY_SWITCH); MOVE(playerRight, MOVE_ACUPRESSURE, target: playerLeft); } } SCENE { MESSAGE("Wobbuffet used Ally Switch!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, playerLeft); MESSAGE("Wobbuffet and Wynaut switched places!"); - + MESSAGE("Wynaut used Acupressure!"); MESSAGE("But it failed!"); NONE_OF { - ANIMATION(ANIM_TYPE_MOVE, MOVE_ACUPRESSURE); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ACUPRESSURE, playerLeft); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft); } } } +DOUBLE_BATTLE_TEST("Acupressure works on the ally if it targeted itself but switched positions via Ally Switch") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_KADABRA); + OPPONENT(SPECIES_ABRA); + } WHEN { + TURN { MOVE(playerLeft, MOVE_ALLY_SWITCH); MOVE(playerRight, MOVE_ACUPRESSURE, target: playerRight); } + } SCENE { + MESSAGE("Wobbuffet used Ally Switch!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, playerLeft); + MESSAGE("Wobbuffet and Wynaut switched places!"); + MESSAGE("Wynaut used Acupressure!"); + NOT MESSAGE("But it failed!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ACUPRESSURE, playerLeft); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight); + } +} + TO_DO_BATTLE_TEST("Acupressure works on the user if its side is protected by Crafty Shield"); TO_DO_BATTLE_TEST("Acupressure fails on the ally if its side is protected by Crafty Shield"); diff --git a/test/battle/move_effect/ally_switch.c b/test/battle/move_effect/ally_switch.c index 520de60106..ba2ac1a053 100644 --- a/test/battle/move_effect/ally_switch.c +++ b/test/battle/move_effect/ally_switch.c @@ -167,6 +167,24 @@ DOUBLE_BATTLE_TEST("Ally Switch - move fails if the target was ally which change } } +DOUBLE_BATTLE_TEST("Ally Switch doesn't make self-targeting status moves fail") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_HARDEN].target == MOVE_TARGET_USER); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(playerLeft, MOVE_ALLY_SWITCH); MOVE(playerRight, MOVE_HARDEN); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, playerLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_HARDEN, playerLeft); + } THEN { + EXPECT_EQ(playerLeft->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 1); + } +} + DOUBLE_BATTLE_TEST("Ally Switch increases the Protect-like moves counter") { GIVEN { diff --git a/test/battle/move_effect/dream_eater.c b/test/battle/move_effect/dream_eater.c index 67b2ed5af5..caa365a17a 100644 --- a/test/battle/move_effect/dream_eater.c +++ b/test/battle/move_effect/dream_eater.c @@ -77,9 +77,9 @@ SINGLE_BATTLE_TEST("Dream Eater works on targets with Comatose") SINGLE_BATTLE_TEST("Dream Eater fails if the target is behind a Substitute (Gen 1-4)") { GIVEN { - ASSUME(gMovesInfo[MOVE_YAWN].effect == EFFECT_YAWN); - ASSUME(gMovesInfo[MOVE_SUBSTITUTE].effect == EFFECT_SUBSTITUTE); - ASSUME(!gMovesInfo[MOVE_DREAM_EATER].ignoresSubstitute); + ASSUME(GetMoveEffect(MOVE_YAWN) == EFFECT_YAWN); + ASSUME(GetMoveEffect(MOVE_SUBSTITUTE) == EFFECT_SUBSTITUTE); + ASSUME(!MoveIgnoresSubstitute(MOVE_DREAM_EATER)); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -97,8 +97,8 @@ SINGLE_BATTLE_TEST("Dream Eater works if the target is behind a Substitute (Gen s16 damage; s16 healed; GIVEN { - ASSUME(gMovesInfo[MOVE_YAWN].effect == EFFECT_YAWN); - ASSUME(gMovesInfo[MOVE_SUBSTITUTE].effect == EFFECT_SUBSTITUTE); + ASSUME(GetMoveEffect(MOVE_YAWN) == EFFECT_YAWN); + ASSUME(GetMoveEffect(MOVE_SUBSTITUTE) == EFFECT_SUBSTITUTE); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { HP(1); } } WHEN { diff --git a/test/battle/move_effect/follow_me.c b/test/battle/move_effect/follow_me.c index fe7b96207d..f24629f141 100644 --- a/test/battle/move_effect/follow_me.c +++ b/test/battle/move_effect/follow_me.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_FOLLOW_ME].effect == EFFECT_FOLLOW_ME); - ASSUME(gMovesInfo[MOVE_SPOTLIGHT].effect == EFFECT_FOLLOW_ME); + ASSUME(GetMoveEffect(MOVE_FOLLOW_ME) == EFFECT_FOLLOW_ME); + ASSUME(GetMoveEffect(MOVE_SPOTLIGHT) == EFFECT_FOLLOW_ME); } DOUBLE_BATTLE_TEST("Follow Me redirects single target moves used by opponents to user") diff --git a/test/battle/move_effect/instruct.c b/test/battle/move_effect/instruct.c index 85f56d4c4b..e61540b9c5 100644 --- a/test/battle/move_effect/instruct.c +++ b/test/battle/move_effect/instruct.c @@ -249,8 +249,8 @@ DOUBLE_BATTLE_TEST("Instructed move will be redirected by Follow Me after instru PARAMETRIZE { moveTarget = opponentLeft; } PARAMETRIZE { moveTarget = opponentRight; } GIVEN { - ASSUME(gMovesInfo[MOVE_FOLLOW_ME].effect == EFFECT_FOLLOW_ME); - ASSUME(gMovesInfo[MOVE_SKILL_SWAP].effect == EFFECT_SKILL_SWAP); + ASSUME(GetMoveEffect(MOVE_FOLLOW_ME) == EFFECT_FOLLOW_ME); + ASSUME(GetMoveEffect(MOVE_SKILL_SWAP) == EFFECT_SKILL_SWAP); PLAYER(SPECIES_DURALUDON) { Ability(ABILITY_STALWART); } PLAYER(SPECIES_DURALUDON) { Ability(ABILITY_STALWART); } OPPONENT(SPECIES_WOBBUFFET); @@ -279,9 +279,9 @@ DOUBLE_BATTLE_TEST("Instructed move will be redirected by Rage Powder after inst PARAMETRIZE { moveTarget = opponentLeft; } PARAMETRIZE { moveTarget = opponentRight; } GIVEN { - ASSUME(gMovesInfo[MOVE_RAGE_POWDER].effect == EFFECT_FOLLOW_ME); - ASSUME(gMovesInfo[MOVE_RAGE_POWDER].powderMove == TRUE); - ASSUME(gMovesInfo[MOVE_SOAK].effect == EFFECT_SOAK); + ASSUME(GetMoveEffect(MOVE_RAGE_POWDER) == EFFECT_FOLLOW_ME); + ASSUME(IsPowderMove(MOVE_RAGE_POWDER) == TRUE); + ASSUME(GetMoveEffect(MOVE_SOAK) == EFFECT_SOAK); PLAYER(SPECIES_TREECKO); PLAYER(SPECIES_SCEPTILE); OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/move_effect/laser_focus.c b/test/battle/move_effect/laser_focus.c index c486a3cbee..17922d3231 100644 --- a/test/battle/move_effect/laser_focus.c +++ b/test/battle/move_effect/laser_focus.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_LASER_FOCUS].effect == EFFECT_LASER_FOCUS); + ASSUME(GetMoveEffect(MOVE_LASER_FOCUS) == EFFECT_LASER_FOCUS); } SINGLE_BATTLE_TEST("Laser Focus causes the user's move used on the next turn to result in a Critical Hit") diff --git a/test/battle/move_effect/recoil_if_miss.c b/test/battle/move_effect/recoil_if_miss.c index 0b65eb8541..a5dbfef178 100644 --- a/test/battle/move_effect/recoil_if_miss.c +++ b/test/battle/move_effect/recoil_if_miss.c @@ -102,7 +102,7 @@ SINGLE_BATTLE_TEST("Recoil if miss: Jump Kick's recoil happens after Spiky Shiel SINGLE_BATTLE_TEST("Recoil if miss: Jump Kick recoil happens after Spiky Shield damage") { GIVEN { - ASSUME(!gMovesInfo[MOVE_JUMP_KICK].ignoresProtect); + ASSUME(!MoveIgnoresProtect(MOVE_JUMP_KICK)); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect/rototiller.c b/test/battle/move_effect/rototiller.c index 32ae7da75f..34b62a2666 100644 --- a/test/battle/move_effect/rototiller.c +++ b/test/battle/move_effect/rototiller.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_ROTOTILLER].effect == EFFECT_ROTOTILLER); + ASSUME(GetMoveEffect(MOVE_ROTOTILLER) == EFFECT_ROTOTILLER); } DOUBLE_BATTLE_TEST("Rototiller boosts Attack and Special Attack of all Grass types on the field") @@ -55,7 +55,7 @@ SINGLE_BATTLE_TEST("Rototiller doesn't affect pokemon that are semi-invulnerable { GIVEN { ASSUME(gSpeciesInfo[SPECIES_TANGELA].types[0] == TYPE_GRASS); - ASSUME(gMovesInfo[MOVE_DIG].effect == EFFECT_SEMI_INVULNERABLE); + ASSUME(GetMoveEffect(MOVE_DIG) == EFFECT_SEMI_INVULNERABLE); PLAYER(SPECIES_TANGELA); OPPONENT(SPECIES_TANGELA); } WHEN { @@ -79,7 +79,7 @@ SINGLE_BATTLE_TEST("Rototiller fails if the only valid target is semi-invulnerab ASSUME(gSpeciesInfo[SPECIES_TANGELA].types[0] == TYPE_GRASS); ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_GRASS); ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_GRASS); - ASSUME(gMovesInfo[MOVE_DIG].effect == EFFECT_SEMI_INVULNERABLE); + ASSUME(GetMoveEffect(MOVE_DIG) == EFFECT_SEMI_INVULNERABLE); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_TANGELA); } WHEN { diff --git a/test/battle/move_effect/sleep_talk.c b/test/battle/move_effect/sleep_talk.c index b00f89e582..fd246f47aa 100644 --- a/test/battle/move_effect/sleep_talk.c +++ b/test/battle/move_effect/sleep_talk.c @@ -94,8 +94,8 @@ SINGLE_BATTLE_TEST("Sleep Talk can use moves while choiced into Sleep Talk") SINGLE_BATTLE_TEST("Sleep Talk fails if user is taunted") { GIVEN { - ASSUME(gMovesInfo[MOVE_TAUNT].effect == EFFECT_TAUNT); - ASSUME(gMovesInfo[MOVE_SLEEP_TALK].category == DAMAGE_CATEGORY_STATUS); + ASSUME(GetMoveEffect(MOVE_TAUNT) == EFFECT_TAUNT); + ASSUME(GetMoveCategory(MOVE_SLEEP_TALK) == DAMAGE_CATEGORY_STATUS); PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); Moves(MOVE_SLEEP_TALK, MOVE_TACKLE, MOVE_FLY, MOVE_DIG); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -113,7 +113,7 @@ DOUBLE_BATTLE_TEST("Sleep Talk calls move and that move may be redirected by Lig { PASSES_RANDOMLY(1, 2, RNG_RANDOM_TARGET); GIVEN { - ASSUME(gMovesInfo[MOVE_SPARK].type == TYPE_ELECTRIC); + ASSUME(GetMoveType(MOVE_SPARK) == TYPE_ELECTRIC); PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); Moves(MOVE_SLEEP_TALK, MOVE_SPARK, MOVE_FLY, MOVE_DIG); } PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -132,7 +132,7 @@ DOUBLE_BATTLE_TEST("Sleep Talk calls move and that move may be redirected by Sto { PASSES_RANDOMLY(1, 2, RNG_RANDOM_TARGET); GIVEN { - ASSUME(gMovesInfo[MOVE_WATER_GUN].type == TYPE_WATER); + ASSUME(GetMoveType(MOVE_WATER_GUN) == TYPE_WATER); PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); Moves(MOVE_SLEEP_TALK, MOVE_WATER_GUN, MOVE_FLY, MOVE_DIG); } PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/move_effect/snore.c b/test/battle/move_effect/snore.c index d83e35b16c..410406a65b 100644 --- a/test/battle/move_effect/snore.c +++ b/test/battle/move_effect/snore.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_SNORE].effect == EFFECT_SNORE); + ASSUME(GetMoveEffect(MOVE_SNORE) == EFFECT_SNORE); } SINGLE_BATTLE_TEST("Snore fails if not asleep") @@ -47,7 +47,7 @@ SINGLE_BATTLE_TEST("Snore fails if user is throat chopped") { GIVEN { ASSUME(MoveHasAdditionalEffect(MOVE_THROAT_CHOP, MOVE_EFFECT_THROAT_CHOP)); - ASSUME(gMovesInfo[MOVE_SNORE].soundMove == TRUE); + ASSUME(IsSoundMove(MOVE_SNORE) == TRUE); PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect/spectral_thief.c b/test/battle/move_effect/spectral_thief.c index 7bb5d5a536..885df9f5e3 100644 --- a/test/battle/move_effect/spectral_thief.c +++ b/test/battle/move_effect/spectral_thief.c @@ -8,8 +8,8 @@ SINGLE_BATTLE_TEST("Spectral Thief steals opponents boost before attacking", s16 PARAMETRIZE { move = MOVE_SWORDS_DANCE; } GIVEN { - ASSUME(gMovesInfo[MOVE_SWORDS_DANCE].effect == EFFECT_ATTACK_UP_2); - ASSUME(gMovesInfo[MOVE_SPECTRAL_THIEF].effect == EFFECT_SPECTRAL_THIEF); + ASSUME(GetMoveEffect(MOVE_SWORDS_DANCE) == EFFECT_ATTACK_UP_2); + ASSUME(GetMoveEffect(MOVE_SPECTRAL_THIEF) == EFFECT_SPECTRAL_THIEF); PLAYER(SPECIES_REGIROCK); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -32,8 +32,8 @@ SINGLE_BATTLE_TEST("Spectral Thief steals opponents boost before attacking", s16 SINGLE_BATTLE_TEST("Spectral Thief can't steal opponent's boost if target is immune") { GIVEN { - ASSUME(gMovesInfo[MOVE_SWORDS_DANCE].effect == EFFECT_ATTACK_UP_2); - ASSUME(gMovesInfo[MOVE_SPECTRAL_THIEF].effect == EFFECT_SPECTRAL_THIEF); + ASSUME(GetMoveEffect(MOVE_SWORDS_DANCE) == EFFECT_ATTACK_UP_2); + ASSUME(GetMoveEffect(MOVE_SPECTRAL_THIEF) == EFFECT_SPECTRAL_THIEF); PLAYER(SPECIES_MEOWTH); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect_secondary/haze.c b/test/battle/move_effect_secondary/haze.c index c3831f0768..c6a0f2cab1 100644 --- a/test/battle/move_effect_secondary/haze.c +++ b/test/battle/move_effect_secondary/haze.c @@ -16,7 +16,10 @@ SINGLE_BATTLE_TEST("Freeze Frost restores stat changes when it was succesful") PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { MOVE(player, MOVE_FREEZY_FROST, hit: moveSuccess); } + TURN { + MOVE(opponent, MOVE_SAND_ATTACK); + MOVE(player, MOVE_FREEZY_FROST, hit: moveSuccess); + } } SCENE { if (moveSuccess == TRUE) { diff --git a/test/battle/move_effect_secondary/leech_seed.c b/test/battle/move_effect_secondary/leech_seed.c index c5a8db57cc..b7eef45ed4 100644 --- a/test/battle/move_effect_secondary/leech_seed.c +++ b/test/battle/move_effect_secondary/leech_seed.c @@ -26,7 +26,10 @@ SINGLE_BATTLE_TEST("Sappy Seed is not going to seed the target if it fails") PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { MOVE(player, MOVE_SAPPY_SEED, hit: FALSE); } + TURN { + MOVE(opponent, MOVE_SAND_ATTACK); + MOVE(player, MOVE_SAPPY_SEED, hit: FALSE); + } } SCENE { NONE_OF { ANIMATION(ANIM_TYPE_MOVE, MOVE_SAPPY_SEED, player); diff --git a/test/battle/move_effect_secondary/light_screen.c b/test/battle/move_effect_secondary/light_screen.c index 244e469893..e834e6055f 100644 --- a/test/battle/move_effect_secondary/light_screen.c +++ b/test/battle/move_effect_secondary/light_screen.c @@ -16,7 +16,10 @@ SINGLE_BATTLE_TEST("Glitzy Glow sets up Light Screen when it was succesful") PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { MOVE(player, MOVE_GLITZY_GLOW, hit: moveSuccess); } + TURN { + MOVE(opponent, MOVE_SAND_ATTACK); + MOVE(player, MOVE_GLITZY_GLOW, hit: moveSuccess); + } } SCENE { if (moveSuccess == TRUE) { diff --git a/test/battle/move_effect_secondary/reflect.c b/test/battle/move_effect_secondary/reflect.c index 6a0dda06d8..0b1dbf7fd3 100644 --- a/test/battle/move_effect_secondary/reflect.c +++ b/test/battle/move_effect_secondary/reflect.c @@ -16,7 +16,10 @@ SINGLE_BATTLE_TEST("Baddy Bad sets up Reflect when it was succesful") PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { MOVE(player, MOVE_BADDY_BAD, hit: moveSuccess); } + TURN { + MOVE(opponent, MOVE_SAND_ATTACK); + MOVE(player, MOVE_BADDY_BAD, hit: moveSuccess); + } } SCENE { if (moveSuccess == TRUE) { diff --git a/test/battle/status1/freeze.c b/test/battle/status1/freeze.c index f363ab9e35..12104438ac 100644 --- a/test/battle/status1/freeze.c +++ b/test/battle/status1/freeze.c @@ -61,3 +61,20 @@ SINGLE_BATTLE_TEST("Freeze isn't thawed if opponent is asleep during thawing att } } } + +SINGLE_BATTLE_TEST("Freeze isn't thawed if opponent is asleep during thawing attack when using Scald") +{ + PASSES_RANDOMLY(80, 100, RNG_FROZEN); + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_FREEZE); } + OPPONENT(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); } + } WHEN { + TURN { MOVE(opponent, MOVE_SCALD); MOVE(player, MOVE_CELEBRATE); } + } SCENE { + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCALD, opponent); + MESSAGE("Wobbuffet thawed out!"); + STATUS_ICON(player, none: TRUE); + } + } +} diff --git a/test/test_runner_battle.c b/test/test_runner_battle.c index b0619505f6..627273ec7f 100644 --- a/test/test_runner_battle.c +++ b/test/test_runner_battle.c @@ -2034,16 +2034,16 @@ s32 MoveGetTarget(s32 battlerId, u32 moveId, struct MoveContext *ctx, u32 source } else { - const struct MoveInfo *move = &gMovesInfo[moveId]; - if (move->target == MOVE_TARGET_RANDOM - || move->target == MOVE_TARGET_BOTH - || move->target == MOVE_TARGET_DEPENDS - || move->target == MOVE_TARGET_FOES_AND_ALLY - || move->target == MOVE_TARGET_OPPONENTS_FIELD) + u32 moveTarget = GetMoveTarget(moveId); + if (moveTarget == MOVE_TARGET_RANDOM + || moveTarget == MOVE_TARGET_BOTH + || moveTarget == MOVE_TARGET_DEPENDS + || moveTarget == MOVE_TARGET_FOES_AND_ALLY + || moveTarget == MOVE_TARGET_OPPONENTS_FIELD) { target = BATTLE_OPPOSITE(battlerId); } - else if (move->target == MOVE_TARGET_SELECTED || move->target == MOVE_TARGET_OPPONENT) + else if (moveTarget == MOVE_TARGET_SELECTED || moveTarget == MOVE_TARGET_OPPONENT) { // In AI Doubles not specified target allows any target for EXPECT_MOVE. if (GetBattleTest()->type != BATTLE_TEST_AI_DOUBLES) @@ -2053,11 +2053,11 @@ s32 MoveGetTarget(s32 battlerId, u32 moveId, struct MoveContext *ctx, u32 source target = BATTLE_OPPOSITE(battlerId); } - else if (move->target == MOVE_TARGET_USER || move->target == MOVE_TARGET_ALL_BATTLERS) + else if (moveTarget == MOVE_TARGET_USER || moveTarget == MOVE_TARGET_ALL_BATTLERS) { target = battlerId; } - else if (move->target == MOVE_TARGET_ALLY) + else if (moveTarget == MOVE_TARGET_ALLY) { target = BATTLE_PARTNER(battlerId); }