diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 8b42801bc0..094cc870a3 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -5660,13 +5660,13 @@ BattleScript_MoveUsedUnfrostbite:: BattleScript_DefrostedViaFireMove:: printstring STRINGID_PKMNWASDEFROSTED waitmessage B_WAIT_TIME_LONG - updatestatusicon BS_TARGET + updatestatusicon BS_SCRIPTING return BattleScript_FrostbiteHealedViaFireMove:: printstring STRINGID_PKMNFROSTBITEHEALED waitmessage B_WAIT_TIME_LONG - updatestatusicon BS_TARGET + updatestatusicon BS_SCRIPTING return BattleScript_MoveUsedIsParalyzed:: diff --git a/include/battle_script_commands.h b/include/battle_script_commands.h index b67c2888a7..19c3ca4d98 100644 --- a/include/battle_script_commands.h +++ b/include/battle_script_commands.h @@ -68,7 +68,7 @@ bool32 ProteanTryChangeType(enum BattlerId battler, enum Ability ability, enum M u8 GetFirstFaintedPartyIndex(enum BattlerId battler); void SaveBattlerTarget(enum BattlerId battler); void SaveBattlerAttacker(enum BattlerId battler); -bool32 CanBurnHitThaw(enum Move move); +bool32 CanBurnHitThaw(enum Ability abilityAtk, enum Move move); extern void (*const gBattleScriptingCommandsTable[])(void); extern const struct StatFractions gAccuracyStageRatios[]; diff --git a/include/constants/battle_move_resolution.h b/include/constants/battle_move_resolution.h index 8d2985df66..5d9a28ed02 100644 --- a/include/constants/battle_move_resolution.h +++ b/include/constants/battle_move_resolution.h @@ -101,14 +101,14 @@ enum MoveEndState MOVEEND_SKY_DROP_CONFUSE, MOVEEND_UPDATE_LAST_MOVES, MOVEEND_MIRROR_MOVE, - MOVEEND_DEFROST, MOVEEND_NEXT_TARGET, // Everything up until here is handled for each strike of a spread move MOVEEND_HP_THRESHOLD_ITEMS_TARGET, // Activation only during a multi hit move / ability (Parental Bond) MOVEEND_MULTIHIT_MOVE, + MOVEEND_DEFROST, + MOVEEND_SHEER_FORCE, // If move is Sheer Force affected, skip to Hit Escape + One MOVEEND_MOVE_BLOCK, MOVEEND_ITEM_EFFECTS_ATTACKER_2, MOVEEND_ABILITY_EFFECT_FOES_FAINTED, // Moxie-like abilities / Battle Bond / Magician - MOVEEND_SHEER_FORCE, // If move is Sheer Force affected, skip to Hit Escape + One MOVEEND_SHELL_TRAP, MOVEEND_COLOR_CHANGE, // Color Change / Berserk / Anger Shell MOVEEND_KEE_MARANGA_HP_THRESHOLD_ITEM_TARGET, @@ -116,14 +116,14 @@ enum MoveEndState MOVEEND_LIFE_ORB_SHELL_BELL, MOVEEND_FORM_CHANGE, MOVEEND_EMERGENCY_EXIT, - MOVEEND_EJECT_PACK, MOVEEND_HIT_ESCAPE, + MOVEEND_PICKPOCKET, MOVEEND_ITEMS_EFFECTS_ALL, MOVEEND_WHITE_HERB, MOVEEND_OPPORTUNIST, MOVEEND_MIRROR_HERB, MOVEEND_THIRD_MOVE_BLOCK, - MOVEEND_PICKPOCKET, + MOVEEND_EJECT_PACK, MOVEEND_CLEAR_BITS, MOVEEND_DANCER, MOVEEND_PURSUIT_NEXT_ACTION, diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 94b359cfb0..e2290636ab 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -1203,13 +1203,13 @@ static s32 AI_CheckBadMove(enum BattlerId battlerAtk, enum BattlerId battlerDef, } // Don't use anything but super effective thawing moves if target is frozen if any other attack available - if (((GetMoveType(move) == TYPE_FIRE && GetMovePower(move) != 0) || CanBurnHitThaw(move)) && effectiveness < UQ_4_12(2.0) && (gBattleMons[battlerDef].status1 & STATUS1_ICY_ANY)) + if (((GetMoveType(move) == TYPE_FIRE && GetMovePower(move) != 0) || CanBurnHitThaw(abilityAtk, move)) && effectiveness < UQ_4_12(2.0) && (gBattleMons[battlerDef].status1 & STATUS1_ICY_ANY)) { enum Move aiMove; for (u32 moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++) { aiMove = gBattleMons[battlerAtk].moves[moveIndex]; - if (GetMoveType(aiMove) != TYPE_FIRE && !CanBurnHitThaw(aiMove) && GetMovePower(gBattleMons[battlerAtk].moves[moveIndex]) != 0) + if (GetMoveType(aiMove) != TYPE_FIRE && !CanBurnHitThaw(abilityAtk, aiMove) && GetMovePower(gBattleMons[battlerAtk].moves[moveIndex]) != 0) { ADJUST_SCORE(-1); break; diff --git a/src/battle_message.c b/src/battle_message.c index 695890d019..a4d95f2cb4 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -229,7 +229,7 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_PKMNWASFROZEN] = COMPOUND_STRING("{B_EFF_NAME_WITH_PREFIX} was frozen solid!"), [STRINGID_PKMNFROZENBY] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_BUFF1} froze {B_EFF_NAME_WITH_PREFIX2} solid!"), //not in gen 5+, ability popup [STRINGID_PKMNISFROZEN] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is frozen solid!"), - [STRINGID_PKMNWASDEFROSTED] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} thawed out!"), + [STRINGID_PKMNWASDEFROSTED] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} thawed out!"), [STRINGID_PKMNWASDEFROSTED2] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} thawed out!"), [STRINGID_PKMNWASDEFROSTEDBY] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_CURRENT_MOVE} melted the ice!"), [STRINGID_PKMNWASPARALYZED] = COMPOUND_STRING("{B_EFF_NAME_WITH_PREFIX} is paralyzed, so it may be unable to move!"), @@ -805,7 +805,7 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_PKMNGOTFROSTBITE] = COMPOUND_STRING("{B_EFF_NAME_WITH_PREFIX} got frostbite!"), [STRINGID_PKMNSITEMHEALEDFROSTBITE] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_LAST_ITEM} cured its frostbite!"), [STRINGID_ATTACKERHEALEDITSFROSTBITE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} cured its frostbite through sheer determination so you wouldn't worry!"), - [STRINGID_PKMNFROSTBITEHEALED] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s frostbite was cured!"), + [STRINGID_PKMNFROSTBITEHEALED] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s frostbite was cured!"), [STRINGID_PKMNFROSTBITEHEALED2] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s frostbite was cured!"), [STRINGID_PKMNFROSTBITEHEALEDBY] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_CURRENT_MOVE} cured its frostbite!"), [STRINGID_MIRRORHERBCOPIED] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} used its Mirror Herb to mirror its opponent's stat changes!"), diff --git a/src/battle_move_resolution.c b/src/battle_move_resolution.c index 75ae68a500..636c9df33d 100644 --- a/src/battle_move_resolution.c +++ b/src/battle_move_resolution.c @@ -2679,41 +2679,6 @@ static enum MoveEndResult MoveEndMirrorMove(void) return MOVEEND_RESULT_CONTINUE; } -static enum MoveEndResult MoveEndDefrost(void) -{ - enum MoveEndResult result = MOVEEND_RESULT_CONTINUE; - - if (gBattleMons[gBattlerTarget].status1 & STATUS1_FREEZE - && IsBattlerTurnDamaged(gBattlerTarget) - && IsBattlerAlive(gBattlerTarget) - && gBattlerAttacker != gBattlerTarget - && (GetBattleMoveType(gCurrentMove) == TYPE_FIRE || CanBurnHitThaw(gCurrentMove)) - && !IsBattlerUnaffectedByMove(gBattlerTarget)) - { - gBattleMons[gBattlerTarget].status1 &= ~STATUS1_FREEZE; - BtlController_EmitSetMonData(gBattlerTarget, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, sizeof(gBattleMons[gBattlerTarget].status1), &gBattleMons[gBattlerTarget].status1); - MarkBattlerForControllerExec(gBattlerTarget); - BattleScriptCall(BattleScript_DefrostedViaFireMove); - result = MOVEEND_RESULT_RUN_SCRIPT; - } - else if (gBattleMons[gBattlerTarget].status1 & STATUS1_FROSTBITE - && IsBattlerTurnDamaged(gBattlerTarget) - && IsBattlerAlive(gBattlerTarget) - && gBattlerAttacker != gBattlerTarget - && MoveThawsUser(GetOriginallyUsedMove(gChosenMove)) - && !IsBattlerUnaffectedByMove(gBattlerTarget)) - { - gBattleMons[gBattlerTarget].status1 &= ~STATUS1_FROSTBITE; - BtlController_EmitSetMonData(gBattlerTarget, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, sizeof(gBattleMons[gBattlerTarget].status1), &gBattleMons[gBattlerTarget].status1); - MarkBattlerForControllerExec(gBattlerTarget); - BattleScriptCall(BattleScript_FrostbiteHealedViaFireMove); - result = MOVEEND_RESULT_RUN_SCRIPT; - } - - gBattleScripting.moveendState++; - return result; -} - static enum MoveEndResult MoveEndNextTarget(void) { enum MoveTarget moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove); @@ -2859,6 +2824,70 @@ static enum MoveEndResult MoveEndMultihitMove(void) return result; } +static void DefrostBattler(enum BattlerId battler, u32 status) +{ + gBattleScripting.battler = battler; + gBattleMons[battler].status1 &= ~status; + BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, sizeof(gBattleMons[battler].status1), &gBattleMons[battler].status1); + MarkBattlerForControllerExec(battler); +} + +static enum MoveEndResult MoveEndDefrost(void) +{ + enum Ability abilityAtk = GetBattlerAbility(gBattlerAttacker); + + while (gBattleStruct->eventState.moveEndBattler < gBattlersCount) + { + enum BattlerId battler = gBattleStruct->eventState.moveEndBattler++; + + if (battler == gBattlerAttacker) + continue; + + if (gBattleMons[battler].status1 & STATUS1_FREEZE + && IsBattlerTurnDamaged(battler) + && IsBattlerAlive(battler) + && GetBattleMoveType(gCurrentMove) == TYPE_FIRE) + { + DefrostBattler(battler, STATUS1_FREEZE); + BattleScriptCall(BattleScript_DefrostedViaFireMove); + return MOVEEND_RESULT_RUN_SCRIPT; + } + else if (gBattleMons[battler].status1 & STATUS1_FREEZE + && IsBattlerTurnDamaged(battler) + && IsBattlerAlive(battler) + && IsBattlerAlive(gBattlerAttacker) + && CanBurnHitThaw(abilityAtk, gCurrentMove)) + { + DefrostBattler(battler, STATUS1_FREEZE); + BattleScriptCall(BattleScript_DefrostedViaFireMove); + return MOVEEND_RESULT_RUN_SCRIPT; + } + else if (gBattleMons[battler].status1 & STATUS1_FROSTBITE + && IsBattlerTurnDamaged(battler) + && IsBattlerAlive(battler) + && MoveThawsUser(GetOriginallyUsedMove(gChosenMove))) + { + DefrostBattler(battler, STATUS1_FROSTBITE); + BattleScriptCall(BattleScript_FrostbiteHealedViaFireMove); + return MOVEEND_RESULT_RUN_SCRIPT; + } + } + + gBattleStruct->eventState.moveEndBattler = 0; + gBattleScripting.moveendState++; + return MOVEEND_RESULT_CONTINUE; +} + +static enum MoveEndResult MoveEndSheerForce(void) +{ + if (IsSheerForceAffected(gCurrentMove, GetBattlerAbility(gBattlerAttacker))) + gBattleScripting.moveendState = MOVEEND_ITEMS_EFFECTS_ALL; + else + gBattleScripting.moveendState++; + + return MOVEEND_RESULT_CONTINUE; +} + static enum MoveEndResult MoveEndMoveBlock(void) { enum MoveEndResult result = MOVEEND_RESULT_CONTINUE; @@ -3142,16 +3171,6 @@ static enum MoveEndResult MoveEndAbilityEffectFoesFainted(void) return result; } -static enum MoveEndResult MoveEndSheerForce(void) -{ - if (IsSheerForceAffected(gCurrentMove, GetBattlerAbility(gBattlerAttacker))) - gBattleScripting.moveendState = MOVEEND_EJECT_PACK; - else - gBattleScripting.moveendState++; - - return MOVEEND_RESULT_CONTINUE; -} - static enum MoveEndResult MoveEndShellTrap(void) { for (enum BattlerId battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) @@ -3374,68 +3393,6 @@ static enum MoveEndResult MoveEndEmergencyExit(void) return result; } -static inline bool32 CanEjectPackTrigger(enum BattlerId battlerAtk, enum BattlerId battlerDef, enum BattleMoveEffects moveEffect) -{ - if (gBattleMons[battlerDef].volatiles.tryEjectPack - && GetBattlerHoldEffect(battlerDef) == HOLD_EFFECT_EJECT_PACK - && IsBattlerAlive(battlerDef) - && CountUsablePartyMons(battlerDef) > 0 - && !gProtectStructs[battlerDef].disableEjectPack - && !(moveEffect == EFFECT_HIT_SWITCH_TARGET && CanBattlerSwitch(battlerAtk)) - && !(moveEffect == EFFECT_PARTING_SHOT && CanBattlerSwitch(battlerAtk))) - return TRUE; - return FALSE; -} - -static enum MoveEndResult MoveEndEjectPack(void) -{ - enum MoveEndResult result = MOVEEND_RESULT_CONTINUE; - u32 ejectPackBattlers = 0; - u32 numEjectPackBattlers = 0; - - // Because sorting the battlers by speed takes lots of cycles, it's better to just check if any of the battlers has the Eject items. - for (enum BattlerId i = 0; i < gBattlersCount; i++) - { - if (CanEjectPackTrigger(gBattlerAttacker, i, GetMoveEffect(gCurrentMove))) - { - ejectPackBattlers |= 1u << i; - numEjectPackBattlers++; - } - } - - if (numEjectPackBattlers == 0) - { - gBattleScripting.moveendState++; - return result; - } - - enum BattlerId battlers[MAX_BATTLERS_COUNT] = {0, 1, 2, 3}; - if (numEjectPackBattlers > 1) - SortBattlersBySpeed(battlers, FALSE); - - for (enum BattlerId i = 0; i < gBattlersCount; i++) - gBattleMons[i].volatiles.tryEjectPack = FALSE; - - for (u32 i = 0; i < gBattlersCount; i++) - { - enum BattlerId battler = battlers[i]; - - if (!(ejectPackBattlers & 1u << battler)) - continue; - - gBattleScripting.battler = battler; - gLastUsedItem = gBattleMons[battler].item; - gBattleStruct->battlerState[battler].usedEjectItem = TRUE; - BattleScriptCall(BattleScript_EjectPackActivates); - gAiLogicData->ejectPackSwitch = TRUE; - result = MOVEEND_RESULT_RUN_SCRIPT; - break; // Only the fastest Eject item activates - } - - gBattleScripting.moveendState++; - return result; -} - static enum MoveEndResult MoveEndHitEscape(void) { enum MoveEndResult result = MOVEEND_RESULT_CONTINUE; @@ -3454,6 +3411,46 @@ static enum MoveEndResult MoveEndHitEscape(void) return result; } +static enum MoveEndResult MoveEndPickpocket(void) +{ + enum MoveEndResult result = MOVEEND_RESULT_CONTINUE; + + if (IsBattlerAlive(gBattlerAttacker) + && gBattleMons[gBattlerAttacker].item != ITEM_NONE + && !GetBattlerPartyState(gBattlerAttacker)->isKnockedOff) // Gen3 edge case where the knocked of item was not removed + { + enum BattlerId battlers[MAX_BATTLERS_COUNT] = {0, 1, 2, 3}; + SortBattlersBySpeed(battlers, FALSE); // Pickpocket activates for fastest mon without item + for (u32 i = 0; i < gBattlersCount; i++) + { + enum BattlerId battlerDef = battlers[i]; + if (battlerDef != gBattlerAttacker + && !IsBattlerUnaffectedByMove(battlerDef) + && GetBattlerAbility(battlerDef) == ABILITY_PICKPOCKET + && IsMoveMakingContact(gBattlerAttacker, battlerDef, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), gCurrentMove) + && IsBattlerTurnDamaged(battlerDef) + && !DoesSubstituteBlockMove(gBattlerAttacker, battlerDef, gCurrentMove) + && IsBattlerAlive(battlerDef) + && gBattleMons[battlerDef].item == ITEM_NONE + && CanStealItem(battlerDef, gBattlerAttacker, gBattleMons[gBattlerAttacker].item)) + { + gBattlerTarget = gBattlerAbility = battlerDef; + // Battle scripting is super brittle so we shall do the item exchange now (if possible) + if (GetBattlerAbility(gBattlerAttacker) != ABILITY_STICKY_HOLD) + StealTargetItem(battlerDef, gBattlerAttacker); // Target takes attacker's item + + gEffectBattler = gBattlerAttacker; + BattleScriptCall(BattleScript_Pickpocket); // Includes sticky hold check to print separate string + result = MOVEEND_RESULT_RUN_SCRIPT; + break; // Pickpocket activates on fastest mon, so exit loop. + } + } + } + + gBattleScripting.moveendState++; + return result; +} + static enum MoveEndResult MoveEndItemsEffectsAll(void) { while (gBattleStruct->eventState.moveEndBattler < gBattlersCount) @@ -3574,42 +3571,64 @@ static enum MoveEndResult MoveEndThirdMoveBlock(void) return result; } -static enum MoveEndResult MoveEndPickpocket(void) +static inline bool32 CanEjectPackTrigger(enum BattlerId battlerAtk, enum BattlerId battlerDef, enum BattleMoveEffects moveEffect) +{ + if (gBattleMons[battlerDef].volatiles.tryEjectPack + && GetBattlerHoldEffect(battlerDef) == HOLD_EFFECT_EJECT_PACK + && IsBattlerAlive(battlerDef) + && CountUsablePartyMons(battlerDef) > 0 + && !gProtectStructs[battlerDef].disableEjectPack + && !(moveEffect == EFFECT_HIT_SWITCH_TARGET && CanBattlerSwitch(battlerAtk)) + && !(moveEffect == EFFECT_PARTING_SHOT && CanBattlerSwitch(battlerAtk))) + return TRUE; + return FALSE; +} + +static enum MoveEndResult MoveEndEjectPack(void) { enum MoveEndResult result = MOVEEND_RESULT_CONTINUE; + u32 ejectPackBattlers = 0; + u32 numEjectPackBattlers = 0; - if (IsBattlerAlive(gBattlerAttacker) - && gBattleMons[gBattlerAttacker].item != ITEM_NONE - && !GetBattlerPartyState(gBattlerAttacker)->isKnockedOff) // Gen3 edge case where the knocked of item was not removed + // Because sorting the battlers by speed takes lots of cycles, it's better to just check if any of the battlers has the Eject items. + for (enum BattlerId i = 0; i < gBattlersCount; i++) { - enum BattlerId battlers[MAX_BATTLERS_COUNT] = {0, 1, 2, 3}; - SortBattlersBySpeed(battlers, FALSE); // Pickpocket activates for fastest mon without item - for (u32 i = 0; i < gBattlersCount; i++) + if (CanEjectPackTrigger(gBattlerAttacker, i, GetMoveEffect(gCurrentMove))) { - enum BattlerId battlerDef = battlers[i]; - if (battlerDef != gBattlerAttacker - && !IsBattlerUnaffectedByMove(battlerDef) - && GetBattlerAbility(battlerDef) == ABILITY_PICKPOCKET - && IsMoveMakingContact(gBattlerAttacker, battlerDef, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), gCurrentMove) - && IsBattlerTurnDamaged(battlerDef) - && !DoesSubstituteBlockMove(gBattlerAttacker, battlerDef, gCurrentMove) - && IsBattlerAlive(battlerDef) - && gBattleMons[battlerDef].item == ITEM_NONE - && CanStealItem(battlerDef, gBattlerAttacker, gBattleMons[gBattlerAttacker].item)) - { - gBattlerTarget = gBattlerAbility = battlerDef; - // Battle scripting is super brittle so we shall do the item exchange now (if possible) - if (GetBattlerAbility(gBattlerAttacker) != ABILITY_STICKY_HOLD) - StealTargetItem(battlerDef, gBattlerAttacker); // Target takes attacker's item - - gEffectBattler = gBattlerAttacker; - BattleScriptCall(BattleScript_Pickpocket); // Includes sticky hold check to print separate string - result = MOVEEND_RESULT_RUN_SCRIPT; - break; // Pickpocket activates on fastest mon, so exit loop. - } + ejectPackBattlers |= 1u << i; + numEjectPackBattlers++; } } + if (numEjectPackBattlers == 0) + { + gBattleScripting.moveendState++; + return result; + } + + enum BattlerId battlers[MAX_BATTLERS_COUNT] = {0, 1, 2, 3}; + if (numEjectPackBattlers > 1) + SortBattlersBySpeed(battlers, FALSE); + + for (enum BattlerId i = 0; i < gBattlersCount; i++) + gBattleMons[i].volatiles.tryEjectPack = FALSE; + + for (u32 i = 0; i < gBattlersCount; i++) + { + enum BattlerId battler = battlers[i]; + + if (!(ejectPackBattlers & 1u << battler)) + continue; + + gBattleScripting.battler = battler; + gLastUsedItem = gBattleMons[battler].item; + gBattleStruct->battlerState[battler].usedEjectItem = TRUE; + BattleScriptCall(BattleScript_EjectPackActivates); + gAiLogicData->ejectPackSwitch = TRUE; + result = MOVEEND_RESULT_RUN_SCRIPT; + break; // Only the fastest Eject item activates + } + gBattleScripting.moveendState++; return result; } @@ -3803,14 +3822,14 @@ static enum MoveEndResult (*const sMoveEndHandlers[])(void) = [MOVEEND_SKY_DROP_CONFUSE] = MoveEndSkyDropConfuse, [MOVEEND_UPDATE_LAST_MOVES] = MoveEndUpdateLastMoves, [MOVEEND_MIRROR_MOVE] = MoveEndMirrorMove, - [MOVEEND_DEFROST] = MoveEndDefrost, [MOVEEND_NEXT_TARGET] = MoveEndNextTarget, [MOVEEND_HP_THRESHOLD_ITEMS_TARGET] = MoveEndHpThresholdItemsTarget, [MOVEEND_MULTIHIT_MOVE] = MoveEndMultihitMove, + [MOVEEND_DEFROST] = MoveEndDefrost, + [MOVEEND_SHEER_FORCE] = MoveEndSheerForce, [MOVEEND_MOVE_BLOCK] = MoveEndMoveBlock, [MOVEEND_ITEM_EFFECTS_ATTACKER_2] = MoveEndItemEffectsAttacker2, [MOVEEND_ABILITY_EFFECT_FOES_FAINTED] = MoveEndAbilityEffectFoesFainted, - [MOVEEND_SHEER_FORCE] = MoveEndSheerForce, [MOVEEND_SHELL_TRAP] = MoveEndShellTrap, [MOVEEND_COLOR_CHANGE] = MoveEndColorChange, [MOVEEND_KEE_MARANGA_HP_THRESHOLD_ITEM_TARGET] = MoveEndKeeMarangaHpThresholdItemTarget, diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 9a2ce15335..6982c7c086 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -11650,11 +11650,11 @@ static bool32 CanAbilityPreventStatLoss(enum Ability abilityDef) return FALSE; } -bool32 CanBurnHitThaw(enum Move move) +bool32 CanBurnHitThaw(enum Ability abilityAtk, enum Move move) { u8 i; - if (GetConfig(CONFIG_BURN_HIT_THAW) >= GEN_6) + if (GetConfig(CONFIG_BURN_HIT_THAW) >= GEN_6 && abilityAtk != ABILITY_SHEER_FORCE) { u32 numAdditionalEffects = GetMoveAdditionalEffectCount(move); for (i = 0; i < numAdditionalEffects; i++) diff --git a/test/battle/move_effect/rapid_spin.c b/test/battle/move_effect/rapid_spin.c index 852b4d69a7..0ef6cce558 100644 --- a/test/battle/move_effect/rapid_spin.c +++ b/test/battle/move_effect/rapid_spin.c @@ -92,3 +92,31 @@ SINGLE_BATTLE_TEST("Rapid Spin blows away all hazards") EXPECT_EQ(gBattleStruct->hazardsQueue[0][5], HAZARDS_NONE); } } + +TO_DO_BATTLE_TEST("Rapid Spin blows away Wrap, hazards, but doesn't raise Speed when Sheer Force boosted (Gen 8)"); + +SINGLE_BATTLE_TEST("Rapid Spin doesn't blow away Wrap, hazards or raise Speed when Sheer Force boosted (Gen 9+)") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_RAPID_SPIN) == EFFECT_RAPID_SPIN); + #if B_SPEED_BUFFING_RAPID_SPIN >= GEN_8 + ASSUME(MoveHasAdditionalEffectSelf(MOVE_RAPID_SPIN, MOVE_EFFECT_SPD_PLUS_1) == TRUE); + #endif + PLAYER(SPECIES_TAUROS) { Ability(ABILITY_SHEER_FORCE); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_WRAP); } + TURN { MOVE(opponent, MOVE_STEALTH_ROCK); MOVE(player, MOVE_RAPID_SPIN); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_RAPID_SPIN, player); + NONE_OF { + #if B_SPEED_BUFFING_RAPID_SPIN >= GEN_8 + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Tauros's Speed rose!"); + #endif + MESSAGE("Tauros got free of the opposing Wobbuffet's Wrap!"); + MESSAGE("Tauros blew away Stealth Rock!"); + } + } +} diff --git a/test/battle/status1/freeze.c b/test/battle/status1/freeze.c index 89f0b91100..d07e0da28f 100644 --- a/test/battle/status1/freeze.c +++ b/test/battle/status1/freeze.c @@ -23,9 +23,60 @@ SINGLE_BATTLE_TEST("Freeze is thawed by opponent's Fire-type attacks") } WHEN { TURN { MOVE(opponent, MOVE_EMBER); MOVE(player, MOVE_CELEBRATE); } } SCENE { - MESSAGE("The opposing Wobbuffet used Ember!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, opponent); MESSAGE("Wobbuffet thawed out!"); STATUS_ICON(player, none: TRUE); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + } +} + +SINGLE_BATTLE_TEST("Freeze is thawed by opponent's Fire-type attacks even if Sheer Force affected") +{ + GIVEN { + ASSUME(GetMoveType(MOVE_EMBER) == TYPE_FIRE); + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_FREEZE); } + OPPONENT(SPECIES_TAUROS) { Ability(ABILITY_SHEER_FORCE); } + } WHEN { + TURN { MOVE(opponent, MOVE_EMBER); MOVE(player, MOVE_CELEBRATE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, opponent); + MESSAGE("Wobbuffet thawed out!"); + STATUS_ICON(player, none: TRUE); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + } +} + +SINGLE_BATTLE_TEST("Freeze is thawed by opponent's attack that can burn (Gen 6+)") +{ + GIVEN { + WITH_CONFIG(CONFIG_BURN_HIT_THAW, GEN_6); + ASSUME(MoveHasAdditionalEffect(MOVE_SCALD, MOVE_EFFECT_BURN)); + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_FREEZE); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SCALD); MOVE(player, MOVE_CELEBRATE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCALD, opponent); + MESSAGE("Wobbuffet thawed out!"); + STATUS_ICON(player, none: TRUE); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + } +} +SINGLE_BATTLE_TEST("Freeze isn't thawed by opponent's attack that can burn if Sheer Force affected (Gen 6+)") +{ + GIVEN { + WITH_CONFIG(CONFIG_BURN_HIT_THAW, GEN_6); + ASSUME(MoveHasAdditionalEffect(MOVE_SCALD, MOVE_EFFECT_BURN)); + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_FREEZE); } + OPPONENT(SPECIES_TAUROS) { Ability(ABILITY_SHEER_FORCE); } + } WHEN { + TURN { MOVE(opponent, MOVE_SCALD); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCALD, opponent); + NONE_OF { + MESSAGE("Wobbuffet thawed out!"); + STATUS_ICON(player, none: TRUE); + } } }