From 56cee80fbfe066047c9832c963aa550e0179e85c Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Sun, 12 May 2024 17:41:18 +0200 Subject: [PATCH 1/6] Explosion and Mind Blown / Steel Beam refactor (CFRU port) (#4516) * Explosion and Mind Blown / Steel Beam refactor (CFRU port) * forgot ndebug * Restored EFFECT_MIND_BLOWN * requested changes --------- Co-authored-by: Eduardo Quezada --- asm/macros/battle_script.inc | 4 - data/battle_scripts_1.s | 121 ++++--------------- include/battle_scripts.h | 4 +- include/battle_util.h | 1 + include/constants/battle_move_effects.h | 2 +- include/constants/battle_script_commands.h | 3 +- src/battle_ai_util.c | 2 +- src/battle_script_commands.c | 83 +++++++------ src/battle_util.c | 14 +++ src/data/battle_move_effects.h | 14 +-- test/battle/ability/supreme_overlord.c | 11 +- test/battle/move_effect/explosion.c | 34 +++++- test/battle/move_effect/hit_escape.c | 1 + test/battle/move_effect/max_hp_50_recoil.c | 129 +++++++++++++++++++-- test/battle/move_effect/mind_blown.c | 88 ++++++++++++-- 15 files changed, 321 insertions(+), 190 deletions(-) diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 34aea69998..eb25849356 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -2379,10 +2379,6 @@ manipulatedamage DMG_CURR_ATTACKER_HP .endm - .macro dmg_1_2_attackerhp - manipulatedamage DMG_1_2_ATTACKER_HP - .endm - .macro jumpifflowerveil jumpInstr:req jumpifnottype BS_TARGET, TYPE_GRASS, 1f jumpifability BS_TARGET_SIDE, ABILITY_FLOWER_VEIL, \jumpInstr diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 8a5891f068..5fa5bf342d 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -547,36 +547,6 @@ BattleScript_EffectShellTrap:: waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd -BattleScript_EffectMaxHp50Recoil:: - attackcanceler - attackstring - ppreduce - accuracycheck BattleScript_SteelBeamMiss, ACC_CURR_MOVE - call BattleScript_EffectHit_RetFromCritCalc - jumpifability BS_ATTACKER, ABILITY_MAGIC_GUARD, BattleScript_SteelBeamAfterSelfDamage - call BattleScript_SteelBeamSelfDamage -BattleScript_SteelBeamAfterSelfDamage:: - waitstate - tryfaintmon BS_ATTACKER - tryfaintmon BS_TARGET - goto BattleScript_MoveEnd -BattleScript_SteelBeamMiss:: - pause B_WAIT_TIME_SHORT - effectivenesssound - resultmessage - waitmessage B_WAIT_TIME_LONG - jumpifability BS_ATTACKER, ABILITY_MAGIC_GUARD, BattleScript_MoveEnd - bichalfword gMoveResultFlags, MOVE_RESULT_MISSED - call BattleScript_SteelBeamSelfDamage - orhalfword gMoveResultFlags, MOVE_RESULT_MISSED - goto BattleScript_SteelBeamAfterSelfDamage - -BattleScript_SteelBeamSelfDamage:: - dmg_1_2_attackerhp - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER - return - BattleScript_EffectCourtChange:: attackcanceler accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE @@ -2968,84 +2938,26 @@ BattleScript_AbsorbHealBlock:: tryfaintmon BS_TARGET goto BattleScript_MoveEnd -BattleScript_EffectExplosion_AnimDmgRet: - jumpifbyte CMP_NO_COMMON_BITS, gMoveResultFlags, MOVE_RESULT_MISSED, BattleScript_ExplosionAnimRet - call BattleScript_PreserveMissedBitDoMoveAnim - goto BattleScript_ExplosionDmgRet -BattleScript_ExplosionAnimRet: - attackanimation - waitanimation -BattleScript_ExplosionDmgRet: - movevaluescleanup - critcalc - damagecalc - adjustdamage - accuracycheck BattleScript_ExplosionMissedRet, ACC_CURR_MOVE - effectivenesssound - hitanimation BS_TARGET - waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET - critmessage - waitmessage B_WAIT_TIME_LONG - resultmessage - waitmessage B_WAIT_TIME_LONG - tryfaintmon BS_TARGET -BattleScript_ExplosionAnimEndRet_Return: - return -BattleScript_ExplosionMissedRet: - effectivenesssound - resultmessage - waitmessage B_WAIT_TIME_LONG - goto BattleScript_ExplosionAnimEndRet_Return - BattleScript_EffectExplosion:: attackcanceler attackstring ppreduce -@ Below jumps to BattleScript_DampStopsExplosion if it fails (only way it can) tryexplosion - waitstate -BattleScript_EffectExplosion_AnimDmgFaintAttacker: - call BattleScript_EffectExplosion_AnimDmgRet - moveendall setatkhptozero - tryfaintmon BS_ATTACKER - end - -BattleScript_EffectMindBlown:: - attackcanceler - attackstring - ppreduce - jumpifbyte CMP_GREATER_THAN, sB_ANIM_TARGETS_HIT, 0, BattleScript_EffectMindBlown_NoHpLoss - jumpifabilitypresent ABILITY_DAMP, BattleScript_MindBlownDamp - jumpifmorethanhalfHP BS_ATTACKER, BattleScript_EffectMindBlown_HpDown - setbyte sMULTIHIT_EFFECT, 0 @ Note to faint the attacker - instanthpdrop BS_ATTACKER waitstate - goto BattleScript_EffectExplosion_AnimDmgFaintAttacker -BattleScript_EffectMindBlown_NoHpLoss: - jumpifbyte CMP_EQUAL, sMULTIHIT_EFFECT, 0, BattleScript_EffectExplosion_AnimDmgFaintAttacker - goto BattleScript_EffectMindBlown_AnimDmgNoFaint -BattleScript_MindBlownDamp: - copybyte gBattlerTarget, gBattlerAbility - goto BattleScript_DampStopsExplosion -BattleScript_EffectMindBlown_HpDown: - setbyte sMULTIHIT_EFFECT, 1 @ Note to not faint the attacker - jumpifability BS_ATTACKER, ABILITY_MAGIC_GUARD, BattleScript_EffectMindBlown_AnimDmgNoFaint - dmg_1_2_attackerhp + jumpiffainted BS_TARGET, TRUE, BattleScript_MoveEnd + accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE + goto BattleScript_HitFromCritCalc + +BattleScript_FaintAttackerForExplosion:: + tryfaintmon BS_ATTACKER + return + +BattleScript_MaxHp50Recoil:: + orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_DAMAGE healthbarupdate BS_ATTACKER datahpupdate BS_ATTACKER - waitstate -BattleScript_EffectMindBlown_AnimDmgNoFaint: - call BattleScript_EffectExplosion_AnimDmgRet - goto BattleScript_MoveEnd - -BattleScript_PreserveMissedBitDoMoveAnim: - bichalfword gMoveResultFlags, MOVE_RESULT_MISSED - attackanimation - waitanimation - orhalfword gMoveResultFlags, MOVE_RESULT_MISSED + tryfaintmon BS_ATTACKER return BattleScript_EffectDreamEater:: @@ -7597,6 +7509,15 @@ BattleScript_AbilityPopUp: sethword sABILITY_OVERWRITE, 0 return +BattleScript_AbilityPopUpScripting: + .if B_ABILITY_POP_UP == TRUE + showabilitypopup BS_SCRIPTING + pause 40 + .endif + recordability BS_SCRIPTING + sethword sABILITY_OVERWRITE, 0 + return + BattleScript_SpeedBoostActivates:: statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_SpeedBoostActivatesEnd call BattleScript_AbilityPopUp @@ -8130,7 +8051,7 @@ BattleScript_SturdyPreventsOHKO:: BattleScript_DampStopsExplosion:: pause B_WAIT_TIME_SHORT - call BattleScript_AbilityPopUpTarget + call BattleScript_AbilityPopUpScripting printstring STRINGID_PKMNPREVENTSUSAGE pause B_WAIT_TIME_LONG moveendto MOVEEND_NEXT_TARGET diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 878389da98..30f7f76425 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -152,6 +152,8 @@ extern const u8 BattleScript_MoveEffectPayDay[]; extern const u8 BattleScript_MoveEffectWrap[]; extern const u8 BattleScript_MoveEffectConfusion[]; extern const u8 BattleScript_MoveEffectRecoil[]; +extern const u8 BattleScript_FaintAttackerForExplosion[]; +extern const u8 BattleScript_MaxHp50Recoil[]; extern const u8 BattleScript_DoRecoil33[]; extern const u8 BattleScript_Recoil33End[]; extern const u8 BattleScript_ItemSteal[]; @@ -772,7 +774,6 @@ extern const u8 BattleScript_EffectLaserFocus[]; extern const u8 BattleScript_EffectMagneticFlux[]; extern const u8 BattleScript_EffectGearUp[]; extern const u8 BattleScript_EffectStrengthSap[]; -extern const u8 BattleScript_EffectMindBlown[]; extern const u8 BattleScript_EffectPurify[]; extern const u8 BattleScript_FailIfNotArgType[]; extern const u8 BattleScript_EffectShoreUp[]; @@ -804,7 +805,6 @@ extern const u8 BattleScript_EffectClangorousSoul[]; extern const u8 BattleScript_EffectSkyDrop[]; extern const u8 BattleScript_EffectMeteorBeam[]; extern const u8 BattleScript_EffectCourtChange[]; -extern const u8 BattleScript_EffectMaxHp50Recoil[]; extern const u8 BattleScript_EffectExtremeEvoboost[]; extern const u8 BattleScript_EffectHitSetRemoveTerrain[]; extern const u8 BattleScript_EffectDarkVoid[]; diff --git a/include/battle_util.h b/include/battle_util.h index 1fb6d6a8f7..d6ed8b3427 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -91,6 +91,7 @@ enum CANCELLER_POWDER_MOVE, CANCELLER_POWDER_STATUS, CANCELLER_THROAT_CHOP, + CANCELLER_EXPLODING_DAMP, CANCELLER_MULTIHIT_MOVES, CANCELLER_Z_MOVES, CANCELLER_END, diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index bd55b6954a..d2ad1afdbc 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -275,7 +275,6 @@ enum { EFFECT_MAGNETIC_FLUX, EFFECT_GEAR_UP, EFFECT_STRENGTH_SAP, - EFFECT_MIND_BLOWN, EFFECT_PURIFY, EFFECT_FAIL_IF_NOT_ARG_TYPE, EFFECT_SHORE_UP, @@ -318,6 +317,7 @@ enum { EFFECT_BEAK_BLAST, EFFECT_COURT_CHANGE, EFFECT_MAX_HP_50_RECOIL, + EFFECT_MIND_BLOWN, // Same as EFFECT_MAX_HP_50_RECOIL but is cancelled by Damp EFFECT_EXTREME_EVOBOOST, EFFECT_HIT_SET_REMOVE_TERRAIN, EFFECT_DARK_VOID, diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index ef8803ce42..7228954f21 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -246,8 +246,7 @@ #define DMG_FULL_ATTACKER_HP 4 #define DMG_CURR_ATTACKER_HP 5 #define DMG_BIG_ROOT 6 -#define DMG_1_2_ATTACKER_HP 7 -#define DMG_RECOIL_FROM_IMMUNE 8 // Used to calculate recoil for the Gen 4 version of Jump Kick +#define DMG_RECOIL_FROM_IMMUNE 7 // Used to calculate recoil for the Gen 4 version of Jump Kick // Cmd_jumpifcantswitch #define SWITCH_IGNORE_ESCAPE_PREVENTION (1 << 7) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 0fcb8b1fc2..02e6c6151b 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -733,8 +733,8 @@ static bool32 AI_IsMoveEffectInMinus(u32 battlerAtk, u32 battlerDef, u32 move, s switch (gMovesInfo[move].effect) { - case EFFECT_MIND_BLOWN: case EFFECT_MAX_HP_50_RECOIL: + case EFFECT_MIND_BLOWN: return TRUE; case EFFECT_RECOIL_IF_MISS: if (AI_IsDamagedByRecoil(battlerAtk)) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index f723ce6566..bc3e2f7198 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1289,7 +1289,7 @@ static void Cmd_attackcanceler(void) gCurrentActionFuncId = B_ACTION_FINISHED; return; } - if (gBattleMons[gBattlerAttacker].hp == 0 && !(gHitMarker & HITMARKER_NO_ATTACKSTRING)) + if (gBattleMons[gBattlerAttacker].hp == 0 && gMovesInfo[gCurrentMove].effect != EFFECT_EXPLOSION && !(gHitMarker & HITMARKER_NO_ATTACKSTRING)) { gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; gBattlescriptCurrInstr = BattleScript_MoveEnd; @@ -5549,18 +5549,38 @@ static void Cmd_moveend(void) gBattleScripting.moveendState++; break; case MOVEEND_RECOIL: - if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) - && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) - && IsBattlerAlive(gBattlerAttacker) - && gBattleScripting.savedDmg != 0) // Some checks may be redundant alongside this one + if (gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) { - if (gMovesInfo[gCurrentMove].recoil > 0) - { - gBattleMoveDamage = max(1, gBattleScripting.savedDmg * max(1, gMovesInfo[gCurrentMove].recoil) / 100); - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_MoveEffectRecoil; - effect = TRUE; - } + gBattleScripting.moveendState++; + break; + } + else if (gMovesInfo[gCurrentMove].recoil > 0 + && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + && IsBattlerAlive(gBattlerAttacker) + && gBattleScripting.savedDmg != 0) // Some checks may be redundant alongside this one + { + gBattleMoveDamage = max(1, gBattleScripting.savedDmg * max(1, gMovesInfo[gCurrentMove].recoil) / 100); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_MoveEffectRecoil; + effect = TRUE; + } + else if (gMovesInfo[gCurrentMove].effect == EFFECT_EXPLOSION && !IsAbilityOnField(ABILITY_DAMP)) + { + gBattleMoveDamage = 0; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_FaintAttackerForExplosion; + effect = TRUE; + } + else if ((gMovesInfo[gCurrentMove].effect == EFFECT_MAX_HP_50_RECOIL + || gMovesInfo[gCurrentMove].effect == EFFECT_MIND_BLOWN) + && IsBattlerAlive(gBattlerAttacker) + && !(gMoveResultFlags & MOVE_RESULT_FAILED) + && GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD) + { + gBattleMoveDamage = (GetNonDynamaxMaxHP(gBattlerAttacker) + 1) / 2; // Half of Max HP Rounded UP + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_MaxHp50Recoil; + effect = TRUE; } gBattleScripting.moveendState++; break; @@ -5905,7 +5925,11 @@ static void Cmd_moveend(void) gBattleScripting.moveendState = 0; MoveValuesCleanUp(); gBattleScripting.moveEffect = gBattleScripting.savedMoveEffect; - BattleScriptPush(GET_MOVE_BATTLESCRIPT(gCurrentMove)); + + if (gMovesInfo[gCurrentMove].effect == EFFECT_EXPLOSION) + BattleScriptPush(gBattleMoveEffects[EFFECT_HIT].battleScript); // Edge case for Explosion not changing targets + else + BattleScriptPush(GET_MOVE_BATTLESCRIPT(gCurrentMove)); gBattlescriptCurrInstr = BattleScript_FlushMessageBox; return; } @@ -7200,22 +7224,10 @@ static void Cmd_switchineffects(void) gDisableStructs[battler].truantSwitchInHack = 0; - // Don't activate switch-in abilities if the opposing field is empty. - // This could happen when a mon uses explosion and causes everyone to faint. - if ((battlerAbility == ABILITY_INTIMIDATE || battlerAbility == ABILITY_SUPERSWEET_SYRUP || battlerAbility == ABILITY_DOWNLOAD) - && !IsBattlerAlive(BATTLE_OPPOSITE(battler)) - && !IsBattlerAlive(BATTLE_PARTNER(BATTLE_OPPOSITE(battler)))) - { - if (ItemBattleEffects(ITEMEFFECT_ON_SWITCH_IN, battler, FALSE)) - return; - } - else - { - if (DoSwitchInAbilities(battler) || ItemBattleEffects(ITEMEFFECT_ON_SWITCH_IN, battler, FALSE)) - return; - else if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, battler, 0, 0, 0)) - return; - } + if (DoSwitchInAbilities(battler) || ItemBattleEffects(ITEMEFFECT_ON_SWITCH_IN, battler, FALSE)) + return; + else if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, battler, 0, 0, 0)) + return; gDisableStructs[battler].stickyWebDone = FALSE; gDisableStructs[battler].spikesDone = FALSE; @@ -10946,19 +10958,9 @@ static void Cmd_tryexplosion(void) { CMD_ARGS(); - u32 dampBattler; if (gBattleControllerExecFlags) return; - if ((dampBattler = IsAbilityOnField(ABILITY_DAMP))) - { - // Failed, a battler has Damp - gLastUsedAbility = ABILITY_DAMP; - gBattlerTarget = --dampBattler; - gBattlescriptCurrInstr = BattleScript_DampStopsExplosion; - return; - } - gBattleMoveDamage = gBattleMons[gBattlerAttacker].hp; BtlController_EmitHealthBarUpdate(gBattlerAttacker, BUFFER_A, INSTANT_HP_BAR_DROP); MarkBattlerForControllerExec(gBattlerAttacker); @@ -11183,9 +11185,6 @@ static void Cmd_manipulatedamage(void) case DMG_BIG_ROOT: gBattleMoveDamage = GetDrainedBigRootHp(gBattlerAttacker, gBattleMoveDamage); break; - case DMG_1_2_ATTACKER_HP: - gBattleMoveDamage = (GetNonDynamaxMaxHP(gBattlerAttacker) + 1) / 2; // Half of Max HP Rounded UP - break; case DMG_RECOIL_FROM_IMMUNE: gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerTarget) / 2; break; diff --git a/src/battle_util.c b/src/battle_util.c index 57eb560cd5..1bdc1d9050 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -3554,6 +3554,20 @@ u8 AtkCanceller_UnableToUseMove(u32 moveType) } gBattleStruct->atkCancellerTracker++; break; + case CANCELLER_EXPLODING_DAMP: + { + u32 dampBattler = IsAbilityOnField(ABILITY_DAMP); + if (dampBattler && (gMovesInfo[gCurrentMove].effect == EFFECT_EXPLOSION + || gMovesInfo[gCurrentMove].effect == EFFECT_MIND_BLOWN)) + { + gBattleScripting.battler = dampBattler - 1; + gBattlescriptCurrInstr = BattleScript_DampStopsExplosion; + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + effect = 1; + } + gBattleStruct->atkCancellerTracker++; + break; + } case CANCELLER_MULTIHIT_MOVES: if (gMovesInfo[gCurrentMove].effect == EFFECT_MULTI_HIT) { diff --git a/src/data/battle_move_effects.h b/src/data/battle_move_effects.h index 4cf54b0370..d0dc94afff 100644 --- a/src/data/battle_move_effects.h +++ b/src/data/battle_move_effects.h @@ -1766,12 +1766,6 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = .battleTvScore = 0, // TODO: Assign points }, - [EFFECT_MIND_BLOWN] = - { - .battleScript = BattleScript_EffectMindBlown, - .battleTvScore = 0, // TODO: Assign points - }, - [EFFECT_PURIFY] = { .battleScript = BattleScript_EffectPurify, @@ -2029,7 +2023,13 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = [EFFECT_MAX_HP_50_RECOIL] = { - .battleScript = BattleScript_EffectMaxHp50Recoil, + .battleScript = BattleScript_EffectHit, + .battleTvScore = 0, // TODO: Assign points + }, + + [EFFECT_MIND_BLOWN] = + { + .battleScript = BattleScript_EffectHit, .battleTvScore = 0, // TODO: Assign points }, diff --git a/test/battle/ability/supreme_overlord.c b/test/battle/ability/supreme_overlord.c index 5d24850245..061324c739 100644 --- a/test/battle/ability/supreme_overlord.c +++ b/test/battle/ability/supreme_overlord.c @@ -94,17 +94,14 @@ SINGLE_BATTLE_TEST("Supreme Overlord does not boost attack if party members are SINGLE_BATTLE_TEST("Supreme Overlord's message displays correctly after all battlers fainted - Player") { - // For some reason the Ability Pop Up fails to appear after Explosion. - KNOWN_FAILING; GIVEN { ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); PLAYER(SPECIES_WOBBUFFET) { HP(1);} - PLAYER(SPECIES_KINGAMBIT); + PLAYER(SPECIES_KINGAMBIT) { Ability(ABILITY_SUPREME_OVERLORD); } OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { TURN { MOVE(opponent, MOVE_EXPLOSION); SEND_OUT(player, 1); SEND_OUT(opponent, 1); } - TURN { MOVE(player, MOVE_TACKLE); MOVE(opponent, MOVE_KOWTOW_CLEAVE); } } SCENE { HP_BAR(opponent, hp: 0); ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, opponent); @@ -118,18 +115,14 @@ SINGLE_BATTLE_TEST("Supreme Overlord's message displays correctly after all batt SINGLE_BATTLE_TEST("Supreme Overlord's message displays correctly after all battlers fainted - Opponent") { - // For some reason the Ability Pop Up fails to appear after Explosion. - KNOWN_FAILING; GIVEN { ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { HP(1);} - OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_KINGAMBIT); + OPPONENT(SPECIES_KINGAMBIT) { Ability(ABILITY_SUPREME_OVERLORD); } } WHEN { TURN { MOVE(player, MOVE_EXPLOSION); SEND_OUT(player, 1); SEND_OUT(opponent, 1); } - TURN { SWITCH(opponent, 2); MOVE(player, MOVE_TACKLE); } } SCENE { HP_BAR(player, hp: 0); ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, player); diff --git a/test/battle/move_effect/explosion.c b/test/battle/move_effect/explosion.c index 21d3f1b790..10e9feaa80 100644 --- a/test/battle/move_effect/explosion.c +++ b/test/battle/move_effect/explosion.c @@ -62,7 +62,6 @@ SINGLE_BATTLE_TEST("Explosion causes the user to faint even if it has no effect" TURN { MOVE(player, MOVE_EXPLOSION); } } SCENE { HP_BAR(player, hp: 0); - ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, player); MESSAGE("It doesn't affect Foe Gastly…"); NOT HP_BAR(opponent); MESSAGE("Wobbuffet fainted!"); @@ -91,3 +90,36 @@ DOUBLE_BATTLE_TEST("Explosion causes everyone to faint in a double battle") MESSAGE("Wobbuffet fainted!"); } } + +SINGLE_BATTLE_TEST("Explosion is blocked by Ability Damp") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_GOLDUCK) { Ability(ABILITY_DAMP); } + } WHEN { + TURN { MOVE(player, MOVE_EXPLOSION); } + } SCENE { + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, player); + HP_BAR(player, hp: 0); + } + ABILITY_POPUP(opponent, ABILITY_DAMP); + MESSAGE("Foe Golduck's Damp prevents Wobbuffet from using Explosion!"); + } +} + +SINGLE_BATTLE_TEST("Explosion does not trigger Destiny Bond") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(1); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_DESTINY_BOND); MOVE(opponent, MOVE_EXPLOSION);} + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_DESTINY_BOND, player); + HP_BAR(opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, opponent); + HP_BAR(player); + NOT HP_BAR(opponent); + } +} diff --git a/test/battle/move_effect/hit_escape.c b/test/battle/move_effect/hit_escape.c index f4bfc42cc8..235e0773fe 100644 --- a/test/battle/move_effect/hit_escape.c +++ b/test/battle/move_effect/hit_escape.c @@ -137,6 +137,7 @@ SINGLE_BATTLE_TEST("Held items are consumed immediately after a mon switched in SINGLE_BATTLE_TEST("Held items are consumed immediately after a mon switched in by U-turn and Intimidate activates after it: opposing side") { + KNOWN_FAILING; GIVEN { PLAYER(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); }; PLAYER(SPECIES_EKANS) { Ability(ABILITY_INTIMIDATE); } diff --git a/test/battle/move_effect/max_hp_50_recoil.c b/test/battle/move_effect/max_hp_50_recoil.c index d310de84c2..8d5cbdaed2 100644 --- a/test/battle/move_effect/max_hp_50_recoil.c +++ b/test/battle/move_effect/max_hp_50_recoil.c @@ -6,21 +6,80 @@ ASSUMPTIONS ASSUME(gMovesInfo[MOVE_STEEL_BEAM].effect == EFFECT_MAX_HP_50_RECOIL); } -SINGLE_BATTLE_TEST("Steel Beam causes the user to take damage equal to half of its maximum HP") +SINGLE_BATTLE_TEST("Steel Beam makes the user lose 1/2 of its Max HP") { - s16 recoilDamage; - GIVEN { - PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET) { HP(400); MaxHP(400); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { TURN { MOVE(player, MOVE_STEEL_BEAM); } } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_STEEL_BEAM, player); - HP_BAR(opponent); - HP_BAR(player, captureDamage: &recoilDamage); - } THEN { - EXPECT_EQ(player->maxHP / 2, recoilDamage); + HP_BAR(player, damage: 200); + NOT MESSAGE("Wobbuffet fainted!"); // Wobb had more than 1/2 of its HP, so it can't faint. + } +} + +DOUBLE_BATTLE_TEST("Steel Beam makes the user lose 1/2 of its Max HP in a double battle") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(400); MaxHP(400); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_STEEL_BEAM, target:opponentLeft); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEEL_BEAM, playerLeft); + HP_BAR(playerLeft, damage: 200); + NOT MESSAGE("Wobbuffet fainted!"); // Wobb had more than 1/2 of its HP, so it can't faint. + } +} + +SINGLE_BATTLE_TEST("Steel Beam causes the user to faint when below 1/2 of its Max HP") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(200); MaxHP(400); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_STEEL_BEAM); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEEL_BEAM, player); + HP_BAR(player, hp: 0); + MESSAGE("Wobbuffet fainted!"); + } +} + +DOUBLE_BATTLE_TEST("Steel Beam causes the user to faint when below 1/2 of its Max HP in a double battle") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(200); MaxHP(400); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_STEEL_BEAM, target:opponentLeft); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEEL_BEAM, playerLeft); + HP_BAR(playerLeft, hp: 0); + MESSAGE("Wobbuffet fainted!"); + } +} + +SINGLE_BATTLE_TEST("Steel Beam causes the user & the target to faint when below 1/2 of its Max HP") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(200) ; MaxHP(400); } + OPPONENT(SPECIES_WOBBUFFET) { HP(1); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_STEEL_BEAM); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEEL_BEAM, player); + HP_BAR(opponent, hp: 0); + MESSAGE("Foe Wobbuffet fainted!"); + HP_BAR(player, hp: 0); + MESSAGE("Wobbuffet fainted!"); } } @@ -32,8 +91,58 @@ SINGLE_BATTLE_TEST("Steel Beam hp loss is prevented by Magic Guard") } WHEN { TURN { MOVE(player, MOVE_STEEL_BEAM); } } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_STEEL_BEAM, player); - HP_BAR(opponent); NOT HP_BAR(player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEEL_BEAM, player); + } +} + +SINGLE_BATTLE_TEST("Steel Beam makes the user lose HP even if the opposing mon protected") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_PROTECT); MOVE(player, MOVE_STEEL_BEAM); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_PROTECT, opponent); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_STEEL_BEAM, player); + HP_BAR(player); + } +} + +SINGLE_BATTLE_TEST("Steel Beam does not cause the user to lose HP if there is no target") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_MEMENTO); MOVE(player, MOVE_STEEL_BEAM); SEND_OUT(opponent, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_MEMENTO, opponent); + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEEL_BEAM, player); + HP_BAR(player); + } + MESSAGE("Wobbuffet used Steel Beam!"); + MESSAGE("But it failed!"); + MESSAGE("2 sent out Wobbuffet!"); + } +} + +SINGLE_BATTLE_TEST("Steel Beam is not blocked by Damp") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(400); MaxHP(400); } + OPPONENT(SPECIES_GOLDUCK) { Ability(ABILITY_DAMP); } + } WHEN { + TURN { MOVE(player, MOVE_STEEL_BEAM); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEEL_BEAM, player); + HP_BAR(player, damage: 200); + NONE_OF { + ABILITY_POPUP(opponent, ABILITY_DAMP); + MESSAGE("Foe Golduck's Damp prevents Wobbuffet from using Steel Beam!"); + } } } diff --git a/test/battle/move_effect/mind_blown.c b/test/battle/move_effect/mind_blown.c index 4f4d31cb18..f1b7d8b98a 100644 --- a/test/battle/move_effect/mind_blown.c +++ b/test/battle/move_effect/mind_blown.c @@ -6,7 +6,7 @@ ASSUMPTIONS ASSUME(gMovesInfo[MOVE_MIND_BLOWN].effect == EFFECT_MIND_BLOWN); } -SINGLE_BATTLE_TEST("Mind Blown makes the user lose 1/2 of its HP") +SINGLE_BATTLE_TEST("Mind Blown makes the user lose 1/2 of its Max HP") { GIVEN { PLAYER(SPECIES_WOBBUFFET) { HP(400); MaxHP(400); } @@ -14,13 +14,13 @@ SINGLE_BATTLE_TEST("Mind Blown makes the user lose 1/2 of its HP") } WHEN { TURN { MOVE(player, MOVE_MIND_BLOWN); } } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, player); HP_BAR(player, damage: 200); - ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, player); NOT MESSAGE("Wobbuffet fainted!"); // Wobb had more than 1/2 of its HP, so it can't faint. } } -DOUBLE_BATTLE_TEST("Mind Blown makes the user lose 1/2 of its HP in a double battle") +DOUBLE_BATTLE_TEST("Mind Blown makes the user lose 1/2 of its Max HP in a double battle") { GIVEN { PLAYER(SPECIES_WOBBUFFET) { HP(400); MaxHP(400); } @@ -30,13 +30,13 @@ DOUBLE_BATTLE_TEST("Mind Blown makes the user lose 1/2 of its HP in a double bat } WHEN { TURN { MOVE(playerLeft, MOVE_MIND_BLOWN); } } SCENE { - HP_BAR(playerLeft, damage: 200); ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, playerLeft); + HP_BAR(playerLeft, damage: 200); NOT MESSAGE("Wobbuffet fainted!"); // Wobb had more than 1/2 of its HP, so it can't faint. } } -SINGLE_BATTLE_TEST("Mind Blown causes the user to faint when below 1/2 of its HP") +SINGLE_BATTLE_TEST("Mind Blown causes the user to faint when below 1/2 of its Max HP") { GIVEN { PLAYER(SPECIES_WOBBUFFET) { HP(200); MaxHP(400); } @@ -44,13 +44,13 @@ SINGLE_BATTLE_TEST("Mind Blown causes the user to faint when below 1/2 of its HP } WHEN { TURN { MOVE(player, MOVE_MIND_BLOWN); } } SCENE { - HP_BAR(player, hp: 0); ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, player); + HP_BAR(player, hp: 0); MESSAGE("Wobbuffet fainted!"); } } -DOUBLE_BATTLE_TEST("Mind Blown causes the user to faint when below 1/2 of its HP in a double battle") +DOUBLE_BATTLE_TEST("Mind Blown causes the user to faint when below 1/2 of its Max HP in a double battle") { GIVEN { PLAYER(SPECIES_WOBBUFFET) { HP(200); MaxHP(400); } @@ -60,13 +60,13 @@ DOUBLE_BATTLE_TEST("Mind Blown causes the user to faint when below 1/2 of its HP } WHEN { TURN { MOVE(playerLeft, MOVE_MIND_BLOWN); } } SCENE { - HP_BAR(playerLeft, hp: 0); ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, playerLeft); + HP_BAR(playerLeft, hp: 0); MESSAGE("Wobbuffet fainted!"); } } -SINGLE_BATTLE_TEST("Mind Blown causes the user & the target to faint when below 1/2 of its HP") +SINGLE_BATTLE_TEST("Mind Blown causes the user & the target to faint when below 1/2 of its Max HP") { GIVEN { PLAYER(SPECIES_WOBBUFFET) { HP(200) ; MaxHP(400); } @@ -75,10 +75,10 @@ SINGLE_BATTLE_TEST("Mind Blown causes the user & the target to faint when below } WHEN { TURN { MOVE(player, MOVE_MIND_BLOWN); } } SCENE { - HP_BAR(player, hp: 0); ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, player); HP_BAR(opponent, hp: 0); MESSAGE("Foe Wobbuffet fainted!"); + HP_BAR(player, hp: 0); MESSAGE("Wobbuffet fainted!"); } } @@ -94,7 +94,6 @@ DOUBLE_BATTLE_TEST("Mind Blown causes everyone to faint in a double battle") } WHEN { TURN { MOVE(playerLeft, MOVE_MIND_BLOWN); } } SCENE { - HP_BAR(playerLeft, hp: 0); ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, playerLeft); HP_BAR(opponentLeft, hp: 0); MESSAGE("Foe Abra fainted!"); @@ -102,6 +101,7 @@ DOUBLE_BATTLE_TEST("Mind Blown causes everyone to faint in a double battle") MESSAGE("Wynaut fainted!"); HP_BAR(opponentRight, hp: 0); MESSAGE("Foe Kadabra fainted!"); + HP_BAR(playerLeft, hp: 0); MESSAGE("Wobbuffet fainted!"); } } @@ -118,3 +118,69 @@ SINGLE_BATTLE_TEST("Mind Blown hp loss is prevented by Magic Guard") ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, player); } } + +SINGLE_BATTLE_TEST("Mind Blown is blocked by Damp") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(400); MaxHP(400); } + OPPONENT(SPECIES_GOLDUCK) { Ability(ABILITY_DAMP); } + } WHEN { + TURN { MOVE(player, MOVE_MIND_BLOWN); } + } SCENE { + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, player); + HP_BAR(player, damage: 200); + } + ABILITY_POPUP(opponent, ABILITY_DAMP); + MESSAGE("Foe Golduck's Damp prevents Wobbuffet from using Mind Blown!"); + } +} + +SINGLE_BATTLE_TEST("Mind Blown makes the user lose HP even if the opposing mon protected") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_PROTECT); MOVE(player, MOVE_MIND_BLOWN); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_PROTECT, opponent); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, player); + HP_BAR(player); + } +} + +SINGLE_BATTLE_TEST("Mind Blown makes the user lose HP even if it is absorbed by Flash Fire") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_MIND_BLOWN].type == TYPE_FIRE); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_CYNDAQUIL) { Ability(ABILITY_FLASH_FIRE); } + } WHEN { + TURN { MOVE(player, MOVE_MIND_BLOWN); } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_FLASH_FIRE); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, player); + HP_BAR(player); + } +} + +SINGLE_BATTLE_TEST("Mind Blown does not cause the user to lose HP if there is no target") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_MEMENTO); MOVE(player, MOVE_MIND_BLOWN); SEND_OUT(opponent, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_MEMENTO, opponent); + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, player); + HP_BAR(player); + } + MESSAGE("Wobbuffet used Mind Blown!"); + MESSAGE("But it failed!"); + MESSAGE("2 sent out Wobbuffet!"); + } +} From b66738ff8d2e7bb77c9f1a5e044aa8f479de8adf Mon Sep 17 00:00:00 2001 From: TheJamesLJ Date: Sun, 12 May 2024 20:43:49 +0100 Subject: [PATCH 2/6] Multiple sprite updates (#4541) * Updated Mega Mewtwo Y sprite to fix transparent eye pixel * Updated Keldeo Resolute sprite to a two framed animation * Updated Keldeo Resolute sprite to increase definition to facial features * Improved Keldeo Resolutes second frame to match BW2 original & changed front animation * Added Meloetta Pirouette front anim * Updated Meloetta Pirouette anim frame to a dip --- graphics/pokemon/keldeo/resolute/anim_front.png | Bin 0 -> 1366 bytes graphics/pokemon/keldeo/resolute/front.png | Bin 836 -> 0 bytes .../pokemon/meloetta/pirouette/anim_front.png | Bin 0 -> 1207 bytes graphics/pokemon/meloetta/pirouette/front.png | Bin 693 -> 0 bytes graphics/pokemon/mewtwo/mega_y/back.png | Bin 781 -> 831 bytes src/data/graphics/pokemon.h | 4 ++-- src/data/pokemon/species_info/gen_5_families.h | 4 ++-- 7 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 graphics/pokemon/keldeo/resolute/anim_front.png delete mode 100644 graphics/pokemon/keldeo/resolute/front.png create mode 100644 graphics/pokemon/meloetta/pirouette/anim_front.png delete mode 100644 graphics/pokemon/meloetta/pirouette/front.png diff --git a/graphics/pokemon/keldeo/resolute/anim_front.png b/graphics/pokemon/keldeo/resolute/anim_front.png new file mode 100644 index 0000000000000000000000000000000000000000..c2611bde2faf9a14a7d411ac5de27e165de8e2aa GIT binary patch literal 1366 zcmV-c1*!UpP)SSYuc6siCK00Cl4M@0BLV`pXn00eqT zL_t(|ob8rPXd6cq$7clDLPU`^>kk#h*r{`X5!SyZYDL>?nhE`^>EayJge{%C=EE}L3nwXuZm8;Y&cDH%0 z2Y5*2*!)=K(npQ14=&A#E-~qCB59k&IE};dz~Z~Svj@1F%sV5dmW~1(@#c4Fz^Lq0YNI?B^kXao=<0 ztsSQ|%!5(?MhX@Lr6ENS^3{Y~GXqm6SJPYiY z3v;UT#(^?7HZm2=H5yxBV%l-mq{vDZna={{ve*McrqmPg z=O=qj?H4xupwo+x1TigU#~U@>11JK7nu$ghI#Bj>3v2}qq}FMtYb!t_vVitzpn$nU z1+RtyA4CAy3T>5f!B>v4`kQS8jz$2F0H8<58Gv^KfZggNsD)OK(!hD|W)*P>iQXTHLE3qDVyfo$*p;Y!}c)XLc-&5-`= zNEeq)GTU=e%?eN{_F`1;q!TnRRF-qmU95Tuz^IX2V|%P}Aq39H2Li8FLvZpj5X(^# zd%JzWFiWBaUv|!csDwZ)LP^$Lfr3HGxyIP6T|@gIK((YmaU!=G+t+M?8N^aB```4r zAFtW)Hs7np&xASA1-2SiNs4nTUi?fLeeE$fTaw=;?bxF(vbBx&bQg)y2PQL5E$znm zM2-&!w002n`xy~JV22@bYoj>~s0VD%m0x;4WdNbdDhK`*Deh!R9HMnaz1*@~F;&X~ z!ZKE0HeK;5dIcu*gNs4dUhcc=svYjczWzoyPS*ZYuK%`vk_IA;wYK<7sP^|60EHof zbhy3ncpW}!8c65|3Nv?Q-CqC|@pqVGLO&SbqFxTz+fMY3Pw59j&(n zkmZS*p&OOf5BgAumZ3FLrhdRQR$B)_ZMc4LrR6)L^aC|f6P)RXGyR|=oaqO>{y+Wj Y5B(#@eO|)ny#N3J07*qoM6N<$f?3I6n*aa+ literal 0 HcmV?d00001 diff --git a/graphics/pokemon/keldeo/resolute/front.png b/graphics/pokemon/keldeo/resolute/front.png deleted file mode 100644 index 8e83b810a775de0424031b3f2000fc5c0af4347d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 836 zcmV-K1H1f*P)dqlNQi(qC`f3?*hnxqus9enU?6~q`0%K(sBrlB_+VHlx0n>F0008d zNkl@PZ<&}$?fmWR%Rk# zs^*V?5}QN9bIDUARw5Ih{hg75QDThM^UQUTs6@bYb8XCnxGAwvV)d%88F(zRyT@47 zPYWc0hOY(kvBq=OsOc1LO)%ztT)z`&Hoq_y`0JXy0va4%d_rJO2Pl^`47tZP11+FN zMZ@+1+a73v$mQnw2lhtvqNRsf4F>051M#aHt?<@(-c|bvop*r{IzTA|Y-{QJc4sh* z6rdH35tIdshpZ0{|pkszw4vUAG=9 z0Hiksw=`(Sd08NH4)ZM7Y!jlqhgcv?1E^u~Lg^|#gG`1NLjGYY+{-=Ci`7Ec$(htClas_AmwgmMlv1^TEw_+BXFe$uH*-OEhNzC zX@L&PUnoEfbqeyxAkdS5?vi+*fD>_nKwk&cWOK!n4*p-io&bEqG0t!30Dq&3w`}Qp-F5 O0000~00Cl4M@0Xn2lB-L00Y}e zL_t(|ob8sqj}u1}z-KI7xa#nJoK8@n-Pz*~QL!FVKy_=}P-1C3N22eBqq!TIny4xq+rY>&{2g7=5JIDl-0vW8ewD&@m!69;I=O3bVg zggh7y2U6iI$I`CRQLV^RsDQJSt!%9t6R8dcHADl1YHff_ZcNG%tU}a{6iPa_;u}#E zJ(%Qd+$h;*E?_(9!6ac9n$`uZ?~iyaaFxJF7w||hTt=&E(b!uFQBNDZm#~iM=)eX1 zFoo@Wto6^$Y&3BJ>y3);Yl!D+`qTxG=1HGx{ZRAWN6tKHlKcAg?HSj#djQhuzt#H1 z3~IRZ0Q|zP=x=r81@0cce5duZjnz+I_X~G&l6I0X_Rua z$PRPOr05YE)P0((Xm4WxDhN<4sHJsOB|BSN8IY{JPaRqG(&z(&C^$D)u^n-FLq{gr{V zjeWMmbto8H$_RvzmSDhzC>X6U0@1YA=?@pFJiTrVM7C39)nHI#G%x}JpFlCJ!y65x zoa}&t03nsMPxr}<8U+LVp>DxptXZxE0}Vvfpa>%u@I8->fdC;L!1}&mJ4*wBbvgtB z3q8m4a8#@{}{-R&iq#cSw&P`U?3nE zRnS0CFshJ&7{N$F01AeECZ7dhk5`J~0Z=fEqL7XgNQ{9{b_@EEQ*!9aKs*iu1`obIK#mqc1G$O*5HgUZKLiY95P*PyU|?XVP&jZvIOuRtKrk@)`0&8Mz`!tA_<*SJP^_7CH;&Y0006& zNkl#$o=~JgBxfN($4P4g6-r@Wdy$fDsp#)c zAT1IU5lt-d0D(t1@c?uYUGfIkv3BUZ>p;UumRI`!_CK><1Mq*t@mj<{e~h;PjDmx$ z0P=Rg!I;G@I=DD!1q6i1JR$No7C?$K76~ck+=2*sfrGvfnn_K>ffNh}L^}vEHxWld zhBz2&hpa-34qZ$thnYyFXj&YJY?>tf+9Azk6L9rRpUT=Hn`LP;$0U=}ajrv`DQAWv zU~+#F1v*7uWI`Go01ibD`j&3%gRTdp{PM&;KO_mzwjL64KXF=gxI=(Yd{_;Gzy!Fufl!~JJ~lM=5*IyixD#N6 zHXyDW9SsqwL3cbBlfx+x;#x`=je3cn==>uv8BnL|lSDV7i1x_XkRXNtk?8VHG4egP zv0*M!#9G!7bGLD8+*-z8i~2{y=CukdAt=jWM>cz=!|-viEw_INZYY!TPPy2YYr?dZ zX(IqSif>8|PT-q$fZMBE>#NvVEcXDg-RuE6n{_(?8{V$pZFx4k6rcBG={q7<4|Jd+xmk2>HJU0N&O)=gG~q9_)5o&hMs)MS7%%Enj_@ zGDsyf@_c6LlD9S zde}$6t9w-=csB_|2UVj3f@}<+3W(pU>(~O31^{vuf~VsE;6^Vh#9B$gdH@6<#Fk$$ z#EQ1SoevyyfoE3>Tso*x#2ed1B!IQL5GlIwc!flqe>#0$v@SjgtP!hOtUW;M2%yDA zwdw(dZ~(DOaqE2V>||DcH2_sX4m@59+XQ(mOJkvmC3M604lpZAYtg337kiO<2G*hl zq^jc?3;-1*^9@W5({Sb+yaE#Q-@N(&?SB^Hu2DcML2W zDw?M1fwqC-3vqyqG>yJ{DY{b`z0t1{53mND0%l1> zK~zY`t(3ivn@|viF9j};iyeHCR_=Vgc>w>U59^B*Z3Pl;+-<{3k;}-`d51gzDBcEb znFmOfZSqi=0q!3QTSU2yLG$^XGcy4D&j$eBuL~jKo9Vi@+iiuonKv#}0BGRz&&VEQp#Uure@m?h7p-6< zveb^yDp1`@;Y1*XbAu-{L}CF?ZJq8h5>@_oAqObiGlZ5(h8>*at-E8=$i50I??K0|CDuRx|*#K+pnU z-kApH39fYr=vg)l@CYYH?;$pJ>*NA#1eQCs1PpT%MJhpVtZr%d>H!`3zQ8yIV?ca Q*Z=?k07*qoM6N<$f>tLd;{X5v diff --git a/src/data/graphics/pokemon.h b/src/data/graphics/pokemon.h index abb2780adf..2742793e0f 100644 --- a/src/data/graphics/pokemon.h +++ b/src/data/graphics/pokemon.h @@ -8452,7 +8452,7 @@ const u8 gMonFootprint_QuestionMark[] = INCBIN_U8("graphics/pokemon/question_mar const u8 gMonFootprint_Keldeo[] = INCBIN_U8("graphics/pokemon/keldeo/footprint.1bpp"); #endif //P_FOOTPRINTS - const u32 gMonFrontPic_KeldeoResolute[] = INCBIN_U32("graphics/pokemon/keldeo/resolute/front.4bpp.lz"); + const u32 gMonFrontPic_KeldeoResolute[] = INCBIN_U32("graphics/pokemon/keldeo/resolute/anim_front.4bpp.lz"); const u32 gMonPalette_KeldeoResolute[] = INCBIN_U32("graphics/pokemon/keldeo/resolute/normal.gbapal.lz"); const u32 gMonBackPic_KeldeoResolute[] = INCBIN_U32("graphics/pokemon/keldeo/resolute/back.4bpp.lz"); const u32 gMonShinyPalette_KeldeoResolute[] = INCBIN_U32("graphics/pokemon/keldeo/resolute/shiny.gbapal.lz"); @@ -8469,7 +8469,7 @@ const u8 gMonFootprint_QuestionMark[] = INCBIN_U8("graphics/pokemon/question_mar const u8 gMonFootprint_Meloetta[] = INCBIN_U8("graphics/pokemon/meloetta/footprint.1bpp"); #endif //P_FOOTPRINTS - const u32 gMonFrontPic_MeloettaPirouette[] = INCBIN_U32("graphics/pokemon/meloetta/pirouette/front.4bpp.lz"); + const u32 gMonFrontPic_MeloettaPirouette[] = INCBIN_U32("graphics/pokemon/meloetta/pirouette/anim_front.4bpp.lz"); const u32 gMonPalette_MeloettaPirouette[] = INCBIN_U32("graphics/pokemon/meloetta/pirouette/normal.gbapal.lz"); const u32 gMonBackPic_MeloettaPirouette[] = INCBIN_U32("graphics/pokemon/meloetta/pirouette/back.4bpp.lz"); const u32 gMonShinyPalette_MeloettaPirouette[] = INCBIN_U32("graphics/pokemon/meloetta/pirouette/shiny.gbapal.lz"); diff --git a/src/data/pokemon/species_info/gen_5_families.h b/src/data/pokemon/species_info/gen_5_families.h index 4b1fea0263..bdbff0e354 100644 --- a/src/data/pokemon/species_info/gen_5_families.h +++ b/src/data/pokemon/species_info/gen_5_families.h @@ -10200,7 +10200,7 @@ const struct SpeciesInfo gSpeciesInfoGen5[] = .frontPicSize = MON_COORDS_SIZE(64, 64), .frontPicYOffset = 2, .frontAnimFrames = sAnims_KeldeoResolute, - .frontAnimId = ANIM_V_STRETCH, + .frontAnimId = ANIM_V_JUMPS_H_JUMPS, .backPic = gMonBackPic_KeldeoResolute, .backPicSize = MON_COORDS_SIZE(64, 64), .backPicYOffset = 3, @@ -10319,7 +10319,7 @@ const struct SpeciesInfo gSpeciesInfoGen5[] = .trainerScale = 256, .trainerOffset = 0, .frontPic = gMonFrontPic_MeloettaPirouette, - .frontPicSize = MON_COORDS_SIZE(40, 64), + .frontPicSize = MON_COORDS_SIZE(64, 64), .frontPicYOffset = 2, .frontAnimFrames = sAnims_MeloettaPirouette, .frontAnimId = ANIM_H_SLIDE_SLOW, From 571d7bc43654d30b2de766115341be7e9d7b336f Mon Sep 17 00:00:00 2001 From: Cafei <46283144+cafei-uh@users.noreply.github.com> Date: Sun, 12 May 2024 23:45:34 +0400 Subject: [PATCH 3/6] Fix silent Oricorio Pom-Pom cry (#4551) * Fix Oricorio Pom-Pom silent cry * Silly mistake, thanks for pointing it out --- sound/cry_tables.inc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/cry_tables.inc b/sound/cry_tables.inc index c98e0ec746..13cb51f53c 100644 --- a/sound/cry_tables.inc +++ b/sound/cry_tables.inc @@ -1786,7 +1786,7 @@ gCryTable:: .endif @ P_FAMILY_CRABRAWLER .if P_FAMILY_ORICORIO == TRUE cry Cry_OricorioBaile - cry Cry_OricorioPomPom + cry_uncomp Cry_OricorioPomPom @ Cannot be heard unless we use cry_uncomp here. cry Cry_OricorioPau cry Cry_OricorioSensu .endif @ P_FAMILY_ORICORIO @@ -4212,7 +4212,7 @@ gCryTable_Reverse:: .endif @ P_FAMILY_CRABRAWLER .if P_FAMILY_ORICORIO == TRUE cry_reverse Cry_OricorioBaile - cry_reverse Cry_OricorioPomPom + cry_reverse_uncomp Cry_OricorioPomPom @ Cannot be heard unless we use cry_reverse_uncomp here. cry_reverse Cry_OricorioPau cry_reverse Cry_OricorioSensu .endif @ P_FAMILY_ORICORIO From eae221b9cff17f6fb253d80aa5adb40fdc0b8a63 Mon Sep 17 00:00:00 2001 From: Cafei <46283144+cafei-uh@users.noreply.github.com> Date: Mon, 13 May 2024 00:08:10 +0400 Subject: [PATCH 4/6] A bunch of Pokemon sprite changes and fixes (#4552) * A bunch of sprite fixes - New Basculin Blue and White animations to fix their entry animations - New Xerneas Neutral entry animation derived from its Active form animation - Recolored Iron Hands and Iron Bundle back sprites * Requested changes --- .../basculin/blue_striped/anim_front.png | Bin 0 -> 794 bytes .../pokemon/basculin/blue_striped/front.png | Bin 522 -> 0 bytes .../basculin/white_striped/anim_front.png | Bin 0 -> 828 bytes .../pokemon/basculin/white_striped/front.png | Bin 546 -> 0 bytes graphics/pokemon/iron_bundle/back.png | Bin 637 -> 647 bytes graphics/pokemon/iron_hands/back.png | Bin 792 -> 790 bytes graphics/pokemon/xerneas/anim_front.png | Bin 0 -> 1460 bytes graphics/pokemon/xerneas/front.png | Bin 846 -> 0 bytes src/data/graphics/pokemon.h | 6 +++--- src/data/pokemon/species_info/gen_9_families.h | 2 +- 10 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 graphics/pokemon/basculin/blue_striped/anim_front.png delete mode 100644 graphics/pokemon/basculin/blue_striped/front.png create mode 100644 graphics/pokemon/basculin/white_striped/anim_front.png delete mode 100644 graphics/pokemon/basculin/white_striped/front.png create mode 100644 graphics/pokemon/xerneas/anim_front.png delete mode 100644 graphics/pokemon/xerneas/front.png diff --git a/graphics/pokemon/basculin/blue_striped/anim_front.png b/graphics/pokemon/basculin/blue_striped/anim_front.png new file mode 100644 index 0000000000000000000000000000000000000000..4b333a0ca8e637e5a60916c295aa7375b51ab628 GIT binary patch literal 794 zcmV+#1LgdQP)Px#Fi=cXMVQc_5D*YxU|`_j;Gm$OATT&UP*4C!m>_`A7)TgEpin4qF!=cR00000 z000000BH4dr~m*0m`OxIRA_+E?5 zf!&>)Vd(1W`Zt0P{WvNCA9DN@`K?{gVl@)wKh0hO;Orcdij@P{{!;~oKfVS)y?HXo zBt6&w4Sx*?krWc*6pK@U*mytG0P*TB_(H`vB}Nm#gea;h!5*?tZer6vK-{!eVRn+s zM-pA5O}@IxW!c9El(U1i{+E+4XbJoH zfI^!7H-8J@mVJC6fNFSOUIJ2lpeg~o_@Dt8aAEJPKN|zwWxo_bBn1#S`(+iB)Bn;O zeb;445Do%J4<;Rb7u#IC2GHDs@3H0}5+BGEOGNRqKZPjKhJTF@7S@~Ly^bG>dz9k? zMl`3#BY;93AH35czo2Y~Yt#EazexTY@j;zmP<#*{6bMZpiQq_ Y11t0@jcJJW#{d8T07*qoM6N<$f&&6)cmMzZ literal 0 HcmV?d00001 diff --git a/graphics/pokemon/basculin/blue_striped/front.png b/graphics/pokemon/basculin/blue_striped/front.png deleted file mode 100644 index cd6e6cda1b0ef6664a547d77cbde8a12507fc626..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 522 zcmV+l0`>igP)evVsm6J`C zf&%geK9zgPFbE-`cI2C(`hItNcR`3l{%(vtyOidNy*xwdSX)}K{Fyo0D_FavDI z{jaN<2o#)0;LSu#^g_Q;-KUz*eGHB_ULhZ?p79BIhiF1=z5y;G;CW0s5P{o=9e@^| zNAqQLi;}SmOni@g3OkShnjePo6rwN;1VFI)skBgKsrKOhUF4@*KtLF0%Du@STTA>Q zVzJ=<1IycGEJ|vF0QjYL1EB%O5IVL~z$&J!X9KOW2k@*t;E;ctAN^de3njv16aWAK M07*qoM6N<$g4kx=C;$Ke diff --git a/graphics/pokemon/basculin/white_striped/anim_front.png b/graphics/pokemon/basculin/white_striped/anim_front.png new file mode 100644 index 0000000000000000000000000000000000000000..ed4c680347181116441d5441a924678e43186ada GIT binary patch literal 828 zcmV-C1H=4@P)Px#Fi=cXMVQc_NKjA+2ngWd;Gm$OATT%(5D-96PG@Ufze6B#r z?3t#ap`oE(DSXcJ3%^#=tkoNUp0$2nhWM$9hh-qZAYhJF^lK4;W)Y(eP$~^smQNH! zL{9-YR1g5@OpG1TaRQjUPcfc9X*tU&hWWFCGSv;_i$;37eFECzhy?OTTcu7C>=0`Dfk zJ<|50AsB6S20(%_?Eidx9l(Ajn0*RZp4N!`wgiB<>W_Zfsobfz&oIcI171D1%wb6o{9&WIDM6YB4C0L z4gw+wV$8|R6@&&LL*SWY4g^4u^(g@kLR`Z@r&>ZBpB4cpf~Q{#4d>Iqz|!{9adz@Y z1DyO-03qPw$2x#EC~gXR*Vp}#kyS!}&@HI_qozNj$atBA7vGPs0eD`&27LR~ctdyx zK*CGF1aARDLqkJDLqk!2CqI~0=a-T#`>gD>KPQhLxEAC%LB&iJ5`9^~;s+kclH zr1$`rqz)*h2X5Pp*|z0li(PB(zoZ8=`DDkRZLP)+=%@BBPY)3!|iVuJR&G6uu zLGPq<=M#y#?_y2fPac0jT+BZC`~CdH!%wrFn;6{yjeMe%s@N zVvu$rB>%7Ypa$3j5Xkjq_YXG_#UF?d{!4!F(myox-}M9NpEg9+9mnJV0000#KvkZgxIzq_sMUe#F1cM8S~Z*^UwBM5@A5FOzHpWbN!@)%fME?<=JGljE*l(!o z(gs)}X4;&Q^5_ksyN3b*#3hXuI5Llz1}e@A0PKDAf}Z(4eTeRG{`CyD7*FPz8QTDq zfY#JMPs2|jI>%oDJJmWTv6#z`v1xcMfe#UcRzQwf0dP&p(=7N)Vu!8@z*cDeq+j%_ zl=6@+h6TV$yjcaZf8YYffeI)uaI%Ca{m9Azuq^;mnx8NX9Y8H6EF@5sTEIJX;F~{A kG2=SG>i`?ofmMDb@9bjVj^@vOF#rGn07*qoM6N<$f`8-W!vFvP diff --git a/graphics/pokemon/iron_bundle/back.png b/graphics/pokemon/iron_bundle/back.png index 1635738474ff44a4699a4e9ec17c7d47b1d5f016..2b75da09fd1322b6c08f6edbb208b30ce8373c25 100644 GIT binary patch delta 564 zcmV-40?YmV1cwEXBnkm@Qb$4nuFf3kks&^R0tHD#K~z|U?Uvn=!XONV4V;45mA?Pm zZW1WcKR0->SDqQI&UijfQX0J7zWVB`cOqIpd3G| z{YuD%KxRO`$NM${4F-sNz-R#OUGERW0fKZt_5~1zIuJT#egfDJ7za|Rp!4gK4WtLG z5w?KRK!E+2jet!Bg}{J>`Nu}cF^jE#0c6B5;K2YJfxDLZ#^rtw5%+**D*?_+?A+|7 zi!@6T8^C#;V9l-sZsKh6lMGHv&z3G%CR)EZ8)vE&gK%-p;X>gv^03ARGmNV%*073R;JLfKxs`>!sLIGtzz5}Fx^r%W` z0jOS3cl31xwLhN?;mX1VBmwkrxsH%Jw+bDA_)J(I%8LkTXDcQvs19oB_nY55NE%0TST|xbQDZAn~t&JI^^fMnEf|!=znse_((GU_lcHkRTbA zA`s3jUrqoas3lMW@L)a?7zO%QE(yI7UO7Zd7(jn1Kr;c0KCPtQCBS4Mh%W#Smy^9v zY=D93@YQJ(4jTyf8v#y08i0wWy#)*!pd(<^fVM!VFT)13iHQ0Hz(W-%UC0FKn`BOI zNS;BbHzUk-=B$N1e<1Q_(esi7>@tWU;<@tjlOxCm)ODX0K^EtE7C?>wC14{UdZ5l& zvIM3!|7c^t6^lB_0jSsxhF2a%#mkb?LpNYLR8o0Ky^f;P?Fx`=1fNA{@mmV^B8Ga| z=h1cSq>=5!{1bHpr6tV+4i)r7h7EK8C1lQ|YXk6uX*=iMe?*Pw4N&-Jx9|y2>l{(J z8Hk~@LjfNxnEd%{2=av;qz3G8d2gY1Y76cFXlDZ6S*QoO6Hqn)M?GXfE&+Re+*#fr&I!s;HwEuL3;CcyTU ugO>q4=@fVZBJ7vm5?I4R`4e!*zsE1())i~X2_ioL0000 zavCuVg(GXR>=~T*f86R~S=tMQ(3!SBa3-*1Io}@L?0kKF*8jIa*PrM&S??oE|2_dX zUw;{}5(jSqEO9~z13v*kNZtZqO8g#xSjsDa&>$oLV!hpNFCa1?^cxn@*IJ(vt^w@c z^tIxD%YY5DzD|89PY6h70PBnC8T8CU0zlFi)7M8)#LyxIVd@1?Z%dDO2F&K006Oc- z(j#sZ1lumS;6V^TCLlPVnB1BoJ(pV!5gPx71xFC^Ck0IXN)CF#sPO`9z4wL*;0p-? z;CkW$p-l~87pds`=Yls0w6t~zX<`LDd%3$Mz;*~10Y#o7N>w)$pIuhmeRKw7-3)} zz_NfE1cx7sv^}=(6~Wm+Sg?02+QvSc76=1~4jJeT4g@s4E)PM|aKDS5QVKKx4tNoN zz%t-~GH?w*9iVAJ#$n_v03`!f#zeR$ zfYfH?vONOqEpQR!R%@PtxL9R?eGLwPO>U+F_Ll(rjp_<89MBvv_4`(mag@6b7|DVH zI3ScF!4W`9eq~_|179`)@IyR+QWIf+zFx-AR4*TJj$v%5b085t37~+H0jeKb6SLrB z5QLNmfTM#MKyPDMtIjr-qhSJ;UM74;XkJ2T4hAF(@?5o0uq=IRSmZc~LNq_F=HHfu zDovS>m9>@eNuPETY&(4rEOogJrb+l;Gow$n)%qwN4VivT+M z{vVf*ujZ+g6hpK@2F#Y013cR|z%dOm%%AmH|9brbv*a*3%x;fq00000NkvXXu0mjf DN2V;+ delta 723 zcmV;^0xbQO2ABqrBmpgvGBJOC(uPz3000kkQchF<|NsC0|NsC0|NsC0|Nr^kcPsz^ z0*gsRK~z|U?Uvha<1h?FOO6dlDD?loTV6zwwiCq70=xSVwN35Bb2KDHDPLco@&667 z@dtX|bi9wC%?H0pz!u{#16JbbEdWtOod$jbpp?7?0B7Ql0D$=pAT@uBWjEONeZPUI zfYfgS6TKR{4`5V1yIwAD12$CsHucOe2qkb7J-eRyrH2CGqUXK5^MH^|3og0$#}%;c zq5lT103wyq1n^bQOE2Z*B=~kgpd{GiRZjt6ms@=t;fr2&3xJyZrG-F9%I#P0d8Ji% z8AQRT$sn}edqV-l08@VgW?4wD;9W!LDph?Sy*&h&1=Di^BnHEo9`>rBD}Z4DHIVgD zAk2U$$AC{CfQtnK$WH=bNjw7j696qht*@mfGjIk_onMQz06gWG74Z!86QEcS7OCL{ z5KFo<=&czTXFk;Fmfkhyn95a8=8=VM<7nwOih=x>9 zNr44Gd4O3I9*QTAx4OZ3i)#cU4M;z<+`XkW2>cq5DS!r(K?tE3cnp9w(6pfKFbaT( zivcg=6M)uc<#H8*Pk^%p1GE+y$ct45${IWalmhl!fa69bNxT3?09pV_@v8-27BTB6 z77QQ(L5oCZKrDYEz0gmOF|1~g%ccNPM*yY_!hF2|!a%bdivd}J31Dw!1CRkm1(<$V zO{N70APFT8L}v#xfZoRFwp8ab#{8zh8OFEYTp6pG-NY>#%KKN@dGakC<}sEo0$Lr002ovPDHLk FV1l%DH|+ob diff --git a/graphics/pokemon/xerneas/anim_front.png b/graphics/pokemon/xerneas/anim_front.png new file mode 100644 index 0000000000000000000000000000000000000000..fdfda5f1375bce984c1d3195f8e8399a8d400eb7 GIT binary patch literal 1460 zcmV;l1xxygP)Px#Fi=cXMVZs3JcoaG!n(Qa{SXikJzSYwisd9WS^WI`CMG68KtLKA8UO$Q00000 z000000Johi_W%F|GD$>1RA_;vnA?JbAPhvyHANrz|G(V{0YnAFF5A|wGKT?zHGDoz zQTqDjRJ4+ds&`Q?8Li8gJ4YKUCzZY-N=;=N84&$X0HeL5 zFZ%C)(qmzHvhJ(B?*qb<-XMCgz`dvb_=h&8nV*YzK^CktrX@;o}~UJu*0&k1at z=dy2L0gws}^a1+t4*=xJ!2USBEg;ygtg9S1`wAzb?bN6eIvc$cS*E+iQaVr0GP4^5W;J~MvzG7cgXjbo#6V=?IG)} zeFsol!fiKuNDl`4Yk-tNUtWqkxcvrmvRL;KF06A|jfNY(2KJHr|7o}vWqtefut1Q0@M zoe8?`AZfF@hS8R^&L7TKz)}ci3n~Y02B-vE8A2(th%|2iao(Lk{OaoCfPglUYw^xU zMvOKfwmyN)C$a2<>Cvx1*g_ZZNxLqUFy8yaLt`IM2ri-KuA-NH!w=@EQO( ziy4dphF51bJ_l7K6B%3tft6a5j;>!PXEGyt{6wP23DZ!Y0D~dG<%k?N0s1{C`k@2f zeTrX&W3L8f{bUG8QKT<*0Vxxwl)?@5h-V+&7twGZ!;}w3Md2}%RGoaivA&#guwkr3QUb04FmDC6j}rmqK_iUvbY3*MKndy zGVg@8&g6=+Fk~ml|pDl@gbf8*vv81Y3|^uX%(l;l)!+d zIy{)OB0d8y)$eB}fSbV>%(c@qLZ^fA4WKtb@kST}x_SiUg)jr$ue#){QUeTCMG~YKpGkv000000000000000x1B8a00009 za7bBm001r{001r{0eGc9b^rhX2XskIMF-~w2M_}u7zTk;00089Nkl7pt>`IxawoJMGAbkvO4=#uJ}{ZMmeqZAhr*!hs9v zm)mo?wrS#Idum<9|DXRae(y;|NQVnwYX>c2qmGb+vf*I>I&%=BNs-lPEJS_MBCvQn z`lAi@VaIDPfe!3Cozz0R%mJ@mU-|1@IJ*SAI&#QL2R97nZ7o=-uS+p$XJ65RM~gTM zz-qW8YXISZ>X7ZTx(oXo4(JX=1;TrG=5GVg1lhqk0J+%N9{8Le`6pV&t(=Z57rzcT z=f3!&WtKMp!g2Vq&yTT#nL$otbmG43HE;`;=(2X=hCO%47%DN4BPn{Lu;e@deke|{ zJTKExZNUBBo3H}t1m9dPN;4pD_xjVWSOJ^)LJ&bZ;(B$3&D$K%6hd5_t~SQE`F4nd z;pi#@JmdhI)qI~;0J;>J46&M20-H)bZWXQ^W`XHrQU#3F!|V=K0%H{wiY=CaR8yta zG90DA5LR6Z`B|xTgPI0H0d=TdX%h6w;~EfXfCCU-{{_^;dioKj6<7z{T1FQl|U1eakP_>N`bf(xF6p`f#XS8jzm3A#?$AR zl>pY;X>{0)7<(!M_F`&vquGppECV8Bb?IR#;Oe=C4w0nC?Tj%on)Qef_G1p2KNka`tz zOn%e<0OsaK044tf^eaqshOMay*iy@PGy`b{JI!GKG)-kfG>|HG+XQ^b*c$&-Y~!&1 Y0k)s Date: Mon, 13 May 2024 04:27:17 -0500 Subject: [PATCH 5/6] Updated AI scores for Status moves that Dynamax Pokemon are immune to (#4523) * Update IsDamageMoveUsable to check for Steel Roller viability * Condense terrain flag checks and renamed IsDamageMoveUsable IsDamageMoveUsable is now named IsDamageMoveUnusable to more accurately reflect the boolean it returns. * Made the AI aware of when more moves will fail against Dynamax Pokemon Turns out Dynamax Pokemon are immune to quite a few moves. The AI is only aware of one of these at present--the Low Kick/Grass Knot effect, which I learned when the AI tried to Heavy Slam my Dynamaxed Pokemon. These additional cases should prevent the AI from selecting moves that have no effect against Dynamax Pokemon, though it may still select moves whose secondary effect won't work on Dynamaxed Pokemon (such as Fake Out or Circle Throw). * Update battle_ai_util.c Now handles damaging moves that Dynamax Pokemon are immune to * Update scores for Status moves Dynamax Pokemon are immune to * Extra parentheses oops * Update pokemon.h Added "doesntAffectDynamax" flag to MoveInfo * Update pokemon.h Replaced comma with semicolon (I'm using the online editor for this lol, sorry for all the commits) * Update moves_info.h Set the "doesntAffectDynamax" flag to TRUE for moves that have no effect on Dynamaxed targets. * Update battle_dynamax.c IsMoveBlockedByDynamax now simply returns the move's "doesntAffectDynamax" flag. * Revert "Update pokemon.h" This reverts commit 7edde776f8fcb5aee81cd76279ceaf29b55337ff. Revert "Update pokemon.h" This reverts commit ed01b18d750124422702974a7c8065f5cd541644. Revert "Update moves_info.h" This reverts commit bc42e7bccf3294244377281e51d2a061eeb97cad. Revert "Update battle_dynamax.c" This reverts commit 29dbdce850f232a23cdc3024dc558bd0d8a2881a. * Update battle_ai_main.c Made the new conditions consistent as separate checks. * Update battle_ai_main.c Whitespace formatting fixes. Sorry, lost track of what I'd changed and what I hadn't. --- src/battle_ai_main.c | 55 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 429ec6642b..6f79042a0b 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -1418,6 +1418,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-10); else if (aiData->abilities[battlerDef] == ABILITY_SUCTION_CUPS) ADJUST_SCORE(-10); + else if (IsDynamaxed(battlerDef)) + ADJUST_SCORE(-10); break; case EFFECT_TOXIC_THREAD: if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_SPEED)) @@ -1449,6 +1451,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) return 0; if (!ShouldTryOHKO(battlerAtk, battlerDef, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], move)) ADJUST_SCORE(-10); + else if (IsDynamaxed(battlerDef)) + ADJUST_SCORE(-10); break; case EFFECT_MIST: if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_MIST @@ -1486,7 +1490,9 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-3); break; case EFFECT_DISABLE: - if (gDisableStructs[battlerDef].disableTimer == 0 + if (IsDynamaxed(battlerDef)) + ADJUST_SCORE(-10); + else if (gDisableStructs[battlerDef].disableTimer == 0 && (B_MENTAL_HERB < GEN_5 || aiData->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB) && !PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)) { @@ -1506,7 +1512,9 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) } break; case EFFECT_ENCORE: - if (gDisableStructs[battlerDef].encoreTimer == 0 + if (IsDynamaxed(battlerDef)) + ADJUST_SCORE(-10); + else if (gDisableStructs[battlerDef].encoreTimer == 0 && (B_MENTAL_HERB < GEN_5 || aiData->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB) && !DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) { @@ -1720,7 +1728,9 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) } break; case EFFECT_TORMENT: - if (gBattleMons[battlerDef].status2 & STATUS2_TORMENT + if (IsDynamaxed(battlerDef)) + ADJUST_SCORE(-10); + else if (gBattleMons[battlerDef].status2 & STATUS2_TORMENT || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) { ADJUST_SCORE(-10); @@ -1923,6 +1933,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) case EFFECT_DESTINY_BOND: if (gBattleMons[battlerDef].status2 & STATUS2_DESTINY_BOND) ADJUST_SCORE(-10); + else if (IsDynamaxed(battlerDef)) + ADJUST_SCORE(-10); break; case EFFECT_HEAL_BELL: if (!AnyPartyMemberStatused(battlerAtk, gMovesInfo[move].soundMove) || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)) @@ -2119,6 +2131,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) || gAbilitiesInfo[aiData->abilities[battlerDef]].cantBeSwapped || aiData->holdEffects[battlerDef] == HOLD_EFFECT_ABILITY_SHIELD) ADJUST_SCORE(-10); + else if (IsDynamaxed(battlerDef)) + ADJUST_SCORE(-10); break; case EFFECT_WORRY_SEED: if (aiData->abilities[battlerDef] == ABILITY_INSOMNIA @@ -2137,6 +2151,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) || gAbilitiesInfo[aiData->abilities[battlerDef]].cantBeOverwritten || aiData->holdEffects[battlerAtk] == HOLD_EFFECT_ABILITY_SHIELD) ADJUST_SCORE(-10); + else if (IsDynamaxed(battlerDef)) + ADJUST_SCORE(-10); break; case EFFECT_SIMPLE_BEAM: if (aiData->abilities[battlerDef] == ABILITY_SIMPLE @@ -2463,6 +2479,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) { ADJUST_SCORE(-10); } + else if (IsDynamaxed(battlerDef)) + ADJUST_SCORE(-10); else if (isDoubleBattle) { if (!IS_TARGETING_PARTNER(battlerAtk, battlerDef)) @@ -3344,7 +3362,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) if (gBattleMons[battlerDef].statStages[STAT_EVASION] < 7 || aiData->abilities[battlerAtk] == ABILITY_NO_GUARD) ADJUST_SCORE(-2); break; - case EFFECT_BIDE: + case EFFECT_BIDE: if (aiData->hpPercents[battlerAtk] < 90) ADJUST_SCORE(-2); // Should be either removed or turned into increasing score case EFFECT_ACUPRESSURE: @@ -3365,7 +3383,10 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) score += AI_TryToClearStats(battlerAtk, battlerDef, isDoubleBattle); break; case EFFECT_ROAR: - if ((gMovesInfo[move].soundMove && aiData->abilities[battlerDef] == ABILITY_SOUNDPROOF) || aiData->abilities[battlerDef] == ABILITY_SUCTION_CUPS) + if ((gMovesInfo[move].soundMove && aiData->abilities[battlerDef] == ABILITY_SOUNDPROOF) + || aiData->abilities[battlerDef] == ABILITY_SUCTION_CUPS) + break; + else if (IsDynamaxed(battlerDef)) break; score += AI_TryToClearStats(battlerAtk, battlerDef, isDoubleBattle); break; @@ -3450,7 +3471,9 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) } break; case EFFECT_OHKO: - if (gStatuses3[battlerAtk] & STATUS3_ALWAYS_HITS) + if (IsDynamaxed(battlerDef)) + break; + else if (gStatuses3[battlerAtk] & STATUS3_ALWAYS_HITS) ADJUST_SCORE(BEST_EFFECT); break; case EFFECT_MEAN_LOOK: @@ -3545,7 +3568,9 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) ADJUST_SCORE(BEST_EFFECT); break; case EFFECT_DISABLE: - if (gDisableStructs[battlerDef].disableTimer == 0 + if (IsDynamaxed(battlerDef)) + break; + else if (gDisableStructs[battlerDef].disableTimer == 0 && (gLastMoves[battlerDef] != MOVE_NONE) && (gLastMoves[battlerDef] != 0xFFFF) && (B_MENTAL_HERB < GEN_5 || aiData->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB) @@ -3556,7 +3581,9 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) } break; case EFFECT_ENCORE: - if (gDisableStructs[battlerDef].encoreTimer == 0 + if (IsDynamaxed(battlerDef)) + break; + else if (gDisableStructs[battlerDef].encoreTimer == 0 && (B_MENTAL_HERB < GEN_5 || aiData->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB) && (gBattleMoveEffects[gMovesInfo[gLastMoves[battlerDef]].effect].encourageEncore)) ADJUST_SCORE(BEST_EFFECT); @@ -3573,7 +3600,9 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) ADJUST_SCORE(GOOD_EFFECT); break; case EFFECT_DESTINY_BOND: - if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER && CanTargetFaintAi(battlerDef, battlerAtk)) + if (IsDynamaxed(battlerDef)) + break; + else if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER && CanTargetFaintAi(battlerDef, battlerAtk)) ADJUST_SCORE(GOOD_EFFECT); break; case EFFECT_SPITE: @@ -4019,7 +4048,9 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) ADJUST_SCORE(DECENT_EFFECT); break; case EFFECT_SKILL_SWAP: - if (gAbilitiesInfo[aiData->abilities[battlerDef]].aiRating > gAbilitiesInfo[aiData->abilities[battlerAtk]].aiRating) + if (IsDynamaxed(battlerDef)) + break; + else if (gAbilitiesInfo[aiData->abilities[battlerDef]].aiRating > gAbilitiesInfo[aiData->abilities[battlerAtk]].aiRating) ADJUST_SCORE(DECENT_EFFECT); break; case EFFECT_WORRY_SEED: @@ -4029,7 +4060,9 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) ADJUST_SCORE(DECENT_EFFECT); break; case EFFECT_ENTRAINMENT: - if ((IsAbilityOfRating(aiData->abilities[battlerDef], 5) || gAbilitiesInfo[aiData->abilities[battlerAtk]].aiRating <= 0) + if (IsDynamaxed(battlerDef)) + break; + else if ((IsAbilityOfRating(aiData->abilities[battlerDef], 5) || gAbilitiesInfo[aiData->abilities[battlerAtk]].aiRating <= 0) && (aiData->abilities[battlerDef] != aiData->abilities[battlerAtk] && !(gStatuses3[battlerDef] & STATUS3_GASTRO_ACID))) ADJUST_SCORE(DECENT_EFFECT); break; From ebdc9ffc39eb6443116bef155fb4840396f67ad3 Mon Sep 17 00:00:00 2001 From: hedara90 <90hedara@gmail.com> Date: Mon, 13 May 2024 13:33:04 +0200 Subject: [PATCH 6/6] Fixed some moves' on-hit effects bypassing Substitutes where they shouldn't and some other things discovered along the way (#4558) * Fixed some moves' on-hit effects bypassing Substitutes where they shouldn't. Fixed Sparkling Aria interaction with Shield Dust in Singles vs Doubles. Fixed Wake-Up Slap and Smelling Salts getting boosted damage where they shouldn't vs Substitutes. * Cleaned up check for Sparkling Aria+Shield Dust interaction and fixed for agbcc. Fixed logic for checking if moves should do extra damage on statused targets. Wrote tests for Wake-Up Slap and Smelling Salts receicing extra damage on statused targets. Wrote tests to check Thousand Arrows type effectiveness vs ungrounded Flying types. * Update src/battle_util.c Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com> * Update src/battle_script_commands.c Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com> * Update src/battle_script_commands.c Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com> * Update test/battle/ability/shield_dust.c Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com> * Update test/battle/item_effect/covert_cloak.c Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com> * Update test/battle/item_effect/covert_cloak.c Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com> * Update test/battle/item_effect/covert_cloak.c Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com> * Update test/battle/move_effect/smelling_salts.c Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com> * Update test/battle/move_effect/thousand_arrows.c Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com> * Update test/battle/move_effect/wake_up_slap.c Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com> * Update test/battle/move_effect/wake_up_slap.c Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com> * Update test/battle/move_effect/wake_up_slap.c Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com> --------- Co-authored-by: Hedara Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com> --- data/battle_scripts_1.s | 1 + src/battle_script_commands.c | 38 ++++- src/battle_util.c | 5 +- test/battle/ability/shield_dust.c | 37 ++++- test/battle/item_effect/covert_cloak.c | 162 ++++++++++++++++++++++ test/battle/move_effect/knock_off.c | 12 ++ test/battle/move_effect/salt_cure.c | 14 ++ test/battle/move_effect/smack_down.c | 19 +++ test/battle/move_effect/smelling_salts.c | 63 +++++++++ test/battle/move_effect/sparkling_aria.c | 25 ++++ test/battle/move_effect/thousand_arrows.c | 55 ++++++++ test/battle/move_effect/wake_up_slap.c | 57 ++++++++ 12 files changed, 476 insertions(+), 12 deletions(-) create mode 100644 test/battle/item_effect/covert_cloak.c create mode 100644 test/battle/move_effect/smack_down.c create mode 100644 test/battle/move_effect/smelling_salts.c create mode 100644 test/battle/move_effect/sparkling_aria.c create mode 100644 test/battle/move_effect/thousand_arrows.c create mode 100644 test/battle/move_effect/wake_up_slap.c diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 5fa5bf342d..1f066d77a8 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -288,6 +288,7 @@ BattleScript_EffectSaltCure:: call BattleScript_EffectHit_Ret tryfaintmon BS_TARGET jumpiffainted BS_TARGET, TRUE, BattleScript_EffectSaltCure_End + jumpifsubstituteblocks BattleScript_EffectSaltCure_End applysaltcure BS_TARGET printstring STRINGID_TARGETISBEINGSALTCURED waitmessage B_WAIT_TIME_LONG diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index bc3e2f7198..be474cea8a 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -5397,6 +5397,7 @@ static void Cmd_moveend(void) u16 *choicedMoveAtk = NULL; u32 endMode, endState; u32 originallyUsedMove; + u8 currBattler, liveBattlerCount; if (gChosenMove == MOVE_UNAVAILABLE) originallyUsedMove = MOVE_NONE; @@ -5661,7 +5662,10 @@ static void Cmd_moveend(void) switch (gBattleStruct->moveEffect2) { case MOVE_EFFECT_KNOCK_OFF: - effect = TryKnockOffBattleScript(gBattlerTarget); + if (!DoesSubstituteBlockMove(gBattlerAttacker, gBattlerTarget, gCurrentMove)) + { + effect = TryKnockOffBattleScript(gBattlerTarget); + } break; case MOVE_EFFECT_STOCKPILE_WORE_OFF: if (gDisableStructs[gBattlerAttacker].stockpileCounter != 0) @@ -5673,7 +5677,9 @@ static void Cmd_moveend(void) } break; case MOVE_EFFECT_SMACK_DOWN: - if (!IsBattlerGrounded(gBattlerTarget) && IsBattlerAlive(gBattlerTarget)) + if (!IsBattlerGrounded(gBattlerTarget) + && IsBattlerAlive(gBattlerTarget) + && !DoesSubstituteBlockMove(gBattlerAttacker, gBattlerTarget, gCurrentMove)) { gStatuses3[gBattlerTarget] |= STATUS3_SMACKED_DOWN; gStatuses3[gBattlerTarget] &= ~(STATUS3_MAGNET_RISE | STATUS3_TELEKINESIS | STATUS3_ON_AIR); @@ -5683,7 +5689,9 @@ static void Cmd_moveend(void) } break; case MOVE_EFFECT_REMOVE_STATUS: // Smelling salts, Wake-Up Slap, Sparkling Aria - if ((gBattleMons[gBattlerTarget].status1 & gMovesInfo[gCurrentMove].argument) && IsBattlerAlive(gBattlerTarget)) + if ((gBattleMons[gBattlerTarget].status1 & gMovesInfo[gCurrentMove].argument) + && IsBattlerAlive(gBattlerTarget) + && !DoesSubstituteBlockMove(gBattlerAttacker, gBattlerTarget, gCurrentMove)) { gBattleMons[gBattlerTarget].status1 &= ~(gMovesInfo[gCurrentMove].argument); @@ -5700,8 +5708,28 @@ static void Cmd_moveend(void) gBattlescriptCurrInstr = BattleScript_TargetWokeUp; break; case STATUS1_BURN: - gBattlescriptCurrInstr = BattleScript_TargetBurnHeal; - break; + // Checks to see if Sparkling Aria should cure a Shield Dust pokemon + if (gBattleMons[gBattlerTarget].ability == ABILITY_SHIELD_DUST || gBattleMons[gBattlerTarget].item == ITEM_COVERT_CLOAK) + { + liveBattlerCount = 0; + for (currBattler = 0; currBattler < gBattlersCount; currBattler++) + { + if (gBattleMons[currBattler].hp != 0) + { + liveBattlerCount++; + } + } + if (liveBattlerCount > 2) + { + gBattlescriptCurrInstr = BattleScript_TargetBurnHeal; + } + break; + } + else + { + gBattlescriptCurrInstr = BattleScript_TargetBurnHeal; + break; + } } } break; // MOVE_EFFECT_REMOVE_STATUS diff --git a/src/battle_util.c b/src/battle_util.c index 1bdc1d9050..64cba43782 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -8632,8 +8632,11 @@ static inline u32 CalcMoveBasePower(u32 move, u32 battlerAtk, u32 battlerDef, u3 break; case EFFECT_DOUBLE_POWER_ON_ARG_STATUS: // Comatose targets treated as if asleep - if ((gBattleMons[battlerDef].status1 | (STATUS1_SLEEP * (abilityDef == ABILITY_COMATOSE))) & gMovesInfo[move].argument) + if ((gBattleMons[battlerDef].status1 | (STATUS1_SLEEP * (abilityDef == ABILITY_COMATOSE))) & gMovesInfo[move].argument + && !((gMovesInfo[move].additionalEffects->moveEffect == MOVE_EFFECT_REMOVE_STATUS) && DoesSubstituteBlockMove(battlerAtk, battlerDef, move))) + { basePower *= 2; + } break; case EFFECT_VARY_POWER_BASED_ON_HP: basePower = gMovesInfo[move].argument * gBattleMons[battlerDef].hp / gBattleMons[battlerDef].maxHP; diff --git a/test/battle/ability/shield_dust.c b/test/battle/ability/shield_dust.c index 0c4ba99a83..11563151ad 100644 --- a/test/battle/ability/shield_dust.c +++ b/test/battle/ability/shield_dust.c @@ -121,19 +121,44 @@ SINGLE_BATTLE_TEST("Shield Dust does not block self-targeting effects, primary o } } -DOUBLE_BATTLE_TEST("Shield Dust does not block Sparkling Aria in doubles") +DOUBLE_BATTLE_TEST("Shield Dust does or does not block Sparkling Aria depending on number of targets hit") { - KNOWN_FAILING; + u32 moveToUse; + PARAMETRIZE { moveToUse = MOVE_FINAL_GAMBIT; } + PARAMETRIZE { moveToUse = MOVE_TACKLE; } GIVEN { - PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_VIVILLON) { Ability(ABILITY_SHIELD_DUST); Status1(STATUS1_BURN); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { MOVE(playerLeft, MOVE_SPARKLING_ARIA); } + TURN { MOVE(playerRight, moveToUse, target: opponentRight); MOVE(playerLeft, MOVE_SPARKLING_ARIA); } } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_SPARKLING_ARIA, playerLeft); - MESSAGE("Foe Vivillion's burn was healed."); - STATUS_ICON(opponentLeft, burn: TRUE); + if (moveToUse == MOVE_TACKLE) { + MESSAGE("Foe Vivillon's burn was healed."); + STATUS_ICON(opponentLeft, none: TRUE); + } else { + NONE_OF { + MESSAGE("Foe Vivillon's burn was healed."); + STATUS_ICON(opponentLeft, none: TRUE); + } + } + } +} + +SINGLE_BATTLE_TEST("Shield Dust blocks Sparkling Aria in singles") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_VIVILLON) { Ability(ABILITY_SHIELD_DUST); Status1(STATUS1_BURN); } + } WHEN { + TURN { MOVE(player, MOVE_SPARKLING_ARIA); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SPARKLING_ARIA, player); + NONE_OF { + MESSAGE("Foe Vivillon's burn was healed."); + STATUS_ICON(opponent, none: TRUE); + } } } diff --git a/test/battle/item_effect/covert_cloak.c b/test/battle/item_effect/covert_cloak.c new file mode 100644 index 0000000000..76dec1c31c --- /dev/null +++ b/test/battle/item_effect/covert_cloak.c @@ -0,0 +1,162 @@ +#include "global.h" +#include "test/battle.h" + +SINGLE_BATTLE_TEST("Covert Cloak blocks secondary effects") +{ + u16 move; + PARAMETRIZE { move = MOVE_NUZZLE; } + PARAMETRIZE { move = MOVE_INFERNO; } + PARAMETRIZE { move = MOVE_MORTAL_SPIN; } + PARAMETRIZE { move = MOVE_FAKE_OUT; } + PARAMETRIZE { move = MOVE_ROCK_TOMB; } + PARAMETRIZE { move = MOVE_SPIRIT_SHACKLE; } + PARAMETRIZE { move = MOVE_PSYCHIC_NOISE; } + + GIVEN { + ASSUME(MoveHasAdditionalEffectWithChance(MOVE_NUZZLE, MOVE_EFFECT_PARALYSIS, 100) == TRUE); + ASSUME(MoveHasAdditionalEffectWithChance(MOVE_INFERNO, MOVE_EFFECT_BURN, 100) == TRUE); + ASSUME(MoveHasAdditionalEffectWithChance(MOVE_MORTAL_SPIN, MOVE_EFFECT_POISON, 100) == TRUE); + ASSUME(MoveHasAdditionalEffectWithChance(MOVE_FAKE_OUT, MOVE_EFFECT_FLINCH, 100) == TRUE); + ASSUME(MoveHasAdditionalEffectWithChance(MOVE_ROCK_TOMB, MOVE_EFFECT_SPD_MINUS_1, 100) == TRUE); + ASSUME(MoveHasAdditionalEffectWithChance(MOVE_SPIRIT_SHACKLE, MOVE_EFFECT_PREVENT_ESCAPE, 100) == TRUE); + ASSUME(MoveHasAdditionalEffectWithChance(MOVE_PSYCHIC_NOISE, MOVE_EFFECT_PSYCHIC_NOISE, 100) == TRUE); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_COVERT_CLOAK); } + } WHEN { + TURN { MOVE(player, move); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, player); + HP_BAR(opponent); + NONE_OF { + MESSAGE("Foe Wobbuffet is paralyzed! It may be unable to move!"); + MESSAGE("Foe Wobbuffet was burned!"); + MESSAGE("Foe Wobbuffet was poisoned!"); + MESSAGE("Foe Wobbuffet flinched!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + MESSAGE("Foe Wobbuffet was prevented from healing!"); + } + } THEN { // Can't find good way to test trapping + EXPECT(!(opponent->status2 & STATUS2_ESCAPE_PREVENTION)); + } +} + +SINGLE_BATTLE_TEST("Covert Cloak does not block primary effects") +{ + u16 move; + PARAMETRIZE { move = MOVE_INFESTATION; } + PARAMETRIZE { move = MOVE_THOUSAND_ARROWS; } + PARAMETRIZE { move = MOVE_JAW_LOCK; } + PARAMETRIZE { move = MOVE_PAY_DAY; } + + GIVEN { + ASSUME(MoveHasAdditionalEffectWithChance(MOVE_INFESTATION, MOVE_EFFECT_WRAP, 0) == TRUE); + ASSUME(MoveHasAdditionalEffectWithChance(MOVE_THOUSAND_ARROWS, MOVE_EFFECT_SMACK_DOWN, 0) == TRUE); + ASSUME(MoveHasAdditionalEffectWithChance(MOVE_JAW_LOCK, MOVE_EFFECT_TRAP_BOTH, 0) == TRUE); + ASSUME(MoveHasAdditionalEffectWithChance(MOVE_PAY_DAY, MOVE_EFFECT_PAYDAY, 0) == TRUE); + ASSUME(MoveHasAdditionalEffectWithChance(MOVE_SMACK_DOWN, MOVE_EFFECT_SMACK_DOWN, 0) == TRUE); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_SKARMORY) { Item(ITEM_COVERT_CLOAK); } + } WHEN { + TURN { MOVE(player, move); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, player); + HP_BAR(opponent); + switch (move) { + case MOVE_INFESTATION: + MESSAGE("Foe Skarmory has been afflicted with an infestation by Wobbuffet!"); + break; + case MOVE_THOUSAND_ARROWS: + MESSAGE("Foe Skarmory fell straight down!"); + break; + case MOVE_JAW_LOCK: + MESSAGE("Neither Pokémon can run away!"); + break; + case MOVE_PAY_DAY: + MESSAGE("Coins scattered everywhere!"); + break; + } + } THEN { // Can't find good way to test trapping + if (move == MOVE_JAW_LOCK) { + EXPECT(opponent->status2 & STATUS2_ESCAPE_PREVENTION); + EXPECT(player->status2 & STATUS2_ESCAPE_PREVENTION); + } + } +} + +SINGLE_BATTLE_TEST("Covert Cloak does not block self-targeting effects, primary or secondary") +{ + u16 move; + PARAMETRIZE { move = MOVE_POWER_UP_PUNCH; } + PARAMETRIZE { move = MOVE_RAPID_SPIN; } + PARAMETRIZE { move = MOVE_LEAF_STORM; } + PARAMETRIZE { move = MOVE_METEOR_ASSAULT; } + + GIVEN { + ASSUME(MoveHasAdditionalEffectSelf(MOVE_POWER_UP_PUNCH, MOVE_EFFECT_ATK_PLUS_1) == TRUE); + ASSUME(MoveHasAdditionalEffectSelf(MOVE_RAPID_SPIN, MOVE_EFFECT_RAPID_SPIN) == TRUE); + ASSUME(MoveHasAdditionalEffectSelf(MOVE_LEAF_STORM, MOVE_EFFECT_SP_ATK_TWO_DOWN) == TRUE); + ASSUME(MoveHasAdditionalEffectSelf(MOVE_METEOR_ASSAULT, MOVE_EFFECT_RECHARGE) == TRUE); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_COVERT_CLOAK); } + } WHEN { + TURN { MOVE(player, move); } + if (move == MOVE_METEOR_ASSAULT) { + TURN { SKIP_TURN(player); } + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, player); + HP_BAR(opponent); + switch (move) { + case MOVE_POWER_UP_PUNCH: + case MOVE_RAPID_SPIN: + case MOVE_LEAF_STORM: + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + break; + case MOVE_METEOR_ASSAULT: // second turn + MESSAGE("Wobbuffet must recharge!"); + break; + } + } +} + +DOUBLE_BATTLE_TEST("Covert Cloak does or does not block Sparkling Aria depending on number of targets hit") +{ + u32 moveToUse; + PARAMETRIZE { moveToUse = MOVE_FINAL_GAMBIT; } + PARAMETRIZE { moveToUse = MOVE_TACKLE; } + GIVEN { + PLAYER(SPECIES_WYNAUT); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_COVERT_CLOAK); Status1(STATUS1_BURN); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerRight, moveToUse, target: opponentRight); MOVE(playerLeft, MOVE_SPARKLING_ARIA); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SPARKLING_ARIA, playerLeft); + if (moveToUse == MOVE_TACKLE) { + MESSAGE("Foe Wobbuffet's burn was healed."); + STATUS_ICON(opponentLeft, none: TRUE); + } else { + NONE_OF { + MESSAGE("Foe Wobbuffet's burn was healed."); + STATUS_ICON(opponentLeft, none: TRUE); + } + } + } +} + +SINGLE_BATTLE_TEST("Covert Cloak blocks Sparkling Aria in singles") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_COVERT_CLOAK); Status1(STATUS1_BURN); } + } WHEN { + TURN { MOVE(player, MOVE_SPARKLING_ARIA); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SPARKLING_ARIA, player); + NONE_OF { + MESSAGE("Foe Wobbuffet's burn was healed."); + STATUS_ICON(opponent, none: TRUE); + } + } +} diff --git a/test/battle/move_effect/knock_off.c b/test/battle/move_effect/knock_off.c index 863cf165d3..883f313f3b 100644 --- a/test/battle/move_effect/knock_off.c +++ b/test/battle/move_effect/knock_off.c @@ -51,3 +51,15 @@ SINGLE_BATTLE_TEST("Knock Off activates after Rocky Helmet and Weakness Policy") } } } + +SINGLE_BATTLE_TEST("Knock Off doesn't knock off items from Pokemon behind substitutes") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_POKE_BALL); } + } WHEN { + TURN { MOVE(opponent, MOVE_SUBSTITUTE); MOVE(player, MOVE_KNOCK_OFF); } + } SCENE { + NOT MESSAGE("Wobbuffet knocked off Foe Wobbuffet's Poké Ball"); + } +} diff --git a/test/battle/move_effect/salt_cure.c b/test/battle/move_effect/salt_cure.c index 547797e38b..939e32f0a6 100644 --- a/test/battle/move_effect/salt_cure.c +++ b/test/battle/move_effect/salt_cure.c @@ -85,3 +85,17 @@ SINGLE_BATTLE_TEST("If Salt Cure faints the target no status will be applied") MESSAGE("Foe Wobbuffet fainted!"); } } + +SINGLE_BATTLE_TEST("Salt Cure does not get applied if hitting a Substitute") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SUBSTITUTE); MOVE(player, MOVE_SALT_CURE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SALT_CURE, player); + MESSAGE("The SUBSTITUTE took damage for Foe Wobbuffet!"); + NOT MESSAGE("Foe Wobbuffet is being salt cured!"); + } +} diff --git a/test/battle/move_effect/smack_down.c b/test/battle/move_effect/smack_down.c new file mode 100644 index 0000000000..54bf6885af --- /dev/null +++ b/test/battle/move_effect/smack_down.c @@ -0,0 +1,19 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gMovesInfo[MOVE_SMACK_DOWN].additionalEffects->moveEffect == MOVE_EFFECT_SMACK_DOWN); +} + +SINGLE_BATTLE_TEST("Smack Down does not ground mons behind substitutes") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_SKARMORY); + } WHEN { + TURN { MOVE(opponent, MOVE_SUBSTITUTE); MOVE(player, MOVE_SMACK_DOWN); } + } SCENE { + NOT MESSAGE("Foe Skarmory fell straight down!"); + } +} diff --git a/test/battle/move_effect/smelling_salts.c b/test/battle/move_effect/smelling_salts.c new file mode 100644 index 0000000000..09168f8a1e --- /dev/null +++ b/test/battle/move_effect/smelling_salts.c @@ -0,0 +1,63 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gMovesInfo[MOVE_SMELLING_SALTS].additionalEffects->moveEffect == MOVE_EFFECT_REMOVE_STATUS); + ASSUME(gMovesInfo[MOVE_SMELLING_SALTS].argument == STATUS1_PARALYSIS); +} + +SINGLE_BATTLE_TEST("Smelling Salts does not cure paralyzed pokemons behind substitutes or get increased power") +{ + u32 ability; + PARAMETRIZE { ability = ABILITY_INNER_FOCUS; } + PARAMETRIZE { ability = ABILITY_INFILTRATOR; } + GIVEN { + PLAYER(SPECIES_CROBAT) { Ability(ability); } + OPPONENT(SPECIES_SEISMITOAD) { Status1(STATUS1_PARALYSIS); } + } WHEN { + TURN { MOVE(opponent, MOVE_SUBSTITUTE); MOVE(player, MOVE_CELEBRATE); } + TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_SMELLING_SALTS); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SMELLING_SALTS, player); + if (ability == ABILITY_INNER_FOCUS) + { + MESSAGE("The SUBSTITUTE took damage for Foe Seismitoad!"); + NONE_OF + { + MESSAGE("Foe Seismitoad's SUBSTITUTE faded!"); // Smelling Salts does 86 damage, the sub has 122 HP, if hitting a sub it shouldn't get boosted damage. + MESSAGE("Foe Seismitoad was healed of paralysis!"); + STATUS_ICON(opponent, none: TRUE); + } + } + else + { + MESSAGE("Foe Seismitoad was healed of paralysis!"); + STATUS_ICON(opponent, none: TRUE); + } + } +} + +SINGLE_BATTLE_TEST("Smelling Salts get incread power vs. paralyzed targets") +{ + u32 status1; + PARAMETRIZE { status1 = STATUS1_PARALYSIS; } + PARAMETRIZE { status1 = STATUS1_NONE; } + GIVEN { + PLAYER(SPECIES_CROBAT); + OPPONENT(SPECIES_LOTAD) { Status1(status1); } + } WHEN { + TURN { MOVE(player, MOVE_SMELLING_SALTS); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SMELLING_SALTS, player); + if (status1 == STATUS1_PARALYSIS) + { + MESSAGE("Foe Lotad fainted!"); + } + else + { + NOT MESSAGE("Foe Lotad fainted!"); + MESSAGE("Foe Lotad used Celebrate!"); + } + } +} diff --git a/test/battle/move_effect/sparkling_aria.c b/test/battle/move_effect/sparkling_aria.c new file mode 100644 index 0000000000..1bf7de2df4 --- /dev/null +++ b/test/battle/move_effect/sparkling_aria.c @@ -0,0 +1,25 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gMovesInfo[MOVE_SPARKLING_ARIA].additionalEffects->moveEffect == MOVE_EFFECT_REMOVE_STATUS); + ASSUME(gMovesInfo[MOVE_SPARKLING_ARIA].argument == STATUS1_BURN); + ASSUME(gMovesInfo[MOVE_SPARKLING_ARIA].soundMove == TRUE); +} + +DOUBLE_BATTLE_TEST("Sparkling Aria cures burns from all Pokemon on the field and behind substitutes") +{ + GIVEN { + PLAYER(SPECIES_PRIMARINA); + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_BURN); } + OPPONENT(SPECIES_WOBBUFFET) { Status1(STATUS1_BURN); } + OPPONENT(SPECIES_WYNAUT) { Status1(STATUS1_BURN); } + } WHEN { + TURN { MOVE(opponentLeft, MOVE_SUBSTITUTE); MOVE(opponentRight, MOVE_CELEBRATE); MOVE(playerRight, MOVE_CELEBRATE); MOVE(playerLeft, MOVE_SPARKLING_ARIA); } + } SCENE { + MESSAGE("Foe Wobbuffet's burn was healed."); + MESSAGE("Wobbuffet's burn was healed."); + MESSAGE("Foe Wynaut's burn was healed."); + } +} diff --git a/test/battle/move_effect/thousand_arrows.c b/test/battle/move_effect/thousand_arrows.c new file mode 100644 index 0000000000..bff3706c34 --- /dev/null +++ b/test/battle/move_effect/thousand_arrows.c @@ -0,0 +1,55 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gMovesInfo[MOVE_THOUSAND_ARROWS].additionalEffects->moveEffect == MOVE_EFFECT_SMACK_DOWN); + ASSUME(gMovesInfo[MOVE_THOUSAND_ARROWS].ignoreTypeIfFlyingAndUngrounded == TRUE); +} + +SINGLE_BATTLE_TEST("Thousand Arrows does not ground mons behind substitutes") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_SKARMORY); + } WHEN { + TURN { MOVE(opponent, MOVE_SUBSTITUTE); MOVE(player, MOVE_THOUSAND_ARROWS); } + } SCENE { + NOT MESSAGE("Foe Skarmory fell straight down!"); + } +} + +SINGLE_BATTLE_TEST("Thousand Arrows does neutral damage to non-grounded Flying types regardless of other typings") +{ + u32 pokemon; + PARAMETRIZE { pokemon = SPECIES_SKARMORY; } + PARAMETRIZE { pokemon = SPECIES_SCYTHER; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(pokemon); + } WHEN { + TURN { MOVE(player, MOVE_THOUSAND_ARROWS); } + TURN { MOVE(player, MOVE_THOUSAND_ARROWS); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_THOUSAND_ARROWS, player); + if (pokemon == SPECIES_SKARMORY) { + MESSAGE("Foe Skarmory fell straight down!"); + MESSAGE("Foe Skarmory used Celebrate!"); + } else { + MESSAGE("Foe Scyther fell straight down!"); + MESSAGE("Foe Scyther used Celebrate!"); + } + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); + MESSAGE("Congratulations, 1!"); + MESSAGE("Wobbuffet used ThousndArrws!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_THOUSAND_ARROWS, player); + if (pokemon == SPECIES_SKARMORY) + { + MESSAGE("It's super effective!"); + } + else + { + MESSAGE("It's not very effective…"); + } + } +} diff --git a/test/battle/move_effect/wake_up_slap.c b/test/battle/move_effect/wake_up_slap.c new file mode 100644 index 0000000000..98bcf95b20 --- /dev/null +++ b/test/battle/move_effect/wake_up_slap.c @@ -0,0 +1,57 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gMovesInfo[MOVE_WAKE_UP_SLAP].additionalEffects->moveEffect == MOVE_EFFECT_REMOVE_STATUS); + ASSUME(gMovesInfo[MOVE_WAKE_UP_SLAP].argument == STATUS1_SLEEP); +} + +SINGLE_BATTLE_TEST("Wake-Up Slap does not cure paralyzed pokemons behind substitutes or get increased power") +{ + u32 ability; + PARAMETRIZE { ability = ABILITY_INNER_FOCUS; } + PARAMETRIZE { ability = ABILITY_INFILTRATOR; } + GIVEN { + PLAYER(SPECIES_CROBAT) { Ability(ability); } + OPPONENT(SPECIES_SEISMITOAD); + } WHEN { + TURN { MOVE(opponent, MOVE_SUBSTITUTE); MOVE(player, MOVE_SING); } + TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_WAKE_UP_SLAP); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_WAKE_UP_SLAP, player); + if (ability == ABILITY_INNER_FOCUS) { + MESSAGE("The SUBSTITUTE took damage for Foe Seismitoad!"); + NONE_OF + { + MESSAGE("Foe Seismitoad's SUBSTITUTE faded!"); // Smelling Salts does 86 damage, the sub has 122 HP, if hitting a sub it shouldn't get boosted damage. + MESSAGE("Foe Seismitoad woke up!"); + STATUS_ICON(opponent, none: TRUE); + } + } else { + MESSAGE("Foe Seismitoad woke up!"); + STATUS_ICON(opponent, none: TRUE); + } + } +} + +SINGLE_BATTLE_TEST("Wake-Up Slap get incread power vs. sleeping targets") +{ + u32 status1; + PARAMETRIZE { status1 = STATUS1_SLEEP; } + PARAMETRIZE { status1 = STATUS1_NONE; } + GIVEN { + PLAYER(SPECIES_CROBAT); + OPPONENT(SPECIES_LOTAD) { Status1(status1); } + } WHEN { + TURN { MOVE(player, MOVE_WAKE_UP_SLAP); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_WAKE_UP_SLAP, player); + if (status1 == STATUS1_SLEEP) { + MESSAGE("Foe Lotad fainted!"); + } else { + NOT MESSAGE("Foe Lotad fainted!"); + MESSAGE("Foe Lotad used Celebrate!"); + } + } +}