From ae2474ab3c925e0d5b467bfdaeeefbdf829627c0 Mon Sep 17 00:00:00 2001 From: cawtds <38510667+cawtds@users.noreply.github.com> Date: Fri, 14 Nov 2025 16:41:44 +0100 Subject: [PATCH 1/6] battle engine update --- asm/macros/battle_script.inc | 74 +- data/battle_scripts_1.s | 762 ++-- data/battle_scripts_2.s | 20 +- include/battle.h | 101 +- include/battle_ai_switch_items.h | 2 +- include/battle_ai_util.h | 32 +- include/battle_dynamax.h | 4 +- include/battle_hold_effects.h | 52 + include/battle_main.h | 14 +- include/battle_script_commands.h | 12 +- include/battle_scripts.h | 35 +- include/battle_terastal.h | 8 +- include/battle_util.h | 128 +- include/config/battle.h | 6 +- include/config/contest.h | 10 + include/config/fishing.h | 13 + include/config/summary_screen.h | 35 +- include/constants/battle.h | 87 +- include/constants/battle_end_turn.h | 92 + include/constants/battle_move_effects.h | 4 +- include/constants/battle_script_commands.h | 36 +- include/constants/battle_string_ids.h | 23 +- include/constants/generational_changes.h | 6 + include/constants/global.h | 16 +- include/constants/hold_effects.h | 12 +- include/constants/items.h | 40 +- include/constants/move_relearner.h | 29 + include/constants/pokemon.h | 78 +- include/field_player_avatar.h | 4 +- include/fishing.h | 10 + include/generational_changes.h | 6 + include/item.h | 2 +- include/move.h | 16 +- include/pokemon.h | 52 +- include/random.h | 12 + include/recorded_battle.h | 4 +- include/test/battle.h | 175 +- include/test/test.h | 28 +- include/test/test_runner_battle.h | 6 + include/test_runner.h | 3 + include/wild_encounter.h | 1 - src/battle_ai_field_statuses.c | 17 +- src/battle_ai_main.c | 229 +- src/battle_ai_switch_items.c | 68 +- src/battle_ai_util.c | 354 +- src/battle_anim_effects_1.c | 8 +- src/battle_debug.c | 13 +- src/battle_dynamax.c | 21 +- src/battle_end_turn.c | 556 ++- src/battle_hold_effects.c | 1271 +++++++ src/battle_main.c | 444 ++- src/battle_message.c | 49 +- src/battle_script_commands.c | 2306 ++++++------ src/battle_terastal.c | 13 +- src/battle_util.c | 3107 +++++------------ src/battle_z_move.c | 11 +- src/data/battle_move_effects.h | 18 +- src/data/hold_effects.h | 649 ++++ src/data/items.h | 478 ++- src/data/moves_info.h | 1245 +++---- src/data/pokemon/form_change_table_pointers.h | 19 + src/field_player_avatar.c | 629 +--- src/fishing.c | 649 ++++ src/item.c | 5 +- src/item_use.c | 3 +- src/learn_move.c | 1 + src/party_menu.c | 143 +- src/pokemon.c | 476 ++- src/quest_log_player.c | 4 +- src/recorded_battle.c | 10 +- src/wallclock.c | 26 +- src/wild_encounter.c | 5 - 72 files changed, 8387 insertions(+), 6490 deletions(-) create mode 100644 include/battle_hold_effects.h create mode 100644 include/config/contest.h create mode 100644 include/config/fishing.h create mode 100644 include/constants/battle_end_turn.h create mode 100644 include/constants/move_relearner.h create mode 100644 include/fishing.h create mode 100644 include/test/test_runner_battle.h create mode 100644 src/battle_hold_effects.c create mode 100644 src/data/hold_effects.h create mode 100644 src/fishing.c diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index b2a579fdc..45d262bbe 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -13,7 +13,7 @@ .byte 0x2 .endm - .macro unused0x3 + .macro unused_0x3 .byte 0x3 .endm @@ -45,14 +45,16 @@ .byte 0xa .endm - .macro healthbarupdate battler:req + .macro healthbarupdate battler:req updateState:req .byte 0xb .byte \battler + .byte \updateState .endm - .macro datahpupdate battler:req + .macro datahpupdate battler:req updateState:req .byte 0xc .byte \battler + .byte \updateState .endm .macro critmessage @@ -187,8 +189,13 @@ .4byte \jumpInstr .endm - .macro unused_0x21 + .macro jumpifstatignorecontrary battler:req, comparison:req, stat:req, value:req, jumpInstr:req .byte 0x21 + .byte \battler + .byte \comparison + .byte \stat + .byte \value + .4byte \jumpInstr .endm .macro jumpbasedontype battler:req, type:req, jumpIfType:req, jumpInstr:req @@ -358,9 +365,8 @@ .byte 0x3a .endm - .macro absorbhealthbarupdate battler:req + .macro isdmgblockedbydisguise .byte 0x3b - .byte \battler .endm .macro return @@ -673,10 +679,8 @@ .byte 0x75 .endm - .macro various battler:req, id:req + .macro unused_0x78 .byte 0x76 - .byte \battler - .byte \id .endm .macro setprotectlike @@ -759,7 +763,7 @@ callnative BS_RemoveStockpileCounters .endm - .macro setdrainedhp + .macro unused_0x88 .byte 0x88 .endm @@ -935,7 +939,7 @@ .4byte \failInstr .endm - .macro trysetdestinybondtohappen + .macro unused_0xab .byte 0xab .endm @@ -1011,9 +1015,10 @@ .4byte \jumpInstr .endm - .macro tryrestorehpberry battler:req + .macro tryactivateitem battler:req, flag:req .byte 0xbb .byte \battler + .byte \flag .endm .macro halvehp failInstr:req @@ -1292,7 +1297,7 @@ .byte 0xf3 .endm - .macro subattackerhpbydmg + .macro unused_0xf4 .byte 0xf4 .endm @@ -1338,7 +1343,7 @@ .byte \trigger .endm - .macro tryworryseed failInstr:req + .macro tryoverwriteability failInstr:req .byte 0xfe .4byte \failInstr .endm @@ -1615,14 +1620,6 @@ .4byte \failInstr .endm - .macro tryupdaterecoiltracker - callnative BS_TryUpdateRecoilTracker - .endm - - .macro tryupdateleaderscresttracker - callnative BS_TryUpdateLeadersCrestTracker - .endm - .macro trytidyup clear:req, jumpInstr:req callnative BS_TryTidyUp .byte \clear @@ -1762,6 +1759,10 @@ .2byte \flags .endm + .macro clearspecialstatuses + callnative BS_ClearSpecialStatuses + .endm + .macro clearmoveresultflags flags:req callnative BS_ClearMoveResultFlags .2byte \flags @@ -1784,11 +1785,8 @@ .4byte \jumpInstr .endm - .macro jumpiflastuseditemholdeffect holdEffect:req, secondaryId:req, jumpInstr:req - callnative BS_JumpIfLastUsedItemHoldEffect - .byte \holdEffect - .2byte \secondaryId - .4byte \jumpInstr + .macro tryflingholdeffect + callnative BS_TryFlingHoldEffect .endm .macro swapsidestatuses @@ -1940,12 +1938,6 @@ .4byte \jumpInstr .endm - .macro infatuatewithbattler battler:req, infatuateWith:req - callnative BS_InfatuateWithBattler - .byte \battler - .byte \infatuateWith - .endm - .macro setlastuseditem battler:req callnative BS_SetLastUsedItem .byte \battler @@ -2077,9 +2069,8 @@ .byte \id .endm - .macro arenawaitmessage id:req + .macro arenawaitmessage callnative BS_ArenaWaitMessage - .byte \id .endm .macro waitcry @@ -2159,11 +2150,6 @@ .4byte \failInstr .endm - .macro setsimplebeam failInstr:req - callnative BS_SetSimpleBeam - .4byte \failInstr - .endm - .macro tryentrainment failInstr:req callnative BS_TryEntrainment .4byte \failInstr @@ -2366,8 +2352,8 @@ .4byte \jumpInstr .endm - .macro jumpifleafguardprotected battler:req, jumpInstr:req - callnative BS_JumpIfLeafGuardProtected + .macro jumpifabilitypreventsrest battler:req, jumpInstr:req + callnative BS_JumpIfAbilityPreventsRest .byte \battler .4byte \jumpInstr .endm @@ -2386,10 +2372,6 @@ .4byte \failInstr .endm - .macro curecertainstatuses - callnative BS_CureCertainStatuses - .endm - .macro tryresetnegativestatstages callnative BS_TryResetNegativeStatStages .endm diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 75fb05788..091f7f30a 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -62,27 +62,6 @@ BattleScript_LeftoverBirchString:: printstring STRINGID_DONTLEAVEBIRCH end2 -BattleScript_TooScaredToMove:: - printstring STRINGID_MONTOOSCAREDTOMOVE - waitmessage B_WAIT_TIME_LONG - playanimation BS_ATTACKER, B_ANIM_MON_SCARED - goto BattleScript_MoveEnd - -BattleScript_GhostGetOutGetOut:: - printstring STRINGID_GHOSTGETOUTGETOUT - playanimation BS_ATTACKER, B_ANIM_GHOST_GET_OUT - goto BattleScript_MoveEnd - -BattleScript_SilphScopeUnveiled:: - pause B_WAIT_TIME_SHORT - printstring STRINGID_SILPHSCOPEUNVEILED - waitstate - playanimation BS_OPPONENT1, B_ANIM_SILPH_SCOPED - pause B_WAIT_TIME_SHORT - printstring STRINGID_GHOSTWASMAROWAK - waitmessage B_WAIT_TIME_LONG - end2 - @ pokeemerald BattleScript_EffectFickleBeam:: @@ -200,11 +179,10 @@ BattleScript_EffectShedTail:: jumpifcantswitch SWITCH_IGNORE_ESCAPE_PREVENTION | BS_ATTACKER, BattleScript_ButItFailed setsubstitute jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_SUBSTITUTE_FAILED, BattleScript_SubstituteString - orword gHitMarker, HITMARKER_PASSIVE_HP_UPDATE attackanimation waitanimation - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printstring STRINGID_SHEDITSTAIL waitmessage B_WAIT_TIME_LONG moveendto MOVEEND_ATTACKER_VISIBLE @@ -223,7 +201,6 @@ BattleScript_EffectFilletAway:: jumpifstat BS_ATTACKER, CMP_EQUAL, STAT_SPEED, MAX_STAT_STAGE, BattleScript_ButItFailed BattleScript_FilletAwayTryAttack:: halvehp BattleScript_ButItFailed - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE attackanimation waitanimation setstatchanger STAT_ATK, 2, FALSE @@ -242,8 +219,8 @@ BattleScript_FilletAwayTrySpeed:: waitmessage B_WAIT_TIME_LONG BattleScript_FilletAwayEnd:: clearmoveresultflags MOVE_RESULT_NO_EFFECT - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE goto BattleScript_MoveEnd BattleScript_EffectDoodle:: @@ -263,7 +240,7 @@ BattleScript_EffectDoodle_AfterCopy: printstring STRINGID_PKMNCOPIEDFOE waitmessage B_WAIT_TIME_LONG switchinabilities BS_ATTACKER - jumpifbyte CMP_NOT_EQUAL, gBattleCommunication, 0x0, BattleScript_MoveEnd + jumpifbyte CMP_NOT_EQUAL, gBattleCommunication, 0x0, BattleScript_EffectDoodleMoveEnd addbyte gBattleCommunication, 1 jumpifnoally BS_ATTACKER, BattleScript_EffectDoodleMoveEnd setallytonextattacker BattleScript_EffectDoodle_CopyAbility @@ -445,20 +422,14 @@ BattleScript_MoveEffectSaltCure:: BattleScript_SaltCureExtraDamage:: playanimation BS_ATTACKER, B_ANIM_SALT_CURE_DAMAGE, NULL waitanimation - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printstring STRINGID_TARGETISHURTBYSALTCURE waitmessage B_WAIT_TIME_LONG tryfaintmon BS_ATTACKER + tryactivateitem BS_ATTACKER, ACTIVATION_ON_HP_THRESHOLD end2 -BattleScript_HurtTarget_NoString: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_TARGET - datahpupdate BS_TARGET - return - BattleScript_EffectCorrosiveGas:: attackcanceler accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE @@ -572,10 +543,8 @@ BattleScript_TeatimeLoop: jumpifelectricabilityaffected BS_TARGET, ABILITY_VOLT_ABSORB, BattleScript_Teatimesorb jumpifelectricabilityaffected BS_TARGET, ABILITY_MOTOR_DRIVE, BattleScript_Teatimemotor jumpifteainvulnerable BS_TARGET, BattleScript_Teatimevul @ in semi-invulnerable state OR held item is not a Berry - orword gHitMarker, HITMARKER_DISABLE_ANIMATION | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_IGNORE_DISGUISE setbyte sBERRY_OVERRIDE, TRUE @ override the requirements for eating berries consumeberry BS_TARGET, TRUE @ consume the berry, then restore the item from changedItems - bicword gHitMarker, HITMARKER_DISABLE_ANIMATION | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_IGNORE_DISGUISE setbyte sBERRY_OVERRIDE, FALSE removeitem BS_TARGET moveendto MOVEEND_NEXT_TARGET @@ -590,8 +559,8 @@ BattleScript_Teatimevul: BattleScript_Teatimesorb: call BattleScript_AbilityPopUpTarget tryhealquarterhealth BS_TARGET, BattleScript_Teatimesorb_end - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, PASSIVE_HP_UPDATE + datahpupdate BS_TARGET, PASSIVE_HP_UPDATE printstring STRINGID_PKMNREGAINEDHEALTH waitmessage B_WAIT_TIME_LONG BattleScript_Teatimesorb_end: @@ -765,28 +734,22 @@ BattleScript_EffectFling:: effectivenesssound hitanimation BS_TARGET waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, MOVE_DAMAGE_HP_UPDATE + datahpupdate BS_TARGET, MOVE_DAMAGE_HP_UPDATE critmessage waitmessage B_WAIT_TIME_MED resultmessage waitmessage B_WAIT_TIME_MED jumpiflastuseditemberry BattleScript_EffectFlingConsumeBerry - jumpifability BS_TARGET, ABILITY_SHIELD_DUST, BattleScript_FlingBlockedByShieldDust - jumpiflastuseditemholdeffect HOLD_EFFECT_FLAME_ORB, 0, BattleScript_FlingFlameOrb - jumpiflastuseditemholdeffect HOLD_EFFECT_FLINCH, 0, BattleScript_FlingFlinch - jumpiflastuseditemholdeffect HOLD_EFFECT_LIGHT_BALL, 0, BattleScript_FlingLightBall - jumpiflastuseditemholdeffect HOLD_EFFECT_MENTAL_HERB, 0, BattleScript_FlingMentalHerb - jumpiflastuseditemholdeffect HOLD_EFFECT_TYPE_POWER, TYPE_POISON, BattleScript_FlingPoisonBarb - jumpiflastuseditemholdeffect HOLD_EFFECT_TOXIC_ORB, 0, BattleScript_FlingToxicOrb - jumpiflastuseditemholdeffect HOLD_EFFECT_WHITE_HERB, 0, BattleScript_FlingWhiteHerb + tryflingholdeffect goto BattleScript_FlingEnd + BattleScript_EffectFlingConsumeBerry: savebattleritem battleritemtolastuseditem setbyte sBERRY_OVERRIDE, 1 @ override the requirements for eating berries orword gHitMarker, HITMARKER_DISABLE_ANIMATION - consumeberry BS_TARGET, TRUE + consumeberry BS_TARGET, FALSE bicword gHitMarker, HITMARKER_DISABLE_ANIMATION setbyte sBERRY_OVERRIDE, 0 restorebattleritem @@ -804,39 +767,6 @@ BattleScript_FlingBlockedByShieldDust:: waitmessage B_WAIT_TIME_LONG goto BattleScript_FlingEnd -BattleScript_FlingFlameOrb: - seteffectsecondary BS_ATTACKER, BS_TARGET, MOVE_EFFECT_BURN - goto BattleScript_FlingEnd -BattleScript_FlingFlinch: - seteffectsecondary BS_ATTACKER, BS_TARGET, MOVE_EFFECT_FLINCH - goto BattleScript_FlingEnd -BattleScript_FlingLightBall: - seteffectsecondary BS_ATTACKER, BS_TARGET, MOVE_EFFECT_PARALYSIS - goto BattleScript_FlingEnd -BattleScript_FlingMentalHerb: - curecertainstatuses - savetarget - copybyte gBattlerAttacker, gBattlerTarget - playanimation BS_ATTACKER, B_ANIM_HELD_ITEM_EFFECT, NULL - printfromtable gMentalHerbCureStringIds - waitmessage B_WAIT_TIME_LONG - updatestatusicon BS_ATTACKER - restoretarget - goto BattleScript_FlingEnd -BattleScript_FlingPoisonBarb: - seteffectsecondary BS_ATTACKER, BS_TARGET, MOVE_EFFECT_POISON - goto BattleScript_FlingEnd -BattleScript_FlingToxicOrb: - seteffectsecondary BS_ATTACKER, BS_TARGET, MOVE_EFFECT_TOXIC - goto BattleScript_FlingEnd -BattleScript_FlingWhiteHerb: - tryresetnegativestatstages - swapattackerwithtarget - printstring STRINGID_PKMNSTATUSNORMAL - waitmessage B_WAIT_TIME_MED - swapattackerwithtarget - goto BattleScript_FlingEnd - BattleScript_FlingMissed: removeitem BS_ATTACKER goto BattleScript_MoveMissedPause @@ -844,11 +774,10 @@ BattleScript_FlingMissed: BattleScript_EffectClangorousSoul:: attackcanceler cutonethirdhpandraisestats BattleScript_ButItFailed - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_IGNORE_BIDE | HITMARKER_PASSIVE_HP_UPDATE | HITMARKER_IGNORE_DISGUISE attackanimation waitanimation - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE call BattleScript_AllStatsUp goto BattleScript_MoveEnd @@ -1036,9 +965,8 @@ BattleScript_EffectJungleHealing:: JungleHealing_RestoreTargetHealth: copybyte gBattlerAttacker, gBattlerTarget tryhealquarterhealth BS_TARGET, BattleScript_JungleHealing_TryCureStatus - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, PASSIVE_HP_UPDATE + datahpupdate BS_TARGET, PASSIVE_HP_UPDATE printstring STRINGID_PKMNREGAINEDHEALTH waitmessage B_WAIT_TIME_LONG BattleScript_JungleHealing_TryCureStatus: @@ -1079,10 +1007,9 @@ BattleScript_EffectLifeDewCheckPartner: setallytonexttarget BattleScript_EffectLifeDewNextTarget BattleScript_EffectLifeDewHealing: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE tryhealquarterhealth BS_TARGET, BattleScript_EffectLifeDewEnd - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, PASSIVE_HP_UPDATE + datahpupdate BS_TARGET, PASSIVE_HP_UPDATE printstring STRINGID_PKMNREGAINEDHEALTH waitmessage B_WAIT_TIME_LONG return @@ -1172,10 +1099,9 @@ BattleScript_StrengthSapHp: jumpiffullhp BS_ATTACKER, BattleScript_MoveEnd BattleScript_StrengthSapManipulateDmg: manipulatedamage DMG_BIG_ROOT - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE jumpifability BS_TARGET, ABILITY_LIQUID_OOZE, BattleScript_StrengthSapLiquidOoze - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printstring STRINGID_PKMNENERGYDRAINED waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd @@ -1183,8 +1109,8 @@ BattleScript_StrengthSapLiquidOoze: call BattleScript_AbilityPopUpTarget manipulatedamage DMG_CHANGE_SIGN setbyte cMULTISTRING_CHOOSER, B_MSG_ABSORB_OOZE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printfromtable gAbsorbDrainStringIds waitmessage B_WAIT_TIME_LONG tryfaintmon BS_ATTACKER @@ -1468,7 +1394,7 @@ BattleScript_FlowerShieldMoveTargetEnd: moveendto MOVEEND_NEXT_TARGET jumpifnexttargetvalid BattleScript_FlowerShieldLoop restoretarget - moveendfrom MOVEEND_ITEM_EFFECTS_ATTACKER + moveendfrom MOVEEND_ITEM_EFFECTS_ATTACKER_1 end BattleScript_EffectRototiller:: @@ -1524,6 +1450,7 @@ BattleScript_EffectBestow:: waitanimation printstring STRINGID_BESTOWITEMGIVING waitmessage B_WAIT_TIME_LONG + tryactivateitem BS_TARGET, ACTIVATION_ON_USABLE_AGAIN trysymbiosis BS_ATTACKER goto BattleScript_MoveEnd @@ -1540,9 +1467,8 @@ BattleScript_EffectAfterYou:: BattleScript_MoveEffectFlameBurst:: printstring STRINGID_BURSTINGFLAMESHIT waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_SCRIPTING - datahpupdate BS_SCRIPTING + healthbarupdate BS_SCRIPTING, PASSIVE_HP_UPDATE + datahpupdate BS_SCRIPTING, PASSIVE_HP_UPDATE tryfaintmon BS_SCRIPTING return @@ -1675,8 +1601,8 @@ BattleScript_AutotomizeWeightLoss:: BattleScript_FinalGambit:: setatkhptozero - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE tryfaintmon BS_ATTACKER return @@ -2087,8 +2013,8 @@ BattleScript_EffectHealPulse:: tryhealpulse BattleScript_AlreadyAtFullHp attackanimation waitanimation - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, PASSIVE_HP_UPDATE + datahpupdate BS_TARGET, PASSIVE_HP_UPDATE printstring STRINGID_PKMNREGAINEDHEALTH waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd @@ -2108,23 +2034,6 @@ BattleScript_EffectEntrainment:: tryendneutralizinggas goto BattleScript_MoveEnd -BattleScript_EffectSimpleBeam:: - attackcanceler - accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE - setsimplebeam BattleScript_ButItFailed - attackanimation - waitanimation - copybyte gBattlerAbility, gBattlerTarget - call BattleScript_AbilityPopUpOverwriteThenNormal - recordability BS_TARGET - printstring STRINGID_PKMNACQUIREDSIMPLE - waitmessage B_WAIT_TIME_LONG - trytoclearprimalweather - tryrevertweatherform - flushtextbox - tryendneutralizinggas - goto BattleScript_MoveEnd - BattleScript_EffectLuckyChant:: attackcanceler setluckychant BattleScript_ButItFailed @@ -2188,8 +2097,8 @@ BattleScript_EffectHealingWishRestore: waitanimation dmgtomaxattackerhp manipulatedamage DMG_CHANGE_SIGN - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE clearstatus waitstate updatestatusicon BS_ATTACKER @@ -2198,10 +2107,10 @@ BattleScript_EffectHealingWishRestore: waitmessage B_WAIT_TIME_LONG return -BattleScript_EffectWorrySeed:: +BattleScript_EffectOverwriteAbility:: attackcanceler accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE - tryworryseed BattleScript_ButItFailed + tryoverwriteability BattleScript_ButItFailed attackanimation waitanimation copybyte gBattlerAbility, gBattlerTarget @@ -2440,6 +2349,7 @@ BattleScript_EffectMiracleEye:: accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE setvolatile BS_TARGET, VOLATILE_MIRACLE_EYE goto BattleScript_IdentifiedFoe + BattleScript_EffectGravity:: call BattleScript_EffectGravityInternal goto BattleScript_MoveEnd @@ -2542,8 +2452,8 @@ BattleScript_Hit_RetFromAtkAnimation:: effectivenesssound hitanimation BS_TARGET waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, MOVE_DAMAGE_HP_UPDATE + datahpupdate BS_TARGET, MOVE_DAMAGE_HP_UPDATE critmessage waitmessage B_WAIT_TIME_LONG resultmessage @@ -2670,15 +2580,16 @@ BattleScript_CantMakeAsleep:: BattleScript_EffectAbsorbLiquidOoze:: call BattleScript_AbilityPopUpTarget + jumpifability BS_ATTACKER, ABILITY_MAGIC_GUARD, BattleScript_EffectAbsorbRet goto BattleScript_EffectAbsorb BattleScript_EffectAbsorb:: - absorbhealthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printfromtable gAbsorbDrainStringIds waitmessage B_WAIT_TIME_LONG tryfaintmon BS_ATTACKER - bicword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE | HITMARKER_PASSIVE_HP_UPDATE +BattleScript_EffectAbsorbRet: return BattleScript_EffectExplosion:: @@ -2695,9 +2606,8 @@ BattleScript_FaintAttackerForExplosion:: return BattleScript_MaxHp50Recoil:: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE tryfaintmon BS_ATTACKER return @@ -2904,9 +2814,8 @@ BattleScript_EffectRestoreHp:: attackanimation waitanimation BattleScript_RestoreHp: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printstring STRINGID_PKMNREGAINEDHEALTH waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd @@ -2934,9 +2843,13 @@ BattleScript_EffectLightScreen:: BattleScript_EffectRest:: attackcanceler -.if B_LEAF_GUARD_PREVENTS_REST >= GEN_5 - jumpifleafguardprotected BS_TARGET, BattleScript_LeafGuardPreventsRest -.endif + jumpifstatus BS_ATTACKER, STATUS1_SLEEP, BattleScript_RestIsAlreadyAsleep + jumpifability BS_ATTACKER, ABILITY_COMATOSE, BattleScript_RestIsAlreadyAsleep + jumpifuproarwakes BattleScript_RestCantSleep + jumpifability BS_TARGET, ABILITY_INSOMNIA, BattleScript_InsomniaProtects + jumpifability BS_TARGET, ABILITY_VITAL_SPIRIT, BattleScript_InsomniaProtects + jumpifability BS_ATTACKER, ABILITY_PURIFYING_SALT, BattleScript_InsomniaProtects + jumpifabilitypreventsrest BS_TARGET, BattleScript_AbilityPreventsRest trysetrest pause B_WAIT_TIME_SHORT printfromtable gRestUsedStringIds @@ -2958,7 +2871,7 @@ BattleScript_RestIsAlreadyAsleep:: waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd -BattleScript_LeafGuardPreventsRest:: +BattleScript_AbilityPreventsRest:: pause B_WAIT_TIME_SHORT printstring STRINGID_BUTITFAILED waitmessage B_WAIT_TIME_LONG @@ -2969,7 +2882,6 @@ BattleScript_EffectOHKO:: typecalc jumpifmovehadnoeffect BattleScript_HitFromAtkAnimation tryKO BattleScript_KOFail - trysetdestinybondtohappen goto BattleScript_HitFromAtkAnimation BattleScript_KOFail:: pause B_WAIT_TIME_LONG @@ -2981,10 +2893,10 @@ BattleScript_RecoilIfMiss:: printstring STRINGID_PKMNCRASHED waitmessage B_WAIT_TIME_LONG jumpifability BS_ATTACKER, ABILITY_MAGIC_GUARD, BattleScript_RecoilEnd - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE | HITMARKER_IGNORE_DISGUISE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE tryfaintmon BS_ATTACKER +BattleScript_RecoilEnd: return BattleScript_EffectMist:: @@ -3144,7 +3056,6 @@ BattleScript_PowerHerbActivation: BattleScript_EffectTwoTurnsAttack:: jumpifvolatile BS_ATTACKER, VOLATILE_MULTIPLETURNS, BattleScript_TwoTurnMovesSecondTurn tryfiretwoturnmovewithoutcharging BS_ATTACKER, BattleScript_EffectHit @ e.g. Solar Beam - jumpifword CMP_COMMON_BITS, gHitMarker, HITMARKER_ATTACKSTRING_PRINTED, BattleScript_EffectHit @ if it's not the first hit call BattleScript_FirstChargingTurn tryfiretwoturnmoveaftercharging BS_ATTACKER, BattleScript_TwoTurnMovesSecondTurn @ e.g. Electro Shot jumpifholdeffect BS_ATTACKER, HOLD_EFFECT_POWER_HERB, BattleScript_TwoTurnMovesSecondPowerHerbActivates, TRUE @@ -3221,11 +3132,10 @@ BattleScript_EffectSubstitute:: jumpifvolatile BS_ATTACKER, VOLATILE_SUBSTITUTE, BattleScript_AlreadyHasSubstitute setsubstitute jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_SUBSTITUTE_FAILED, BattleScript_SubstituteString - orword gHitMarker, HITMARKER_PASSIVE_HP_UPDATE attackanimation waitanimation - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE BattleScript_SubstituteString:: pause B_WAIT_TIME_SHORT printfromtable gSubstituteUsedStringIds @@ -3345,11 +3255,10 @@ BattleScript_EffectPainSplit:: painsplitdmgcalc BattleScript_ButItFailed attackanimation waitanimation - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE + healthbarupdate BS_TARGET, PASSIVE_HP_UPDATE + datahpupdate BS_TARGET, PASSIVE_HP_UPDATE printstring STRINGID_SHAREDPAIN waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd @@ -3525,12 +3434,11 @@ BattleScript_DoGhostCurse:: attackcanceler accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON cursetarget BattleScript_ButItFailed - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE setbyte sB_ANIM_TURN, 0 attackanimation waitanimation - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printstring STRINGID_PKMNLAIDCURSE waitmessage B_WAIT_TIME_LONG tryfaintmon BS_ATTACKER @@ -3643,26 +3551,27 @@ BattleScript_FuryCutterHit: BattleScript_TryDestinyKnotTarget: jumpifnoholdeffect BS_ATTACKER, HOLD_EFFECT_DESTINY_KNOT, BattleScript_TryDestinyKnotTargetRet - infatuatewithbattler BS_TARGET, BS_ATTACKER playanimation BS_ATTACKER, B_ANIM_HELD_ITEM_EFFECT waitanimation + printstring STRINGID_DESTINYKNOTACTIVATES + tryinfatuating BattleScript_ButItFailed volatileanimation BS_TARGET, VOLATILE_INFATUATION waitanimation - printstring STRINGID_DESTINYKNOTACTIVATES waitmessage B_WAIT_TIME_LONG BattleScript_TryDestinyKnotTargetRet: return BattleScript_TryDestinyKnotAttacker: - jumpifnoholdeffect BS_TARGET, HOLD_EFFECT_DESTINY_KNOT, BattleScript_TryDestinyKnotAttackerRet - infatuatewithbattler BS_ATTACKER, BS_TARGET + jumpifnoholdeffect BS_TARGET, HOLD_EFFECT_DESTINY_KNOT, BattleScript_TryDestinyKnotTargetRet playanimation BS_TARGET, B_ANIM_HELD_ITEM_EFFECT waitanimation + swapattackerwithtarget + printstring STRINGID_DESTINYKNOTACTIVATES + tryinfatuating BattleScript_SwapTargetAttackerButItFailed + swapattackerwithtarget volatileanimation BS_ATTACKER, VOLATILE_INFATUATION waitanimation - printstring STRINGID_DESTINYKNOTACTIVATES waitmessage B_WAIT_TIME_LONG -BattleScript_TryDestinyKnotAttackerRet: return BattleScript_EffectAttract:: @@ -3819,13 +3728,12 @@ BattleScript_BlockedByPrimalWeatherRet:: BattleScript_EffectBellyDrum:: attackcanceler - jumpifstat BS_ATTACKER, CMP_EQUAL, STAT_ATK, MAX_STAT_STAGE, BattleScript_ButItFailed + jumpifstatignorecontrary BS_ATTACKER, CMP_EQUAL, STAT_ATK, MAX_STAT_STAGE, BattleScript_ButItFailed halvehp BattleScript_ButItFailed - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE attackanimation waitanimation - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE setstatchanger STAT_ATK, MAX_STAT_STAGE, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_MoveEnd printstring STRINGID_PKMNCUTHPMAXEDATTACK @@ -3897,8 +3805,8 @@ BattleScript_BeatUpAttack:: effectivenesssound hitanimation BS_TARGET waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, MOVE_DAMAGE_HP_UPDATE + datahpupdate BS_TARGET, MOVE_DAMAGE_HP_UPDATE critmessage waitmessage B_WAIT_TIME_LONG resultmessage @@ -3926,9 +3834,8 @@ BattleScript_EffectSoftboiled:: BattleScript_PresentHealTarget:: attackanimation waitanimation - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, PASSIVE_HP_UPDATE + datahpupdate BS_TARGET, PASSIVE_HP_UPDATE printstring STRINGID_PKMNREGAINEDHEALTH waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd @@ -3953,6 +3860,9 @@ BattleScript_RestoreAttackerButItFailed: BattleScript_RestoreTargetButItFailed: restoretarget goto BattleScript_ButItFailed +BattleScript_SwapTargetAttackerButItFailed: + swapattackerwithtarget + goto BattleScript_ButItFailed BattleScript_NotAffected:: pause B_WAIT_TIME_SHORT @@ -4037,9 +3947,8 @@ BattleScript_EffectSwallow:: stockpiletohpheal BattleScript_ButItFailed attackanimation waitanimation - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, PASSIVE_HP_UPDATE + datahpupdate BS_TARGET, PASSIVE_HP_UPDATE printstring STRINGID_PKMNREGAINEDHEALTH waitmessage B_WAIT_TIME_LONG removestockpilecounters @@ -4279,8 +4188,8 @@ BattleScript_BrickBreakDoHit:: effectivenesssound hitanimation BS_TARGET waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, MOVE_DAMAGE_HP_UPDATE + datahpupdate BS_TARGET, MOVE_DAMAGE_HP_UPDATE critmessage waitmessage B_WAIT_TIME_LONG resultmessage @@ -4531,39 +4440,22 @@ BattleScript_EffectCamouflage:: waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd -BattleScript_FaintAttacker:: - tryillusionoff BS_ATTACKER +BattleScript_FaintBattler:: + tryillusionoff BS_FAINTED tryactivategulpmissile - playfaintcry BS_ATTACKER + playfaintcry BS_FAINTED pause B_WAIT_TIME_LONG - dofaintanimation BS_ATTACKER - printstring STRINGID_ATTACKERFAINTED - cleareffectsonfaint BS_ATTACKER + dofaintanimation BS_FAINTED + copybyte sBATTLER, gBattlerFainted @ for message + printstring STRINGID_BATTLERFAINTED + cleareffectsonfaint BS_FAINTED trytoclearprimalweather tryrevertweatherform flushtextbox waitanimation + tryactivatereceiver BS_FAINTED tryactivatesoulheart - tryactivatereceiver BS_ATTACKER - trytrainerslidemsgfirstoff BS_ATTACKER - return - -BattleScript_FaintTarget:: - tryillusionoff BS_TARGET - tryactivategulpmissile - tryupdateleaderscresttracker - playfaintcry BS_TARGET - pause B_WAIT_TIME_LONG - dofaintanimation BS_TARGET - printstring STRINGID_TARGETFAINTED - cleareffectsonfaint BS_TARGET - trytoclearprimalweather - tryrevertweatherform - flushtextbox - waitanimation - tryactivatesoulheart - tryactivatereceiver BS_TARGET - trytrainerslidemsgfirstoff BS_TARGET + trytrainerslidemsgfirstoff BS_FAINTED return BattleScript_GiveExp:: @@ -4978,8 +4870,8 @@ BattleScript_FogEnded_Ret:: BattleScript_IceBodyHeal:: call BattleScript_AbilityPopUp playanimation BS_ATTACKER, B_ANIM_SIMPLE_HEAL - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printstring STRINGID_ICEBODYHPGAIN waitmessage B_WAIT_TIME_LONG end2 @@ -5046,7 +4938,7 @@ BattleScript_MagicRoomEnds:: setbyte gBattlerTarget, 0 BattleScript_MagicRoomHealingItemsLoop: copyarraywithindex gBattlerAttacker, gBattlerByTurnOrder, gBattlerTarget, 1 - tryrestorehpberry BS_ATTACKER + tryactivateitem BS_ATTACKER, ACTIVATION_ON_USABLE_AGAIN addbyte gBattlerTarget, 1 jumpifbytenotequal gBattlerTarget, gBattlersCount, BattleScript_MagicRoomHealingItemsLoop end2 @@ -5097,18 +4989,19 @@ BattleScript_LeechSeedTurnDrainLiquidOoze:: copybyte gBattlerAbility, gBattlerAttacker call BattleScript_AbilityPopUp copybyte gBattlerAttacker, gBattlerTarget @ needed to get liquid ooze message correct + jumpifability BS_TARGET, ABILITY_MAGIC_GUARD, BattleScript_LeechSeedTurnDrainHealBlockEnd2 goto BattleScript_LeechSeedTurnDrainGainHp BattleScript_LeechSeedTurnDrainHealBlock:: call BattleScript_LeechSeedTurnDrain +BattleScript_LeechSeedTurnDrainHealBlockEnd2: end2 BattleScript_LeechSeedTurnDrainRecovery:: call BattleScript_LeechSeedTurnDrain BattleScript_LeechSeedTurnDrainGainHp: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, PASSIVE_HP_UPDATE + datahpupdate BS_TARGET, PASSIVE_HP_UPDATE printfromtable gLeechSeedStringIds waitmessage B_WAIT_TIME_LONG tryfaintmon BS_TARGET @@ -5116,8 +5009,8 @@ BattleScript_LeechSeedTurnDrainGainHp: BattleScript_LeechSeedTurnDrain: playanimation BS_ATTACKER, B_ANIM_LEECH_SEED_DRAIN, sB_ANIM_ARG1 - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE tryfaintmon BS_ATTACKER return @@ -5142,8 +5035,8 @@ BattleScript_BideAttack:: effectivenesssound hitanimation BS_TARGET waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, MOVE_DAMAGE_HP_UPDATE + datahpupdate BS_TARGET, MOVE_DAMAGE_HP_UPDATE resultmessage waitmessage B_WAIT_TIME_LONG tryfaintmon BS_TARGET @@ -5291,16 +5184,14 @@ BattleScript_EncoredNoMore:: BattleScript_DestinyBondTakesLife:: printstring STRINGID_PKMNTOOKFOE waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE tryfaintmon BS_ATTACKER return BattleScript_DmgHazardsOnAttacker:: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE call BattleScript_PrintHurtByDmgHazards tryfaintmon BS_ATTACKER tryfaintmon_spikes BS_ATTACKER, BattleScript_DmgHazardsOnAttackerFainted @@ -5313,9 +5204,8 @@ BattleScript_DmgHazardsOnAttackerFainted:: goto BattleScript_HandleFaintedMon BattleScript_DmgHazardsOnTarget:: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, PASSIVE_HP_UPDATE + datahpupdate BS_TARGET, PASSIVE_HP_UPDATE call BattleScript_PrintHurtByDmgHazards tryfaintmon BS_TARGET tryfaintmon_spikes BS_TARGET, BattleScript_DmgHazardsOnTargetFainted @@ -5328,9 +5218,8 @@ BattleScript_DmgHazardsOnTargetFainted:: goto BattleScript_HandleFaintedMon BattleScript_DmgHazardsOnBattlerScripting:: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_SCRIPTING - datahpupdate BS_SCRIPTING + healthbarupdate BS_SCRIPTING, PASSIVE_HP_UPDATE + datahpupdate BS_SCRIPTING, PASSIVE_HP_UPDATE call BattleScript_PrintHurtByDmgHazards tryfaintmon BS_SCRIPTING tryfaintmon_spikes BS_SCRIPTING, BattleScript_DmgHazardsOnBattlerScriptingFainted @@ -5343,9 +5232,8 @@ BattleScript_DmgHazardsOnBattlerScriptingFainted:: goto BattleScript_HandleFaintedMon BattleScript_DmgHazardsOnFaintedBattler:: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_FAINTED - datahpupdate BS_FAINTED + healthbarupdate BS_FAINTED, PASSIVE_HP_UPDATE + datahpupdate BS_FAINTED, PASSIVE_HP_UPDATE call BattleScript_PrintHurtByDmgHazards tryfaintmon BS_FAINTED tryfaintmon_spikes BS_FAINTED, BattleScript_DmgHazardsOnFaintedBattlerFainted @@ -5404,9 +5292,8 @@ BattleScript_StickyWebOnSwitchInEnd: BattleScript_PerishSongTakesLife:: printstring STRINGID_PKMNPERISHCOUNTFELL waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE tryfaintmon BS_ATTACKER end2 @@ -5414,20 +5301,18 @@ BattleScript_PerishBodyActivates:: call BattleScript_AbilityPopUp printstring STRINGID_PKMNSWILLPERISHIN3TURNS waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE return BattleScript_GulpMissileGorging:: call BattleScript_AbilityPopUp playanimation BS_ATTACKER, B_ANIM_GULP_MISSILE waitanimation - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE effectivenesssound hitanimation BS_ATTACKER waitstate jumpifability BS_ATTACKER, ABILITY_MAGIC_GUARD, BattleScript_GulpMissileNoDmgGorging - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE tryfaintmon BS_ATTACKER jumpiffainted BS_ATTACKER, TRUE, BattleScript_GulpMissileNoSecondEffectGorging BattleScript_GulpMissileNoDmgGorging: @@ -5448,13 +5333,12 @@ BattleScript_GulpMissileGulping:: call BattleScript_AbilityPopUp playanimation BS_ATTACKER, B_ANIM_GULP_MISSILE waitanimation - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE effectivenesssound hitanimation BS_ATTACKER waitstate jumpifability BS_ATTACKER, ABILITY_MAGIC_GUARD, BattleScript_GulpMissileNoDmgGulping - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE tryfaintmon BS_ATTACKER jumpiffainted BS_ATTACKER, TRUE, BattleScript_GulpMissileNoSecondEffectGulping BattleScript_GulpMissileNoDmgGulping: @@ -5492,7 +5376,6 @@ BattleScript_BerserkActivates:: call BattleScript_StatUp BattleScript_BerserkActivatesTryBerry: restoreattacker - tryrestorehpberry BS_EFFECT_BATTLER return BattleScript_AngerShellActivates:: @@ -5513,7 +5396,6 @@ BattleScript_AngerShellTrySpAtk: BattleScript_AngerShellTrySpeed: modifybattlerstatstage BS_EFFECT_BATTLER, STAT_SPEED, INCREASE, 1, BattleScript_AngerShellRet, ANIM_ON BattleScript_AngerShellRet: - tryrestorehpberry BS_EFFECT_BATTLER return BattleScript_WindPowerActivates:: @@ -5530,18 +5412,16 @@ BattleScript_ToxicDebrisActivates:: printstring STRINGID_POISONSPIKESSCATTERED waitmessage B_WAIT_TIME_LONG BattleScript_ToxicDebrisRet: - copybyte sBATTLER, gBattlerTarget - copybyte gBattlerTarget, gBattlerAttacker - copybyte gBattlerAttacker, sBATTLER + restoretarget + restoreattacker return BattleScript_EarthEaterActivates:: call BattleScript_AbilityPopUp pause B_WAIT_TIME_LONG tryhealquarterhealth BS_TARGET, BattleScript_EarthEaterRet - orword gHitMarker, HITMARKER_IGNORE_BIDE | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, PASSIVE_HP_UPDATE + datahpupdate BS_TARGET, PASSIVE_HP_UPDATE printstring STRINGID_PKMNREGAINEDHEALTH waitmessage B_WAIT_TIME_LONG BattleScript_EarthEaterRet: @@ -5636,8 +5516,8 @@ BattleScript_DoFutureAttackHit:: effectivenesssound hitanimation BS_TARGET waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, MOVE_DAMAGE_HP_UPDATE + datahpupdate BS_TARGET, MOVE_DAMAGE_HP_UPDATE critmessage waitmessage B_WAIT_TIME_LONG BattleScript_DoFutureAttackResult: @@ -5650,15 +5530,17 @@ BattleScript_FutureAttackEnd:: moveendcase MOVEEND_RAGE moveendcase MOVEEND_ABILITIES moveendcase MOVEEND_COLOR_CHANGE - moveendfromto MOVEEND_ITEM_EFFECTS_ALL, MOVEEND_UPDATE_LAST_MOVES - setmoveresultflags 0 - end2 + moveendcase MOVEEND_ITEM_EFFECTS_TARGET + moveendfromto MOVEEND_SYMBIOSIS, MOVEEND_UPDATE_LAST_MOVES + goto BattleScript_FutureAttackClearResults BattleScript_FutureAttackMiss:: pause B_WAIT_TIME_SHORT setmoveresultflags MOVE_RESULT_FAILED resultmessage waitmessage B_WAIT_TIME_LONG +BattleScript_FutureAttackClearResults: setmoveresultflags 0 + clearspecialstatuses end2 BattleScript_NoMovesLeft:: @@ -5782,9 +5664,8 @@ BattleScript_WishComesTrue:: playanimation BS_TARGET, B_ANIM_WISH_HEAL printstring STRINGID_PKMNWISHCAMETRUE waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_IGNORE_DISGUISE - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, PASSIVE_HP_UPDATE + datahpupdate BS_TARGET, PASSIVE_HP_UPDATE printstring STRINGID_PKMNREGAINEDHEALTH waitmessage B_WAIT_TIME_LONG end2 @@ -5810,9 +5691,8 @@ BattleScript_IngrainTurnHeal:: printstring STRINGID_PKMNABSORBEDNUTRIENTS BattleScript_TurnHeal: waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE end2 BattleScript_AquaRingHeal:: @@ -6094,9 +5974,8 @@ BattleScript_CudChewActivates:: BattleScript_ApplyDisguiseFormChangeHPLoss:: jumpifgenconfiglowerthan GEN_CONFIG_DISGUISE_HP_LOSS, GEN_8, BattleScript_ApplyDisguiseFormChangeHPLossReturn - orword gHitMarker, HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_SCRIPTING - datahpupdate BS_SCRIPTING + healthbarupdate BS_SCRIPTING, PASSIVE_HP_UPDATE + datahpupdate BS_SCRIPTING, PASSIVE_HP_UPDATE BattleScript_ApplyDisguiseFormChangeHPLossReturn: return @@ -6185,9 +6064,8 @@ BattleScript_AftermathDmg:: pause B_WAIT_TIME_SHORT call BattleScript_AbilityPopUpScripting jumpifability BS_ATTACKER, ABILITY_MAGIC_GUARD, BattleScript_AftermathDmgRet - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printstring STRINGID_AFTERMATHDMG waitmessage B_WAIT_TIME_LONG tryfaintmon BS_ATTACKER @@ -6228,12 +6106,11 @@ BattleScript_PoisonTurnDmg:: BattleScript_DoStatusTurnDmg:: statusanimation BS_ATTACKER BattleScript_DoTurnDmg: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE tryfaintmon BS_ATTACKER checkteamslost BattleScript_DoTurnDmgEnd - tryrestorehpberry BS_ATTACKER + tryactivateitem BS_ATTACKER, ACTIVATION_ON_HP_THRESHOLD BattleScript_DoTurnDmgEnd: end2 @@ -6243,9 +6120,8 @@ BattleScript_PoisonHealActivates:: printstring STRINGID_POISONHEALHPUP waitmessage B_WAIT_TIME_LONG statusanimation BS_ATTACKER - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE end2 BattleScript_BurnTurnDmg:: @@ -6299,10 +6175,11 @@ BattleScript_PowderMoveNoEffect:: pause B_WAIT_TIME_SHORT jumpiftype BS_TARGET, TYPE_GRASS, BattleScript_PowderMoveNoEffectPrint jumpifability BS_TARGET, ABILITY_OVERCOAT, BattleScript_PowderMoveNoEffectOvercoat + setlastuseditem BS_TARGET printstring STRINGID_SAFETYGOGGLESPROTECTED goto BattleScript_PowderMoveNoEffectWaitMsg BattleScript_PowderMoveNoEffectOvercoat: - call BattleScript_AbilityPopUp + call BattleScript_AbilityPopUpTarget BattleScript_PowderMoveNoEffectPrint: printstring STRINGID_ITDOESNTAFFECT BattleScript_PowderMoveNoEffectWaitMsg: @@ -6314,7 +6191,7 @@ BattleScript_PowderMoveNoEffectWaitMsg: BattleScript_MoveUsedFlinched:: printstring STRINGID_PKMNFLINCHED waitmessage B_WAIT_TIME_LONG - waitmessage B_WAIT_TIME_LONG + jumpifability BS_ATTACKER, ABILITY_STEADFAST, BattleScript_TryActivateSteadFast BattleScript_MoveUsedFlinchedEnd: goto BattleScript_MoveEnd BattleScript_TryActivateSteadFast: @@ -6324,7 +6201,7 @@ BattleScript_TryActivateSteadFast: copybyte gBattlerAbility, gBattlerAttacker call BattleScript_AbilityPopUp statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_MoveUsedFlinchedEnd - setbyte gBattleCommunication STAT_SPEED + setbyte gBattleCommunication, STAT_SPEED stattextbuffer printstring STRINGID_ATTACKERABILITYSTATRAISE waitmessage B_WAIT_TIME_LONG @@ -6354,9 +6231,9 @@ BattleScript_DoSelfConfusionDmg:: effectivenesssound hitanimation BS_ATTACKER waitstate - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + isdmgblockedbydisguise + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE resultmessage waitmessage B_WAIT_TIME_LONG tryfaintmon BS_ATTACKER @@ -6372,9 +6249,8 @@ BattleScript_MoveUsedPowder:: effectivenesssound hitanimation BS_ATTACKER waitstate - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printstring STRINGID_POWDEREXPLODES waitmessage B_WAIT_TIME_LONG tryfaintmon BS_ATTACKER @@ -6475,7 +6351,7 @@ BattleScript_YawnEnd: BattleScript_EmbargoEndTurn:: printstring STRINGID_EMBARGOENDS waitmessage B_WAIT_TIME_LONG - tryrestorehpberry BS_ATTACKER + tryactivateitem BS_ATTACKER, ACTIVATION_ON_USABLE_AGAIN end2 BattleScript_TelekinesisEndTurn:: @@ -6558,22 +6434,15 @@ BattleScript_MoveEffectConfusion:: return BattleScript_MoveEffectRecoil:: - jumpifmove MOVE_STRUGGLE, BattleScript_DoRecoil - jumpifability BS_ATTACKER, ABILITY_ROCK_HEAD, BattleScript_RecoilEnd - jumpifability BS_ATTACKER, ABILITY_MAGIC_GUARD, BattleScript_RecoilEnd -BattleScript_DoRecoil:: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE | HITMARKER_IGNORE_DISGUISE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printstring STRINGID_PKMNHITWITHRECOIL waitmessage B_WAIT_TIME_LONG - tryupdaterecoiltracker tryfaintmon BS_ATTACKER -BattleScript_RecoilEnd:: return BattleScript_ItemSteal:: - playanimation BS_TARGET, B_ANIM_ITEM_STEAL + playanimation BS_EFFECT_BATTLER, B_ANIM_ITEM_STEAL printstring STRINGID_PKMNSTOLEITEM waitmessage B_WAIT_TIME_LONG return @@ -6737,15 +6606,15 @@ BattleScript_ReceiverActivates:: printstring STRINGID_RECEIVERABILITYTAKEOVER waitmessage B_WAIT_TIME_LONG settracedability BS_ABILITY_BATTLER + switchinabilities BS_ABILITY_BATTLER return BattleScript_AbilityHpHeal: call BattleScript_AbilityPopUp printstring STRINGID_PKMNSXRESTOREDHPALITTLE2 waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE return BattleScript_RainDishActivates:: @@ -6765,7 +6634,7 @@ BattleScript_PickupActivates:: call BattleScript_AbilityPopUp printstring STRINGID_XFOUNDONEY waitmessage B_WAIT_TIME_LONG - tryrestorehpberry BS_ATTACKER + tryactivateitem BS_ATTACKER, ACTIVATION_ON_PICK_UP BattleScript_PickupActivatesEnd: end2 @@ -6775,15 +6644,14 @@ BattleScript_HarvestActivates:: call BattleScript_AbilityPopUp printstring STRINGID_HARVESTBERRY waitmessage B_WAIT_TIME_LONG - tryrestorehpberry BS_ATTACKER + tryactivateitem BS_ATTACKER, ACTIVATION_ON_HARVEST BattleScript_HarvestActivatesEnd: end2 BattleScript_SolarPowerActivates:: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE call BattleScript_AbilityPopUp - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printstring STRINGID_SOLARPOWERHPDROP waitmessage B_WAIT_TIME_LONG tryfaintmon BS_ATTACKER @@ -7067,10 +6935,9 @@ BattleScript_HospitalityActivates:: call BattleScript_AbilityPopUp printstring STRINGID_HOSPITALITYRESTORATION waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE playanimation BS_EFFECT_BATTLER, B_ANIM_SIMPLE_HEAL - healthbarupdate BS_EFFECT_BATTLER - datahpupdate BS_EFFECT_BATTLER + healthbarupdate BS_EFFECT_BATTLER, PASSIVE_HP_UPDATE + datahpupdate BS_EFFECT_BATTLER, PASSIVE_HP_UPDATE end3 BattleScript_AttackWeakenedByStrongWinds:: @@ -7172,9 +7039,8 @@ BattleScript_BadDreams_DmgAfterPopUp: printstring STRINGID_BADDREAMSDMG waitmessage B_WAIT_TIME_LONG dmg_1_8_targethp - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, PASSIVE_HP_UPDATE + datahpupdate BS_TARGET, PASSIVE_HP_UPDATE jumpifhasnohp BS_TARGET, BattleScript_BadDreams_HidePopUp BattleScript_BadDreamsIncrement: addbyte gBattlerTarget, 1 @@ -7219,9 +7085,8 @@ BattleScript_DampStopsExplosion:: BattleScript_MoveHPDrain:: pause B_WAIT_TIME_SHORT call BattleScript_AbilityPopUp - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, PASSIVE_HP_UPDATE + datahpupdate BS_TARGET, PASSIVE_HP_UPDATE printstring STRINGID_PKMNRESTOREDHPUSING waitmessage B_WAIT_TIME_LONG setmoveresultflags MOVE_RESULT_DOESNT_AFFECT_FOE @@ -7298,6 +7163,7 @@ BattleScript_FlinchPrevention:: BattleScript_OwnTempoPrevents:: pause B_WAIT_TIME_SHORT call BattleScript_AbilityPopUp + copybyte sBATTLER, gBattlerTarget printstring STRINGID_PKMNPREVENTSCONFUSIONWITH waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd @@ -7331,10 +7197,8 @@ BattleScript_MoveUsedPsychicTerrainPrevents:: BattleScript_GrassyTerrainHeals:: printstring STRINGID_GRASSYTERRAINHEALS waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_BIDE | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER - bicword gHitMarker, HITMARKER_IGNORE_BIDE | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE end2 BattleScript_AbilityNoSpecificStatLoss:: @@ -7347,11 +7211,15 @@ BattleScript_AbilityNoSpecificStatLoss:: return BattleScript_StickyHoldActivates:: + call BattleScript_StickyHoldActivatesRet + goto BattleScript_MoveEnd + +BattleScript_StickyHoldActivatesRet:: pause B_WAIT_TIME_SHORT call BattleScript_AbilityPopUp printstring STRINGID_PKMNSXMADEYINEFFECTIVE waitmessage B_WAIT_TIME_LONG - goto BattleScript_MoveEnd + return BattleScript_ColorChangeActivates:: call BattleScript_AbilityPopUp @@ -7575,9 +7443,8 @@ BattleScript_ImposterActivates:: end3 BattleScript_HurtAttacker: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printstring STRINGID_PKMNHURTSWITH waitmessage B_WAIT_TIME_LONG tryfaintmon BS_ATTACKER @@ -7599,10 +7466,9 @@ BattleScript_RockyHelmetActivatesDmg: BattleScript_SpikyShieldEffect:: jumpifabsent BS_ATTACKER, BattleScript_SpikyShieldRet - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE clearmoveresultflags MOVE_RESULT_NO_EFFECT - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printstring STRINGID_PKMNHURTSWITH waitmessage B_WAIT_TIME_LONG tryfaintmon BS_ATTACKER @@ -7611,7 +7477,6 @@ BattleScript_SpikyShieldRet:: return BattleScript_KingsShieldEffect:: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE clearmoveresultflags MOVE_RESULT_NO_EFFECT seteffectsecondary BS_ATTACKER, BS_TARGET, MOVE_EFFECT_NONE copybyte sBATTLER, gBattlerTarget @@ -7621,7 +7486,6 @@ BattleScript_KingsShieldEffect:: return BattleScript_BanefulBunkerEffect:: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE clearmoveresultflags MOVE_RESULT_NO_EFFECT setnonvolatilestatus TRIGGER_ON_PROTECT setmoveresultflags MOVE_RESULT_MISSED @@ -7636,11 +7500,13 @@ BattleScript_CuteCharmActivates:: return BattleScript_GooeyActivates:: + statbuffchange BS_ATTACKER, STAT_CHANGE_ONLY_CHECKING, BattleScript_GooeyActivatesRet waitstate call BattleScript_AbilityPopUp swapattackerwithtarget @ for defiant, mirror armor seteffectsecondary BS_ATTACKER, BS_TARGET, MOVE_EFFECT_SPD_MINUS_1 swapattackerwithtarget +BattleScript_GooeyActivatesRet: return BattleScript_AbilityStatusEffect:: @@ -7708,6 +7574,13 @@ BattleScript_AbilityCuredStatus:: updatestatusicon BS_SCRIPTING return +BattleScript_AbilityCuredStatusEnd3:: + call BattleScript_AbilityPopUp + printstring STRINGID_PKMNSXCUREDITSYPROBLEM + waitmessage B_WAIT_TIME_LONG + updatestatusicon BS_SCRIPTING + end3 + BattleScript_BattlerShookOffTaunt:: call BattleScript_AbilityPopUp printstring STRINGID_PKMNSHOOKOFFTHETAUNT @@ -7765,73 +7638,13 @@ BattleScript_SubstituteFade:: printstring STRINGID_PKMNSUBSTITUTEFADED return -BattleScript_BerryCurePrlzEnd2:: - call BattleScript_BerryCureParRet +BattleScript_BerryCureStatusEnd2:: + call BattleScript_BerryCureStatusRet end2 -BattleScript_BerryCureParRet:: +BattleScript_BerryCureStatusRet:: playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT - printstring STRINGID_PKMNSITEMCUREDPARALYSIS - waitmessage B_WAIT_TIME_LONG - updatestatusicon BS_SCRIPTING - removeitem BS_SCRIPTING - return - -BattleScript_BerryCurePsnEnd2:: - call BattleScript_BerryCurePsnRet - end2 - -BattleScript_BerryCurePsnRet:: - playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT - printstring STRINGID_PKMNSITEMCUREDPOISON - waitmessage B_WAIT_TIME_LONG - updatestatusicon BS_SCRIPTING - removeitem BS_SCRIPTING - return - -BattleScript_BerryCureBrnEnd2:: - call BattleScript_BerryCureBrnRet - end2 - -BattleScript_BerryCureBrnRet:: - playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT - printstring STRINGID_PKMNSITEMHEALEDBURN - waitmessage B_WAIT_TIME_LONG - updatestatusicon BS_SCRIPTING - removeitem BS_SCRIPTING - return - -BattleScript_BerryCureFrzEnd2:: - call BattleScript_BerryCureFrzRet - end2 - -BattleScript_BerryCureFrzRet:: - playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT - printstring STRINGID_PKMNSITEMDEFROSTEDIT - waitmessage B_WAIT_TIME_LONG - updatestatusicon BS_SCRIPTING - removeitem BS_SCRIPTING - return - -BattleScript_BerryCureFrbEnd2:: - call BattleScript_BerryCureFrzRet - end2 - -BattleScript_BerryCureFrbRet:: - playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT - printstring STRINGID_PKMNSITEMHEALEDFROSTBITE - waitmessage B_WAIT_TIME_LONG - updatestatusicon BS_SCRIPTING - removeitem BS_SCRIPTING - return - -BattleScript_BerryCureSlpEnd2:: - call BattleScript_BerryCureSlpRet - end2 - -BattleScript_BerryCureSlpRet:: - playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT - printstring STRINGID_PKMNSITEMWOKEIT + printfromtable CureStatusBerryEffectStringID waitmessage B_WAIT_TIME_LONG updatestatusicon BS_SCRIPTING removeitem BS_SCRIPTING @@ -7866,25 +7679,12 @@ BattleScript_BerryCureConfusionRet:: removeitem BS_SCRIPTING return -BattleScript_BerryCureChosenStatusEnd2:: - call BattleScript_BerryCureChosenStatusRet - end2 - -BattleScript_BerryCureChosenStatusRet:: - playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT - printfromtable gBerryEffectStringIds - waitmessage B_WAIT_TIME_LONG - updatestatusicon BS_SCRIPTING - removeitem BS_SCRIPTING - return - BattleScript_MentalHerbCureRet:: - playanimation BS_ATTACKER, B_ANIM_HELD_ITEM_EFFECT + playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT printfromtable gMentalHerbCureStringIds waitmessage B_WAIT_TIME_LONG updatestatusicon BS_SCRIPTING removeitem BS_SCRIPTING - copybyte gBattlerAttacker, sSAVED_BATTLER @ restore the original attacker just to be safe return BattleScript_MentalHerbCureEnd2:: @@ -7906,14 +7706,13 @@ BattleScript_ItemHealHP_RemoveItemRet:: jumpifability BS_SCRIPTING, ABILITY_RIPEN, BattleScript_ItemHealHP_RemoveItemRet_AbilityPopUp goto BattleScript_ItemHealHP_RemoveItemRet_Anim BattleScript_ItemHealHP_RemoveItemRet_AbilityPopUp: - call BattleScript_AbilityPopUp + call BattleScript_AbilityPopUpScripting BattleScript_ItemHealHP_RemoveItemRet_Anim: playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT printstring STRINGID_PKMNSITEMRESTOREDHEALTH waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_BIDE | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_SCRIPTING - datahpupdate BS_SCRIPTING + healthbarupdate BS_SCRIPTING, PASSIVE_HP_UPDATE + datahpupdate BS_SCRIPTING, PASSIVE_HP_UPDATE removeitem BS_SCRIPTING return @@ -7921,14 +7720,13 @@ BattleScript_ItemHealHP_RemoveItemEnd2:: jumpifability BS_ATTACKER, ABILITY_RIPEN, BattleScript_ItemHealHP_RemoveItemEnd2_AbilityPopUp goto BattleScript_ItemHealHP_RemoveItemEnd2_Anim BattleScript_ItemHealHP_RemoveItemEnd2_AbilityPopUp: - call BattleScript_AbilityPopUp + call BattleScript_AbilityPopUpScripting BattleScript_ItemHealHP_RemoveItemEnd2_Anim: playanimation BS_ATTACKER, B_ANIM_HELD_ITEM_EFFECT printstring STRINGID_PKMNSITEMRESTOREDHEALTH waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_BIDE | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE removeitem BS_ATTACKER end2 @@ -7952,21 +7750,25 @@ BattleScript_ItemHealHP_End2:: call BattleScript_ItemHealHP_Ret end2 -BattleScript_AirBaloonMsgIn:: +BattleScript_AirBalloonMsgIn:: printstring STRINGID_AIRBALLOONFLOAT waitmessage B_WAIT_TIME_LONG end3 -BattleScript_AirBaloonMsgPop:: +BattleScript_AirBalloonMsgInRet:: + printstring STRINGID_AIRBALLOONFLOAT + waitmessage B_WAIT_TIME_LONG + return + +BattleScript_AirBalloonMsgPop:: printstring STRINGID_AIRBALLOONPOP waitmessage B_WAIT_TIME_LONG removeitem BS_TARGET return BattleScript_ItemHurtRet:: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE | HITMARKER_IGNORE_DISGUISE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printstring STRINGID_HURTBYITEM waitmessage B_WAIT_TIME_LONG tryfaintmon BS_ATTACKER @@ -7982,9 +7784,8 @@ BattleScript_ItemHealHP_Ret:: playanimation BS_ATTACKER, B_ANIM_HELD_ITEM_EFFECT printstring STRINGID_PKMNSITEMRESTOREDHPALITTLE waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_BIDE | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_IGNORE_DISGUISE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE return BattleScript_SelectingNotAllowedMoveChoiceItem:: @@ -8037,9 +7838,8 @@ BattleScript_BerryConfuseHealEnd2_Anim: playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT printstring STRINGID_PKMNSITEMRESTOREDHEALTH waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_BIDE | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_SCRIPTING - datahpupdate BS_SCRIPTING + healthbarupdate BS_SCRIPTING, PASSIVE_HP_UPDATE + datahpupdate BS_SCRIPTING, PASSIVE_HP_UPDATE seteffectprimary BS_SCRIPTING, BS_SCRIPTING, MOVE_EFFECT_CONFUSION removeitem BS_SCRIPTING end2 @@ -8053,9 +7853,8 @@ BattleScript_BerryConfuseHealRet_Anim: playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT printstring STRINGID_PKMNSITEMRESTOREDHEALTH waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_BIDE | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_SCRIPTING - datahpupdate BS_SCRIPTING + healthbarupdate BS_SCRIPTING, PASSIVE_HP_UPDATE + datahpupdate BS_SCRIPTING, PASSIVE_HP_UPDATE seteffectprimary BS_SCRIPTING, BS_SCRIPTING, MOVE_EFFECT_CONFUSION removeitem BS_SCRIPTING return @@ -8065,24 +7864,22 @@ BattleScript_ConsumableStatRaiseEnd2:: end2 BattleScript_ConsumableStatRaiseRet:: - @ to ensure `statbuffchange` has correct battler id, backup and use target - savetarget - copybyte gBattlerTarget, sBATTLER jumpifnotberry BS_SCRIPTING, BattleScript_ConsumableStatRaiseRet_Anim - @ check ripen popup if consuming berry jumpifability BS_SCRIPTING, ABILITY_RIPEN, BattleScript_ConsumableStatRaiseRet_AbilityPopup goto BattleScript_ConsumableStatRaiseRet_Anim BattleScript_ConsumableStatRaiseRet_AbilityPopup: call BattleScript_AbilityPopUp BattleScript_ConsumableStatRaiseRet_Anim: - statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR | STAT_CHANGE_ONLY_CHECKING, BattleScript_ConsumableStatRaiseRet_End + statbuffchange BS_SCRIPTING, STAT_CHANGE_ALLOW_PTR | STAT_CHANGE_ONLY_CHECKING, BattleScript_ConsumableStatRaiseRet_End playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT, sB_ANIM_ARG1 - statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_ConsumableStatRaiseRet_End + statbuffchange BS_SCRIPTING, STAT_CHANGE_ALLOW_PTR, BattleScript_ConsumableStatRaiseRet_End setbyte cMULTISTRING_CHOOSER, B_MSG_STAT_CHANGED_ITEM + savetarget + copybyte gBattlerTarget, sBATTLER @ BattleScript_StatUp uses target as a message arg call BattleScript_StatUp + restoretarget removeitem BS_SCRIPTING BattleScript_ConsumableStatRaiseRet_End: - restoretarget return BattleScript_BerryFocusEnergyRet:: @@ -8246,7 +8043,7 @@ BattleScript_MirrorHerbCopyStatChange:: removeitem BS_SCRIPTING BattleScript_MirrorHerbStartCopyStats: copyfoesstatincrease BS_SCRIPTING, BattleScript_MirrorHerbStartReturn - statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_MirrorHerbStartReturn + statbuffchange BS_SCRIPTING, STAT_CHANGE_ALLOW_PTR, BattleScript_MirrorHerbStartReturn setbyte sSTAT_ANIM_PLAYED, TRUE @ play stat change animation only once goto BattleScript_MirrorHerbStartCopyStats BattleScript_MirrorHerbStartReturn: @@ -8257,7 +8054,7 @@ BattleScript_OpportunistCopyStatChange:: call BattleScript_AbilityPopUpScripting BattleScript_OpportunistStartCopyStats: copyfoesstatincrease BS_SCRIPTING, BattleScript_OpportunistCopyStatChangeEnd - statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_OpportunistCopyStatChangeEnd + statbuffchange BS_SCRIPTING, STAT_CHANGE_ALLOW_PTR, BattleScript_OpportunistCopyStatChangeEnd printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG setbyte sSTAT_ANIM_PLAYED, TRUE @ play stat change animation only once @@ -8302,14 +8099,28 @@ BattleScript_ActivateTeraformZero_RemoveWeather: removeweather printfromtable gWeatherEndsStringIds waitmessage B_WAIT_TIME_LONG - jumpifhalfword CMP_NO_COMMON_BITS, gFieldStatuses, STATUS_FIELD_TERRAIN_ANY, BattleScript_ActivateTeraformZero_End + call BattleScript_ActivateWeatherAbilities + jumpifhalfword CMP_NO_COMMON_BITS, gFieldStatuses, STATUS_FIELD_TERRAIN_ANY, BattleScript_ActivateTeraformZeroEffects BattleScript_ActivateTeraformZero_RemoveTerrain: removeterrain playanimation BS_ATTACKER, B_ANIM_RESTORE_BG printfromtable gTerrainStringIds waitmessage B_WAIT_TIME_LONG -BattleScript_ActivateTeraformZero_End: +BattleScript_ActivateTeraformZeroEffects: + saveattacker + savetarget tryboosterenergy ON_ANY + resetterrainabilityflags + setbyte gBattlerAttacker, 0 +BattleScript_ActivateTeraformZeroLoop: + copyarraywithindex gBattlerTarget, gBattlerByTurnOrder, gBattlerAttacker, 1 + activateterrainchangeabilities BS_TARGET + activateweatherchangeabilities BS_TARGET + addbyte gBattlerAttacker, 1 + jumpifbytenotequal gBattlerAttacker, gBattlersCount, BattleScript_ActivateTeraformZeroLoop + restoreattacker + restoretarget +BattleScript_ActivateTeraformZero_End: end3 BattleScript_QuickClawActivation:: @@ -8352,7 +8163,7 @@ BattleScript_MicleBerryActivateRet:: jumpifability BS_SCRIPTING, ABILITY_RIPEN, BattleScript_MicleBerryActivateRet_Ripen goto BattleScript_MicleBerryActivateRet_Anim BattleScript_MicleBerryActivateRet_Ripen: - call BattleScript_AbilityPopUp + call BattleScript_AbilityPopUpScripting BattleScript_MicleBerryActivateRet_Anim: playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT printstring STRINGID_MICLEBERRYACTIVATES @@ -8401,8 +8212,8 @@ BattleScript_ZEffectPrintString:: return BattleScript_RecoverHPZMove:: - healthbarupdate BS_SCRIPTING - datahpupdate BS_SCRIPTING + healthbarupdate BS_SCRIPTING, PASSIVE_HP_UPDATE + datahpupdate BS_SCRIPTING, PASSIVE_HP_UPDATE printfromtable gZEffectStringIds waitmessage B_WAIT_TIME_LONG return @@ -8421,8 +8232,8 @@ BattleScript_HealReplacementZMove:: playanimation BS_SCRIPTING, B_ANIM_WISH_HEAL, 0x0 printfromtable gZEffectStringIds waitmessage B_WAIT_TIME_LONG - healthbarupdate BS_SCRIPTING - datahpupdate BS_SCRIPTING + healthbarupdate BS_SCRIPTING, PASSIVE_HP_UPDATE + datahpupdate BS_SCRIPTING, PASSIVE_HP_UPDATE return BattleScript_EffectExtremeEvoboost:: @@ -8463,31 +8274,6 @@ BattleScript_ExtremeEvoboostSpDef:: BattleScript_ExtremeEvoboostEnd:: goto BattleScript_MoveEnd -BattleScript_EffectHitSetTerrain:: - attackcanceler - accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE - critcalc - damagecalc - adjustdamage - attackanimation - waitanimation - effectivenesssound - hitanimation BS_TARGET - waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET - critmessage - waitmessage B_WAIT_TIME_LONG - resultmessage - waitmessage B_WAIT_TIME_LONG - setterrain BattleScript_TryFaint - playanimation BS_ATTACKER, B_ANIM_RESTORE_BG - printfromtable gTerrainStringIds - waitmessage B_WAIT_TIME_LONG -BattleScript_TryFaint: - tryfaintmon BS_TARGET - goto BattleScript_MoveEnd - BattleScript_RemoveTerrain:: removeterrain playanimation BS_ATTACKER, B_ANIM_RESTORE_BG @@ -8499,6 +8285,7 @@ BattleScript_Pickpocket:: call BattleScript_AbilityPopUp jumpifability BS_ATTACKER, ABILITY_STICKY_HOLD, BattleScript_PickpocketPrevented swapattackerwithtarget + copybyte gEffectBattler, gBattlerTarget call BattleScript_ItemSteal swapattackerwithtarget activateitemeffects @@ -8917,9 +8704,8 @@ BattleScript_EffectHealOneSixthAllies:: BattleScript_HealOneSixthAlliesLoop: jumpifabsent BS_TARGET, BattleScript_HealOneSixthAlliesIncrement tryhealsixthhealth BattleScript_HealOneSixthAlliesIncrement - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, PASSIVE_HP_UPDATE + datahpupdate BS_TARGET, PASSIVE_HP_UPDATE printstring STRINGID_PKMNREGAINEDHEALTH waitmessage B_WAIT_TIME_LONG BattleScript_HealOneSixthAlliesIncrement: @@ -9003,10 +8789,8 @@ BattleScript_DynamaxEnds_Ret:: BattleScript_MoveBlockedByDynamax:: accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE pause B_WAIT_TIME_SHORT - jumpifword CMP_COMMON_BITS, gHitMarker, HITMARKER_STRING_PRINTED, BattleScript_MoveEnd printstring STRINGID_MOVEBLOCKEDBYDYNAMAX waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_STRING_PRINTED goto BattleScript_MoveEnd BattleScript_PokemonCantUseTheMove:: @@ -9021,18 +8805,15 @@ BattleScript_CouldntFullyProtect:: return BattleScript_BerserkGeneRet:: - saveattacker - savetarget - copybyte gBattlerTarget, sBATTLER - statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR | STAT_CHANGE_ONLY_CHECKING, BattleScript_BerserkGeneRet_TryConfuse - playanimation BS_ATTACKER, B_ANIM_HELD_ITEM_EFFECT, sB_ANIM_ARG1 - statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_BerserkGeneRet_TryConfuse + statbuffchange BS_SCRIPTING, STAT_CHANGE_ALLOW_PTR | STAT_CHANGE_ONLY_CHECKING, BattleScript_BerserkGeneRet_TryConfuse + playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT, sB_ANIM_ARG1 + statbuffchange BS_SCRIPTING, STAT_CHANGE_ALLOW_PTR, BattleScript_BerserkGeneRet_TryConfuse setbyte cMULTISTRING_CHOOSER, B_MSG_STAT_CHANGED_ITEM call BattleScript_StatUp BattleScript_BerserkGeneRet_TryConfuse: - jumpifability BS_ATTACKER, ABILITY_OWN_TEMPO, BattleScript_BerserkGeneRet_OwnTempoPrevents + jumpifability BS_SCRIPTING, ABILITY_OWN_TEMPO, BattleScript_BerserkGeneRet_OwnTempoPrevents jumpifsafeguard BattleScript_BerserkGeneRet_SafeguardProtected - seteffectprimary BS_ATTACKER, BS_ATTACKER, MOVE_EFFECT_CONFUSION + seteffectprimary BS_SCRIPTING, BS_SCRIPTING, MOVE_EFFECT_CONFUSION goto BattleScript_BerserkGeneRet_End BattleScript_BerserkGeneRet_SafeguardProtected:: pause B_WAIT_TIME_SHORT @@ -9041,13 +8822,11 @@ BattleScript_BerserkGeneRet_SafeguardProtected:: goto BattleScript_BerserkGeneRet_End BattleScript_BerserkGeneRet_OwnTempoPrevents: pause B_WAIT_TIME_SHORT - call BattleScript_AbilityPopUp + call BattleScript_AbilityPopUpScripting printstring STRINGID_PKMNPREVENTSCONFUSIONWITH waitmessage B_WAIT_TIME_LONG BattleScript_BerserkGeneRet_End: - restoreattacker - restoretarget - removeitem BS_ATTACKER + removeitem BS_SCRIPTING return BattleScript_BerserkGeneRetEnd2:: @@ -9138,7 +8917,28 @@ BattleScript_MetronomeAttackstring:: BattleScript_NaturePowerAttackstring:: printattackstring pause B_WAIT_TIME_SHORT + setcalledmove printstring STRINGID_NATUREPOWERTURNEDINTO waitmessage B_WAIT_TIME_LONG - setcalledmove return + +BattleScript_TooScaredToMove:: + printstring STRINGID_MONTOOSCAREDTOMOVE + waitmessage B_WAIT_TIME_LONG + playanimation BS_ATTACKER, B_ANIM_MON_SCARED + goto BattleScript_MoveEnd + +BattleScript_GhostGetOutGetOut:: + printstring STRINGID_GHOSTGETOUTGETOUT + playanimation BS_ATTACKER, B_ANIM_GHOST_GET_OUT + goto BattleScript_MoveEnd + +BattleScript_SilphScopeUnveiled:: + pause B_WAIT_TIME_SHORT + printstring STRINGID_SILPHSCOPEUNVEILED + waitstate + playanimation BS_OPPONENT1, B_ANIM_SILPH_SCOPED + pause B_WAIT_TIME_SHORT + printstring STRINGID_GHOSTWASMAROWAK + waitmessage B_WAIT_TIME_LONG + end2 diff --git a/data/battle_scripts_2.s b/data/battle_scripts_2.s index 8fec1d949..df77f715c 100644 --- a/data/battle_scripts_2.s +++ b/data/battle_scripts_2.s @@ -19,12 +19,6 @@ BattleScript_OldMan_Pokedude_CaughtMessage:: endlinkbattle finishturn -BattleScript_GhostBallDodge:: - waitmessage B_WAIT_TIME_LONG - printstring STRINGID_ITDODGEDBALL - waitmessage B_WAIT_TIME_LONG - finishaction - @ pokemerald .align 2 gBattlescriptsForUsingItem:: @@ -92,9 +86,8 @@ BattleScript_UseItemMessage: BattleScript_ItemRestoreHPRet: clearmoveresultflags MOVE_RESULT_NO_EFFECT - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE - healthbarupdate BS_SCRIPTING - datahpupdate BS_SCRIPTING + healthbarupdate BS_SCRIPTING, PASSIVE_HP_UPDATE + datahpupdate BS_SCRIPTING, PASSIVE_HP_UPDATE printstring STRINGID_ITEMRESTOREDSPECIESHEALTH waitmessage B_WAIT_TIME_LONG return @@ -259,7 +252,10 @@ BattleScript_WallyBallThrow:: finishturn BattleScript_ShakeBallThrow:: + animatewildpokemonafterfailedpokeball BS_TARGET + waitmessage B_WAIT_TIME_LONG printfromtable gBallEscapeStringIds + waitanimation waitmessage B_WAIT_TIME_LONG jumpifword CMP_NO_COMMON_BITS, gBattleTypeFlags, BATTLE_TYPE_SAFARI, BattleScript_ShakeBallThrowEnd jumpifbyte CMP_NOT_EQUAL, gNumSafariBalls, 0, BattleScript_ShakeBallThrowEnd @@ -307,3 +303,9 @@ BattleScript_TrainerBSlideMsgRet:: BattleScript_TrainerBSlideMsgEnd2:: call BattleScript_TrainerBSlideMsgRet end2 + +BattleScript_GhostBallDodge:: + waitmessage B_WAIT_TIME_LONG + printstring STRINGID_ITDODGEDBALL + waitmessage B_WAIT_TIME_LONG + finishaction diff --git a/include/battle.h b/include/battle.h index d8a014e9c..55d887a5d 100644 --- a/include/battle.h +++ b/include/battle.h @@ -2,9 +2,12 @@ #define GUARD_BATTLE_H // should they be included here or included individually by every file? +#include "constants/battle_end_turn.h" #include "constants/abilities.h" #include "constants/battle.h" #include "constants/form_change_types.h" +#include "constants/hold_effects.h" +#include "constants/moves.h" #include "battle_main.h" #include "battle_message.h" #include "battle_util.h" @@ -14,6 +17,7 @@ #include "battle_util2.h" #include "battle_bg.h" #include "pokeball.h" +#include "main.h" #include "battle_debug.h" #include "battle_dynamax.h" #include "battle_terastal.h" @@ -233,7 +237,7 @@ struct SideTimer u8 followmePowder:1; // Rage powder, does not affect grass type pokemon. u8 retaliateTimer; u16 damageNonTypesTimer; - u8 damageNonTypesType; + enum Type damageNonTypesType; u16 rainbowTimer; u16 seaOfFireTimer; u16 swampTimer; @@ -270,7 +274,7 @@ struct AI_SavedBattleMon u16 heldItem; u16 species:15; u16 saved:1; - u8 types[3]; + enum Type types[3]; }; struct AiPartyMon @@ -582,10 +586,11 @@ struct BattlerState u32 pursuitTarget:1; u32 stompingTantrumTimer:2; u32 canPickupItem:1; - u32 itemCanBeKnockedOff:1; u32 ateBoost:1; + u32 wasAboveHalfHp:1; // For Berserk, Emergency Exit, Wimp Out and Anger Shell. u32 commanderSpecies:11; - u32 padding:4; + u32 selectionScriptFinished:1; + u32 padding:3; // End of Word }; @@ -599,7 +604,25 @@ struct PartyState u32 supersweetSyrup:1; u32 timesGotHit:5; u32 changedSpecies:11; // For forms when multiple mons can change into the same pokemon. - u32 padding:10; + u32 sentOut:1; + u32 padding:9; + u16 usedHeldItem; +}; + +struct EventStates +{ + enum EndTurnResolutionOrder endTurn:8; + u32 endTurnBlock:8; // FirstEventBlock, SecondEventBlock, ThirdEventBlock + enum BattlerId endTurnBattler:4; + u32 arenaTurn:8; + enum BattleSide battlerSide:4; + enum BattlerId moveEndBattler:4; + enum FirstTurnEventsStates beforeFristTurn:8; + enum FaintedActions faintedAction:8; + enum BattlerId faintedActionBattler:4; + enum MoveSuccessOrder atkCanceller:8; + enum BattleIntroStates battleIntro:8; + u32 padding:24; }; // Cleared at the beginning of the battle. Fields need to be cleared when needed manually otherwise. @@ -607,11 +630,7 @@ struct BattleStruct { struct BattlerState battlerState[MAX_BATTLERS_COUNT]; struct PartyState partyState[NUM_BATTLE_SIDES][PARTY_SIZE]; - u8 eventBlockCounter; - u8 endTurnEventsCounter; - u8 turnEffectsBattlerId:4; - u8 moveEndBattlerId:4; - u16 wrappedMove[MAX_BATTLERS_COUNT]; + struct EventStates eventState; u16 moveTarget[MAX_BATTLERS_COUNT]; u32 expShareExpValue; u32 expValue; @@ -623,18 +642,13 @@ struct BattleStruct u8 givenExpMons; // Bits for enemy party's pokemon that gave exp to player's party. u8 expSentInMons; // As bits for player party mons - not including exp share mons. u8 wildVictorySong; - u8 dynamicMoveType; - u8 wrappedBy[MAX_BATTLERS_COUNT]; + enum Type dynamicMoveType; u8 battlerPreventingSwitchout; u8 moneyMultiplier:6; u8 moneyMultiplierItem:1; u8 moneyMultiplierMove:1; u8 savedTurnActionNumber; - u8 eventsBeforeFirstTurnState; - u8 faintedActionsState; - u8 faintedActionsBattlerId; u8 scriptPartyIdx; // for printing the nickname - bool8 selectionScriptFinished[MAX_BATTLERS_COUNT]; u8 battlerPartyIndexes[MAX_BATTLERS_COUNT]; u8 monToSwitchIntoId[MAX_BATTLERS_COUNT]; u8 battlerPartyOrders[MAX_BATTLERS_COUNT][PARTY_SIZE / 2]; @@ -666,29 +680,23 @@ struct BattleStruct u8 isSkyBattle:1; u8 multipleSwitchInSortedBattlers[MAX_BATTLERS_COUNT]; void (*savedCallback)(void); - u16 usedHeldItems[PARTY_SIZE][NUM_BATTLE_SIDES]; // For each party member and side. For harvest, recycle u16 chosenItem[MAX_BATTLERS_COUNT]; u16 choicedMove[MAX_BATTLERS_COUNT]; u16 changedItems[MAX_BATTLERS_COUNT]; u8 switchInBattlerCounter; - u8 arenaTurnCounter; - u8 turnSideTracker; u16 lastTakenMoveFrom[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT]; // a 2-D array [target][attacker] union { struct LinkBattlerHeader linkBattlerHeader; struct BattleVideo battleVideo; } multiBuffer; - u8 startingStatus:6; // status to apply at battle start. defined in constants/battle.h - u8 startingStatusDone:1; - u8 terrainDone:1; - u8 overworldWeatherDone:1; + u8 startingStatus; // status to apply at battle start. defined in constants/battle.h u8 battlerKOAnimsRunning:3; u8 friskedAbility:1; // If identifies two mons, show the ability pop-up only once. u8 fickleBeamBoosted:1; u8 poisonPuppeteerConfusion:1; u8 toxicChainPriority:1; // If Toxic Chain will trigger on target, all other non volatiles will be blocked + u8 padding1:1; u16 startingStatusTimer; - u8 atkCancellerTracker; // struct BattleTvMovePoints tvMovePoints; // struct BattleTv tv; u8 AI_monToSwitchIntoId[MAX_BATTLERS_COUNT]; @@ -709,15 +717,13 @@ struct BattleStruct struct DynamaxData dynamax; struct BattleGimmickData gimmick; const u8 *trainerSlideMsg; - enum BattleIntroStates introState:8; u8 stolenStats[NUM_BATTLE_STATS]; // hp byte is used for which stats to raise, other inform about by how many stages u8 lastMoveTarget[MAX_BATTLERS_COUNT]; // The last target on which each mon used a move, for the sake of Instruct enum Ability tracedAbility[MAX_BATTLERS_COUNT]; - u16 hpBefore[MAX_BATTLERS_COUNT]; // Hp of battlers before using a move. For Berserk and Anger Shell. struct Illusion illusion[MAX_BATTLERS_COUNT]; u8 soulheartBattlerId; u8 friskedBattler; // Frisk needs to identify 2 battlers in double battles. - u8 sameMoveTurns[MAX_BATTLERS_COUNT]; // For Metronome, number of times the same moves has been SUCCESFULLY used. + u8 metronomeItemCounter[MAX_BATTLERS_COUNT]; // For Metronome, number of times the same moves has been SUCCESFULLY used. u8 quickClawBattlerId; struct LostItem itemLost[NUM_BATTLE_SIDES][PARTY_SIZE]; // Pokemon that had items consumed or stolen (two bytes per party member per side) u8 blunderPolicy:1; // should blunder policy activate @@ -730,7 +736,6 @@ struct BattleStruct u8 throwingPokeBall:1; u8 ballSpriteIds[2]; // item gfx, window gfx u8 moveInfoSpriteId; // move info, window gfx - u8 appearedInBattle; // Bitfield to track which Pokemon appeared in battle. Used for Burmy's form change u8 skyDropTargets[MAX_BATTLERS_COUNT]; // For Sky Drop, to account for if multiple Pokemon use Sky Drop in a double battle. // When using a move which hits multiple opponents which is then bounced by a target, we need to make sure, the move hits both opponents, the one with bounce, and the one without. u16 beatUpSpecies[PARTY_SIZE]; @@ -745,7 +750,6 @@ struct BattleStruct s32 aiDelayTimer; // Counts number of frames AI takes to choose an action. s32 aiDelayFrames; // Number of frames it took to choose an action. s32 aiDelayCycles; // Number of cycles it took to choose an action. - u8 stickySyrupdBy[MAX_BATTLERS_COUNT]; u8 supremeOverlordCounter[MAX_BATTLERS_COUNT]; u8 shellSideArmCategory[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT]; u8 speedTieBreaks; // MAX_BATTLERS_COUNT! values. @@ -758,6 +762,7 @@ struct BattleStruct u8 pursuitStoredSwitch; // Stored id for the Pursuit target's switch s32 battlerExpReward; u16 prevTurnSpecies[MAX_BATTLERS_COUNT]; // Stores species the AI has in play at start of turn + s16 passiveHpUpdate[MAX_BATTLERS_COUNT]; // non-move damage and healing s16 moveDamage[MAX_BATTLERS_COUNT]; s16 critChance[MAX_BATTLERS_COUNT]; u16 moveResultFlags[MAX_BATTLERS_COUNT]; @@ -769,15 +774,19 @@ struct BattleStruct u8 printedStrongWindsWeakenedAttack:1; u8 numSpreadTargets:2; u8 noTargetPresent:1; - u8 cheekPouchActivated:1; - s16 savedcheekPouchDamage; // Cheek Pouch can happen in the middle of an attack execution so we need to store the current dmg + u8 padding2:1; struct MessageStatus slideMessageStatus; u8 trainerSlideSpriteIds[MAX_BATTLERS_COUNT]; u8 hazardsQueue[NUM_BATTLE_SIDES][HAZARDS_MAX_COUNT]; u8 numHazards[NUM_BATTLE_SIDES]; u8 hazardsCounter:4; // Counter for applying hazard on switch in enum SubmoveState submoveAnnouncement:2; - u8 padding2:2; + u8 tryDestinyBond:1; + u8 tryGrudge:1; + u16 flingItem; + u8 incrementEchoedVoice:1; + u8 echoedVoiceCounter:3; + u8 padding3:4; // pokefirered u8 field_DA; // battle tower related u8 lastAttackerToFaintOpponent; @@ -824,7 +833,7 @@ static inline bool32 IsBattleMoveStatus(u32 move) * times with one type because it shares the 'GetBattlerTypes' result. */ #define _IS_BATTLER_ANY_TYPE(battler, ignoreTera, ...) \ ({ \ - u32 types[3]; \ + enum Type types[3]; \ GetBattlerTypes(battler, ignoreTera, types); \ RECURSIVELY(R_FOR_EACH(_IS_BATTLER_ANY_TYPE_HELPER, __VA_ARGS__)) FALSE; \ }) @@ -838,7 +847,7 @@ static inline bool32 IsBattleMoveStatus(u32 move) #define IS_BATTLER_TYPELESS(battlerId) \ ({ \ - u32 types[3]; \ + enum Type types[3]; \ GetBattlerTypes(battlerId, FALSE, types); \ types[0] == TYPE_MYSTERY && types[1] == TYPE_MYSTERY && types[2] == TYPE_MYSTERY; \ }) @@ -1124,7 +1133,7 @@ extern u16 gBattleTurnCounter; extern u8 gBattlerAbility; extern struct QueuedStatBoost gQueuedStatBoosts[MAX_BATTLERS_COUNT]; -extern void (*gPreBattleCallback1)(void); +extern MainCallback gPreBattleCallback1; extern void (*gBattleMainFunc)(void); extern struct BattleResults gBattleResults; extern u8 gLeveledUpInBattle; @@ -1195,7 +1204,7 @@ static inline u32 GetBattlerSide(u32 battler) return GetBattlerPosition(battler) & BIT_SIDE; } -static inline u32 IsOnPlayerSide(u32 battler) +static inline bool32 IsOnPlayerSide(u32 battler) { return GetBattlerSide(battler) == B_SIDE_PLAYER; } @@ -1216,7 +1225,7 @@ static inline struct Pokemon* GetBattlerMon(u32 battler) return !IsOnPlayerSide(battler) ? &gEnemyParty[index] : &gPlayerParty[index]; } -static inline struct Pokemon *GetSideParty(u32 side) +static inline struct Pokemon *GetSideParty(enum BattleSide side) { return side == B_SIDE_PLAYER ? gPlayerParty : gEnemyParty; } @@ -1233,7 +1242,7 @@ static inline struct PartyState *GetBattlerPartyState(u32 battler) static inline bool32 IsDoubleBattle(void) { - return gBattleTypeFlags & BATTLE_TYPE_DOUBLE; + return (gBattleTypeFlags & BATTLE_TYPE_MORE_THAN_TWO_BATTLERS); } static inline bool32 IsSpreadMove(u32 moveTarget) @@ -1244,7 +1253,7 @@ static inline bool32 IsSpreadMove(u32 moveTarget) static inline bool32 IsDoubleSpreadMove(void) { return gBattleStruct->numSpreadTargets > 1 - && !(gHitMarker & (HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE | HITMARKER_UNABLE_TO_USE_MOVE)) + && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) && IsSpreadMove(GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove)); } @@ -1260,6 +1269,20 @@ static inline u32 GetChosenMoveFromPosition(u32 battler) return gBattleMons[battler].moves[gBattleStruct->chosenMovePositions[battler]]; } +static inline void SetPassiveDamageAmount(u32 battler, s32 value) +{ + if (value == 0) + value = 1; + gBattleStruct->passiveHpUpdate[battler] = value; +} + +static inline void SetHealAmount(u32 battler, s32 value) +{ + if (value == 0) + value = 1; + gBattleStruct->passiveHpUpdate[battler] = -1 * value; +} + static inline bool32 IsGhostBattleWithoutScope() { return (gBattleTypeFlags & BATTLE_TYPE_GHOST) && !CheckBagHasItem(ITEM_SILPH_SCOPE, 1); diff --git a/include/battle_ai_switch_items.h b/include/battle_ai_switch_items.h index 8fcd7ba35..35085563a 100644 --- a/include/battle_ai_switch_items.h +++ b/include/battle_ai_switch_items.h @@ -45,7 +45,7 @@ void GetAIPartyIndexes(u32 battlerId, s32 *firstId, s32 *lastId); void AI_TrySwitchOrUseItem(u32 battler); u32 GetMostSuitableMonToSwitchInto(u32 battler, enum SwitchType switchType); bool32 ShouldSwitch(u32 battler); -bool32 IsMonGrounded(u16 heldItemEffect, enum Ability ability, u8 type1, u8 type2); +bool32 IsMonGrounded(enum HoldEffect heldItemEffect, enum Ability ability, enum Type type1, enum Type type2); void ModifySwitchAfterMoveScoring(u32 battler); #endif // GUARD_BATTLE_AI_SWITCH_ITEMS_H diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 415c4fb93..2c8760893 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -4,11 +4,6 @@ #include "battle_ai_main.h" #include "battle_ai_field_statuses.h" -// Left and right are determined by how they're referred to in tests and everywhere else. -// Left is battlers 0 and 1, right 2 and 3; if you assume the battler referencing them is south, left is to the northeast and right to the northwest. -#define LEFT_FOE(battler) ((BATTLE_OPPOSITE(battler)) & BIT_SIDE) -#define RIGHT_FOE(battler) (((BATTLE_OPPOSITE(battler)) & BIT_SIDE) | BIT_FLANK) - // Roll boundaries used by AI when scoring. Doesn't affect actual damage dealt. #define MAX_ROLL_PERCENTAGE DMG_ROLL_PERCENT_HI #define MIN_ROLL_PERCENTAGE DMG_ROLL_PERCENT_LO @@ -94,7 +89,7 @@ void RecordAllMoves(u32 battler); void RecordKnownMove(u32 battlerId, u32 move); void RecordAbilityBattle(u32 battlerId, enum Ability abilityId); void ClearBattlerAbilityHistory(u32 battlerId); -void RecordItemEffectBattle(u32 battlerId, u32 itemEffect); +void RecordItemEffectBattle(u32 battlerId, enum HoldEffect itemEffect); void ClearBattlerItemEffectHistory(u32 battlerId); void SaveBattlerData(u32 battlerId); void SetBattlerData(u32 battlerId); @@ -115,7 +110,7 @@ u32 GetBestDmgFromBattler(u32 battler, u32 battlerTarget, enum DamageCalcContext bool32 CanTargetMoveFaintAi(u32 move, u32 battlerDef, u32 battlerAtk, u32 nHits); bool32 CanTargetFaintAiWithMod(u32 battlerDef, u32 battlerAtk, s32 hpMod, s32 dmgMod); enum Ability AI_DecideKnownAbilityForTurn(u32 battlerId); -enum ItemHoldEffect AI_DecideHoldEffectForTurn(u32 battlerId); +enum HoldEffect AI_DecideHoldEffectForTurn(u32 battlerId); bool32 DoesBattlerIgnoreAbilityChecks(u32 battlerAtk, enum Ability atkAbility, u32 move); u32 AI_GetWeather(void); u32 AI_GetSwitchinWeather(struct BattlePokemon battleMon); @@ -123,7 +118,7 @@ enum WeatherState IsWeatherActive(u32 flags); bool32 CanAIFaintTarget(u32 battlerAtk, u32 battlerDef, u32 numHits); bool32 CanIndexMoveFaintTarget(u32 battlerAtk, u32 battlerDef, u32 index, enum DamageCalcContext calcContext); bool32 HasDamagingMove(u32 battler); -bool32 HasDamagingMoveOfType(u32 battler, u32 type); +bool32 HasDamagingMoveOfType(u32 battler, enum Type type); u32 GetBattlerSecondaryDamage(u32 battlerId); bool32 BattlerWillFaintFromWeather(u32 battler, enum Ability ability); bool32 BattlerWillFaintFromSecondaryDamage(u32 battler, enum Ability ability); @@ -132,6 +127,8 @@ bool32 ShouldUseRecoilMove(u32 battlerAtk, u32 battlerDef, u32 recoilDmg, u32 mo bool32 ShouldAbsorb(u32 battlerAtk, u32 battlerDef, u32 move, s32 damage); bool32 ShouldRecover(u32 battlerAtk, u32 battlerDef, u32 move, u32 healPercent); bool32 ShouldSetScreen(u32 battlerAtk, u32 battlerDef, enum BattleMoveEffects moveEffect); +bool32 ShouldCureStatus(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData); +bool32 ShouldCureStatusWithItem(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData); enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, enum Ability defAbility, u32 move, u32 moveIndex); bool32 IsRecycleEncouragedItem(u32 item); bool32 ShouldRestoreHpBerry(u32 battlerAtk, u32 item); @@ -139,7 +136,7 @@ bool32 IsStatBoostingBerry(u32 item); bool32 CanKnockOffItem(u32 battler, u32 item); bool32 IsAbilityOfRating(enum Ability ability, s8 rating); bool32 AI_IsAbilityOnSide(u32 battlerId, enum Ability ability); -bool32 AI_MoveMakesContact(enum Ability ability, enum ItemHoldEffect holdEffect, u32 move); +bool32 AI_MoveMakesContact(enum Ability ability, enum HoldEffect holdEffect, u32 move); bool32 IsConsideringZMove(u32 battlerAtk, u32 battlerDef, u32 move); bool32 ShouldUseZMove(u32 battlerAtk, u32 battlerDef, u32 chosenMove); void SetAIUsingGimmick(u32 battler, enum AIConsiderGimmick use); @@ -149,18 +146,18 @@ bool32 CanEndureHit(u32 battler, u32 battlerTarget, u32 move); // stat stage checks bool32 AnyStatIsRaised(u32 battlerId); -bool32 CanLowerStat(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData, u32 stat); -bool32 BattlerStatCanRise(u32 battler, enum Ability battlerAbility, u32 stat); +bool32 CanLowerStat(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData, enum Stat stat); +bool32 BattlerStatCanRise(u32 battler, enum Ability battlerAbility, enum Stat stat); bool32 AreBattlersStatsMaxed(u32 battler); u32 CountPositiveStatStages(u32 battlerId); u32 CountNegativeStatStages(u32 battlerId); // move checks bool32 Ai_IsPriorityBlocked(u32 battlerAtk, u32 battlerDef, u32 move, struct AiLogicData *aiData); -bool32 IsAffectedByPowder(u32 battler, enum Ability ability, enum ItemHoldEffect holdEffect); bool32 MovesWithCategoryUnusable(u32 attacker, u32 target, enum DamageCategory category); enum MoveComparisonResult AI_WhichMoveBetter(u32 move1, u32 move2, u32 battlerAtk, u32 battlerDef, s32 noOfHitsToKo); struct SimulatedDamage AI_CalcDamageSaveBattlers(u32 move, u32 battlerAtk, u32 battlerDef, uq4_12_t *typeEffectiveness, enum AIConsiderGimmick considerGimmickAtk, enum AIConsiderGimmick considerGimmickDef); +bool32 IsAdditionalEffectBlocked(u32 battlerAtk, u32 abilityAtk, u32 battlerDef, u32 abilityDef); struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, uq4_12_t *typeEffectiveness, enum AIConsiderGimmick considerGimmickAtk, enum AIConsiderGimmick considerGimmickDef, u32 weather); bool32 AI_IsDamagedByRecoil(u32 battler); u32 GetNoOfHitsToKO(u32 dmg, s32 hp); @@ -175,7 +172,7 @@ bool32 HasMove(u32 battlerId, u32 move); u32 GetIndexInMoveArray(u32 battler, u32 move); bool32 HasOnlyMovesWithCategory(u32 battlerId, enum DamageCategory category, bool32 onlyOffensive); bool32 HasMoveWithCategory(u32 battler, enum DamageCategory category); -bool32 HasMoveWithType(u32 battler, u32 type); +bool32 HasMoveWithType(u32 battler, enum Type type); bool32 HasMoveWithEffect(u32 battler, enum BattleMoveEffects moveEffect); bool32 HasMoveWithAIEffect(u32 battler, u32 aiEffect); bool32 HasBattlerSideMoveWithEffect(u32 battler, u32 effect); @@ -246,15 +243,15 @@ bool32 AI_IsBattlerAsleepOrComatose(u32 battlerId); bool32 IsMoxieTypeAbility(enum Ability ability); bool32 DoesAbilityRaiseStatsWhenLowered(enum Ability ability); bool32 ShouldTriggerAbility(u32 battlerAtk, u32 battlerDef, enum Ability ability); -bool32 CanEffectChangeAbility(u32 battlerAtk, u32 battlerDef, u32 effect, struct AiLogicData *aiData); -void AbilityChangeScore(u32 battlerAtk, u32 battlerDef, u32 effect, s32 *score, struct AiLogicData *aiData); +bool32 CanEffectChangeAbility(u32 battlerAtk, u32 battlerDef, u32 move, struct AiLogicData *aiData); +void AbilityChangeScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score, struct AiLogicData *aiData); s32 BattlerBenefitsFromAbilityScore(u32 battler, enum Ability ability, struct AiLogicData *aiData); // partner logic bool32 IsTargetingPartner(u32 battlerAtk, u32 battlerDef); // IsTargetingPartner includes a check to make sure the adjacent pokemon is truly a partner. u32 GetAllyChosenMove(u32 battlerId); -bool32 IsBattle1v1(); +bool32 IsBattle1v1(void); // IsBattle1v1 is distinct from !IsDoubleBattle. If the player is fighting Maxie and Tabitha, with Steven as their partner, and both Tabitha and Steven have run out of Pokemon, the battle is 1v1, even though mechanically it is a Double Battle for how battlers and flags are set. // Most AI checks should be using IsBattle1v1; most engine checks should be using !IsDoubleBattle bool32 HasTwoOpponents(u32 battler); @@ -285,7 +282,7 @@ bool32 SideHasMoveCategory(u32 battlerId, enum DamageCategory category); // score increases u32 IncreaseStatUpScore(u32 battlerAtk, u32 battlerDef, enum StatChange statId); u32 IncreaseStatUpScoreContrary(u32 battlerAtk, u32 battlerDef, enum StatChange statId); -u32 IncreaseStatDownScore(u32 battlerAtk, u32 battlerDef, u32 stat); +u32 IncreaseStatDownScore(u32 battlerAtk, u32 battlerDef, enum Stat stat); void IncreasePoisonScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score); void IncreaseBurnScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score); void IncreaseParalyzeScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score); @@ -305,7 +302,6 @@ bool32 IsBattlerItemEnabled(u32 battler); bool32 IsBattlerPredictedToSwitch(u32 battler); u32 GetIncomingMove(u32 battler, u32 opposingBattler, struct AiLogicData *aiData); u32 GetIncomingMoveSpeedCheck(u32 battler, u32 opposingBattler, struct AiLogicData *aiData); -bool32 HasBattlerSideAbility(u32 battlerDef, enum Ability ability, struct AiLogicData *aiData); bool32 IsNaturalEnemy(u32 speciesAttacker, u32 speciesTarget); // These are for the purpose of not doubling up on moves during double battles. diff --git a/include/battle_dynamax.h b/include/battle_dynamax.h index 03dfef96a..d9fa48706 100644 --- a/include/battle_dynamax.h +++ b/include/battle_dynamax.h @@ -5,7 +5,7 @@ bool32 CanDynamax(u32 battler); bool32 IsGigantamaxed(u32 battler); -void ApplyDynamaxHPMultiplier(struct Pokemon* mon); +void ApplyDynamaxHPMultiplier(struct Pokemon *mon); void ActivateDynamax(u32 battler); u16 GetNonDynamaxHP(u32 battler); u16 GetNonDynamaxMaxHP(u32 battler); @@ -15,7 +15,7 @@ bool32 IsMoveBlockedByMaxGuard(u32 move); u16 GetMaxMove(u32 battler, u32 baseMove); u32 GetMaxMovePower(u32 move); bool32 IsMaxMove(u32 move); -void ChooseDamageNonTypesString(u8 type); +void ChooseDamageNonTypesString(enum Type type); void BS_UpdateDynamax(void); void BS_SetSteelsurge(void); diff --git a/include/battle_hold_effects.h b/include/battle_hold_effects.h new file mode 100644 index 000000000..51e63ea20 --- /dev/null +++ b/include/battle_hold_effects.h @@ -0,0 +1,52 @@ +#ifndef GUARD_BATTLE_HOLD_EFFECTS +#define GUARD_BATTLE_HOLD_EFFECTS + +struct HoldEffectInfo +{ + u32 onSwitchIn:1; + u32 onSwitchInFirstTurn:1; + u32 mirrorHerb:1; + u32 mirrorHerbFirstTurn:1; + u32 whiteHerb:1; + u32 whiteHerbFirstTurn:1; + u32 whiteHerbEndTurn:1; + u32 onStatusChange:1; + u32 onHpThreshold:1; + u32 keeMarangaBerry:1; + u32 MentalHerb:1; + u32 onTargetAfterHit:1; + u32 onAttackerAfterHit:1; + u32 lifeOrbShellBell:1; + u32 leftovers:1; + u32 orbs:1; + u32 onEffect:1; + u32 onFling:1; + u32 padding:14; +}; + +extern const struct HoldEffectInfo gHoldEffectsInfo[]; + +typedef bool32 (*ActivationTiming)(enum HoldEffect holdEffect); +enum ItemEffect ItemBattleEffects(u32 primaryBattler, u32 secondaryBattler, enum HoldEffect holdEffect, ActivationTiming timing); + +bool32 IsOnSwitchInActivation(enum HoldEffect holdEffect); +bool32 IsOnSwitchInFirstTurnActivation(enum HoldEffect holdEffect); +bool32 IsMirrorHerbActivation(enum HoldEffect holdEffect); +bool32 IsMirrorHerbFirstTurnActivation(enum HoldEffect holdEffect); +bool32 IsWhiteHerbActivation(enum HoldEffect holdEffect); +bool32 IsWhiteHerbFirstTurnActivation(enum HoldEffect holdEffect); +bool32 IsWhiteHerbEndTurnActivation(enum HoldEffect holdEffect); +bool32 IsOnStatusChangeActivation(enum HoldEffect holdEffect); +bool32 IsOnHpThresholdActivation(enum HoldEffect holdEffect); +bool32 IsKeeMarangaBerryActivation(enum HoldEffect holdEffect); +bool32 IsOnTargetHitActivation(enum HoldEffect holdEffect); +bool32 IsOnAttackerAfterHitActivation(enum HoldEffect holdEffect); +bool32 IsLifeOrbShellBellActivation(enum HoldEffect holdEffect); +bool32 IsLeftoversActivation(enum HoldEffect holdEffect); +bool32 IsOrbsActivation(enum HoldEffect holdEffect); +bool32 IsOnEffectActivation(enum HoldEffect holdEffect); +bool32 IsForceTriggerItemActivation(enum HoldEffect holdEffect); +bool32 IsOnBerryActivation(enum HoldEffect holdEffect); +bool32 IsOnFlingActivation(enum HoldEffect holdEffect); + +#endif // GUARD_BATTLE_HOLD_EFFECTS diff --git a/include/battle_main.h b/include/battle_main.h index 94c8ad971..beb461200 100644 --- a/include/battle_main.h +++ b/include/battle_main.h @@ -1,6 +1,7 @@ #ifndef GUARD_BATTLE_MAIN_H #define GUARD_BATTLE_MAIN_H +#include "battle_util.h" #include "pokemon.h" #include "data.h" #include "constants/hold_effects.h" @@ -98,18 +99,15 @@ u8 IsRunningFromBattleImpossible(u32 battler); void SwitchTwoBattlersInParty(u32 battler, u32 battler2); void SwitchPartyOrder(u32 battler); void SwapTurnOrder(u8 id1, u8 id2); -u32 GetBattlerTotalSpeedStatArgs(u32 battler, enum Ability ability, enum ItemHoldEffect holdEffect); -u32 GetBattlerTotalSpeedStat(u32 battler); +u32 GetBattlerTotalSpeedStat(u32 battler, enum Ability ability, enum HoldEffect holdEffect); s32 GetChosenMovePriority(u32 battler, enum Ability ability); s32 GetBattleMovePriority(u32 battler, enum Ability ability, u32 move); -s32 GetWhichBattlerFasterArgs(u32 battler1, u32 battler2, bool32 ignoreChosenMoves, enum Ability ability1, enum Ability ability2, - enum ItemHoldEffect holdEffectBattler1, enum ItemHoldEffect holdEffectBattler2, u32 speedBattler1, u32 speedBattler2, s32 priority1, s32 priority2); -s32 GetWhichBattlerFasterOrTies(u32 battler1, u32 battler2, bool32 ignoreChosenMoves); -s32 GetWhichBattlerFaster(u32 battler1, u32 battler2, bool32 ignoreChosenMoves); +s32 GetWhichBattlerFasterArgs(struct BattleContext *ctx, bool32 ignoreChosenMoves, u32 speedBattler1, u32 speedBattler2, s32 priority1, s32 priority2); +s32 GetWhichBattlerFasterOrTies(struct BattleContext *ctx, bool32 ignoreChosenMoves); +s32 GetWhichBattlerFaster(struct BattleContext *ctx, bool32 ignoreChosenMoves); void RunBattleScriptCommands_PopCallbacksStack(void); void RunBattleScriptCommands(void); -void SpecialStatusesClear(void); -u32 GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum MonState monInBattle); +enum Type GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum MonState monInBattle); void SetTypeBeforeUsingMove(u32 move, u32 battlerAtk); bool32 IsWildMonSmart(void); u8 CreateNPCTrainerPartyFromTrainer(struct Pokemon *party, const struct Trainer *trainer, bool32 firstTrainer, u32 battleTypeFlags); diff --git a/include/battle_script_commands.h b/include/battle_script_commands.h index 10bc1219d..593ad94a7 100644 --- a/include/battle_script_commands.h +++ b/include/battle_script_commands.h @@ -40,16 +40,15 @@ union TRANSPARENT StatChangeFlags }; }; -s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, enum Ability abilityAtk, enum Ability abilityDef, enum ItemHoldEffect holdEffectAtk); -s32 CalcCritChanceStageGen1(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, enum Ability abilityAtk, enum Ability abilityDef, enum ItemHoldEffect holdEffectAtk); +s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, enum Ability abilityAtk, enum Ability abilityDef, enum HoldEffect holdEffectAtk); +s32 CalcCritChanceStageGen1(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, enum Ability abilityAtk, enum Ability abilityDef, enum HoldEffect holdEffectAtk); s32 GetCritHitOdds(s32 critChanceIndex); -u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, enum Ability atkAbility, enum Ability defAbility, u32 atkHoldEffect, u32 defHoldEffect); bool32 HasBattlerActedThisTurn(u32 battler); u32 GetBattlerTurnOrderNum(u32 battler); bool32 NoAliveMonsForBattlerSide(u32 battler); bool32 NoAliveMonsForPlayer(void); bool32 NoAliveMonsForEitherParty(void); -void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certain); +void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, const u8 *battleScript, enum SetMoveEffectFlags effectFlags); bool32 CanBattlerSwitch(u32 battlerId); void BattleDestroyYesNoCursorAt(u8 cursorPosition); void BattleCreateYesNoCursorAt(u8 cursorPosition); @@ -67,8 +66,8 @@ bool32 TryResetBattlerStatChanges(u8 battler); bool32 CanCamouflage(u8 battlerId); void StealTargetItem(u8 battlerStealer, u8 battlerItem); u8 GetCatchingBattler(void); -u32 GetHighestStatId(u32 battlerId); -bool32 ProteanTryChangeType(u32 battler, enum Ability ability, u32 move, u32 moveType); +enum Stat GetHighestStatId(u32 battlerId); +bool32 ProteanTryChangeType(u32 battler, enum Ability ability, u32 move, enum Type moveType); bool32 IsMoveNotAllowedInSkyBattles(u32 move); bool32 DoSwitchInAbilities(u32 battlerId); u8 GetFirstFaintedPartyIndex(u8 battlerId); @@ -76,6 +75,7 @@ bool32 IsMoveAffectedByParentalBond(u32 move, u32 battler); void SaveBattlerTarget(u32 battler); void SaveBattlerAttacker(u32 battler); bool32 CanBurnHitThaw(u16 move); +bool32 EmergencyExitCanBeTriggered(u32 battler); bool32 IsMonGettingExpSentOut(void); extern void (*const gBattleScriptingCommandsTable[])(void); diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 8fbf623ed..f9920bca8 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -14,6 +14,7 @@ extern const u8 BattleScript_MoveMissedPause[]; extern const u8 BattleScript_MoveMissedPause[]; extern const u8 BattleScript_MoveMissed[]; extern const u8 BattleScript_FlingFailConsumeItem[]; +extern const u8 BattleScript_FlingBlockedByShieldDust[]; extern const u8 BattleScript_FailedFromAtkCanceler[]; extern const u8 BattleScript_ButItFailed[]; extern const u8 BattleScript_StatUp[]; @@ -21,8 +22,7 @@ extern const u8 BattleScript_StatDown[]; extern const u8 BattleScript_AlreadyAtFullHp[]; extern const u8 BattleScript_PresentHealTarget[]; extern const u8 BattleScript_MoveUsedMustRecharge[]; -extern const u8 BattleScript_FaintAttacker[]; -extern const u8 BattleScript_FaintTarget[]; +extern const u8 BattleScript_FaintBattler[]; extern const u8 BattleScript_GiveExp[]; extern const u8 BattleScript_HandleFaintedMon[]; extern const u8 BattleScript_LocalTrainerBattleWon[]; @@ -191,6 +191,7 @@ extern const u8 BattleScript_OwnTempoPrevents[]; extern const u8 BattleScript_SoundproofProtected[]; extern const u8 BattleScript_AbilityNoSpecificStatLoss[]; extern const u8 BattleScript_StickyHoldActivates[]; +extern const u8 BattleScript_StickyHoldActivatesRet[]; extern const u8 BattleScript_ColorChangeActivates[]; extern const u8 BattleScript_RoughSkinActivates[]; extern const u8 BattleScript_CuteCharmActivates[]; @@ -198,6 +199,7 @@ extern const u8 BattleScript_AbilityStatusEffect[]; extern const u8 BattleScript_SynchronizeActivates[]; extern const u8 BattleScript_NoItemSteal[]; extern const u8 BattleScript_AbilityCuredStatus[]; +extern const u8 BattleScript_AbilityCuredStatusEnd3[]; extern const u8 BattleScript_IgnoresWhileAsleep[]; extern const u8 BattleScript_IgnoresAndUsesRandomMove[]; extern const u8 BattleScript_MoveUsedLoafingAround[]; @@ -205,22 +207,10 @@ extern const u8 BattleScript_TruantLoafingAround[]; extern const u8 BattleScript_IgnoresAndFallsAsleep[]; extern const u8 BattleScript_IgnoresAndHitsItself[]; extern const u8 BattleScript_SubstituteFade[]; -extern const u8 BattleScript_BerryCurePrlzEnd2[]; -extern const u8 BattleScript_BerryCureParRet[]; -extern const u8 BattleScript_BerryCurePsnEnd2[]; -extern const u8 BattleScript_BerryCurePsnRet[]; -extern const u8 BattleScript_BerryCureBrnEnd2[]; -extern const u8 BattleScript_BerryCureBrnRet[]; -extern const u8 BattleScript_BerryCureFrzEnd2[]; -extern const u8 BattleScript_BerryCureFrzRet[]; -extern const u8 BattleScript_BerryCureFrbEnd2[]; -extern const u8 BattleScript_BerryCureFrbRet[]; -extern const u8 BattleScript_BerryCureSlpEnd2[]; -extern const u8 BattleScript_BerryCureSlpRet[]; +extern const u8 BattleScript_BerryCureStatusEnd2[]; +extern const u8 BattleScript_BerryCureStatusRet[]; extern const u8 BattleScript_BerryCureConfusionEnd2[]; extern const u8 BattleScript_BerryCureConfusionRet[]; -extern const u8 BattleScript_BerryCureChosenStatusEnd2[]; -extern const u8 BattleScript_BerryCureChosenStatusRet[]; extern const u8 BattleScript_WhiteHerbEnd2[]; extern const u8 BattleScript_WhiteHerbRet[]; extern const u8 BattleScript_ItemHealHP_RemoveItemRet[]; @@ -354,8 +344,9 @@ extern const u8 BattleScript_WeaknessPolicy[]; extern const u8 BattleScript_TargetItemStatRaise[]; extern const u8 BattleScript_RockyHelmetActivates[]; extern const u8 BattleScript_ItemHurtEnd2[]; -extern const u8 BattleScript_AirBaloonMsgIn[]; -extern const u8 BattleScript_AirBaloonMsgPop[]; +extern const u8 BattleScript_AirBalloonMsgIn[]; +extern const u8 BattleScript_AirBalloonMsgInRet[]; +extern const u8 BattleScript_AirBalloonMsgPop[]; extern const u8 BattleScript_ItemHurtRet[]; extern const u8 BattleScript_ToxicOrb[]; extern const u8 BattleScript_FlameOrb[]; @@ -686,7 +677,7 @@ extern const u8 BattleScript_EffectSoftboiled[]; extern const u8 BattleScript_EffectStockpile[]; extern const u8 BattleScript_EffectSpitUp[]; extern const u8 BattleScript_EffectSwallow[]; -extern const u8 BattleScript_EffectWorrySeed[]; +extern const u8 BattleScript_EffectOverwriteAbility[]; extern const u8 BattleScript_EffectHail[]; extern const u8 BattleScript_EffectTorment[]; extern const u8 BattleScript_EffectFlatter[]; @@ -747,7 +738,6 @@ extern const u8 BattleScript_EffectGuardSplit[]; extern const u8 BattleScript_EffectStickyWeb[]; extern const u8 BattleScript_EffectMetalBurst[]; extern const u8 BattleScript_EffectLuckyChant[]; -extern const u8 BattleScript_EffectSimpleBeam[]; extern const u8 BattleScript_EffectEntrainment[]; extern const u8 BattleScript_EffectHealPulse[]; extern const u8 BattleScript_EffectQuash[]; @@ -824,7 +814,6 @@ extern const u8 BattleScript_EffectSkyDrop[]; extern const u8 BattleScript_EffectMeteorBeam[]; extern const u8 BattleScript_EffectCourtChange[]; extern const u8 BattleScript_EffectExtremeEvoboost[]; -extern const u8 BattleScript_EffectHitSetTerrain[]; extern const u8 BattleScript_EffectDarkVoid[]; extern const u8 BattleScript_EffectVictoryDance[]; extern const u8 BattleScript_EffectTeatime[]; @@ -866,10 +855,6 @@ extern const u8 BattleScript_SilphScopeUnveiled[]; // pokefirered extern const u8 BattleScript_BattleTowerTrainerBattleWon[]; extern const u8 BattleScript_MoveUsedLoafingAroundMsg[]; -extern const u8 BattleScript_GhostGetOutGetOut[]; -extern const u8 BattleScript_TooScaredToMove[]; -extern const u8 BattleScript_GhostBallDodge[]; extern const u8 BattleScript_OldMan_Pokedude_CaughtMessage[]; -extern const u8 BattleScript_SilphScopeUnveiled[]; #endif // GUARD_BATTLE_SCRIPTS_H diff --git a/include/battle_terastal.h b/include/battle_terastal.h index 9c55a49d7..6bfb74986 100644 --- a/include/battle_terastal.h +++ b/include/battle_terastal.h @@ -4,11 +4,11 @@ void ActivateTera(u32 battler); void ApplyBattlerVisualsForTeraAnim(u32 battler); bool32 CanTerastallize(u32 battler); -u32 GetBattlerTeraType(u32 battler); -void ExpendTypeStellarBoost(u32 battler, u32 type); -bool32 IsTypeStellarBoosted(u32 battler, u32 type); +enum Type GetBattlerTeraType(u32 battler); +void ExpendTypeStellarBoost(u32 battler, enum Type type); +bool32 IsTypeStellarBoosted(u32 battler, enum Type type); uq4_12_t GetTeraMultiplier(struct DamageContext *ctx); -u16 GetTeraTypeRGB(u32 type); +u16 GetTeraTypeRGB(enum Type type); #endif diff --git a/include/battle_util.h b/include/battle_util.h index f8a910b03..1481656fb 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -3,6 +3,7 @@ #include "move.h" #include "constants/battle_string_ids.h" +#include "constants/hold_effects.h" #define MOVE_LIMITATION_ZEROMOVE (1 << 0) #define MOVE_LIMITATION_PP (1 << 1) @@ -39,7 +40,15 @@ enum MoveAbsorbed MOVE_ABSORBED_BY_BOOST_FLASH_FIRE, }; -enum { +enum FieldEffectCases +{ + FIELD_EFFECT_TRAINER_STATUSES, + FIELD_EFFECT_OVERWORLD_TERRAIN, + FIELD_EFFECT_OVERWORLD_WEATHER, +}; + +enum AbilityEffect +{ ABILITYEFFECT_ON_SWITCHIN, ABILITYEFFECT_ENDTURN, ABILITYEFFECT_MOVE_END_ATTACKER, @@ -53,33 +62,9 @@ enum { ABILITYEFFECT_NEUTRALIZINGGAS_FIRST_TURN, ABILITYEFFECT_ON_WEATHER, ABILITYEFFECT_ON_TERRAIN, - ABILITYEFFECT_SWITCH_IN_TERRAIN, - ABILITYEFFECT_SWITCH_IN_WEATHER, ABILITYEFFECT_OPPORTUNIST, ABILITYEFFECT_OPPORTUNIST_FIRST_TURN, - ABILITYEFFECT_SWITCH_IN_STATUSES, -}; - -// For the first argument of ItemBattleEffects, to deteremine which block of item effects to try -enum ItemCaseId -{ - ITEMEFFECT_NONE, - ITEMEFFECT_ON_SWITCH_IN, - ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN, - ITEMEFFECT_LEFTOVERS, // Leftovers, Black Sludge - ITEMEFFECT_NORMAL, - ITEMEFFECT_TRY_HEALING, - ITEMEFFECT_MOVE_END, - ITEMEFFECT_KINGSROCK, - ITEMEFFECT_TARGET, - ITEMEFFECT_ORBS, - ITEMEFFECT_LIFEORB_SHELLBELL, - ITEMEFFECT_USE_LAST_ITEM, // move end effects for just the battler, not whole field - ITEMEFFECT_WHITE_HERB, - ITEMEFFECT_WHITE_HERB_ENDTURN, - ITEMEFFECT_WHITE_HERB_FIRST_TURN, - ITEMEFFECT_MIRROR_HERB, - ITEMEFFECT_MIRROR_HERB_FIRST_TURN, + ABILITYEFFECT_ON_SWITCHIN_IMMUNITIES, }; enum ItemEffect @@ -106,7 +91,7 @@ enum ItemEffect // for Natural Gift and Fling struct TypePower { - u8 type; + enum Type type; u8 power; u16 effect; }; @@ -127,7 +112,7 @@ enum MoveSuccessOrder CANCELLER_TAUNTED, CANCELLER_IMPRISONED, CANCELLER_CONFUSED, - CANCELLER_GHOST, // pokefirered + CANCELLER_GHOST, CANCELLER_PARALYSED, CANCELLER_INFATUATION, CANCELLER_BIDE, @@ -174,19 +159,22 @@ struct DamageContext u32 battlerAtk:3; u32 battlerDef:3; u32 move:16; - u32 moveType:5; + enum Type moveType:5; u32 isCrit:1; u32 randomFactor:1; u32 updateFlags:1; - u32 padding1:2; + u32 isAnticipation:1; + u32 padding1:1; u32 weather:16; u32 fixedBasePower:8; u32 padding2:8; + u32 chosenMove:16; // May be different to 'move', e.g. for Z moves. + u32 padding3:16; uq4_12_t typeEffectivenessModifier; enum Ability abilityAtk; enum Ability abilityDef; - enum ItemHoldEffect holdEffectAtk:16; - enum ItemHoldEffect holdEffectDef:16; + enum HoldEffect holdEffectAtk; + enum HoldEffect holdEffectDef; }; struct BattleContext @@ -194,8 +182,9 @@ struct BattleContext u32 battlerAtk:3; u32 battlerDef:3; u32 currentMove:16; - enum BattleMoveEffects moveEffect:10; - enum Ability ability[MAX_BATTLERS_COUNT]; + u32 padding:10; + enum Ability abilities[MAX_BATTLERS_COUNT]; + enum HoldEffect holdEffects[MAX_BATTLERS_COUNT]; }; enum SleepClauseBlock @@ -217,9 +206,17 @@ enum SkyDropState #define SKY_DROP_NO_TARGET 0xFF #define SKY_DROP_RELEASED_TARGET 0xFE +enum EjectPackTiming +{ + FIRST_TURN, + END_TURN, + OTHER, +}; + void HandleAction_ThrowBall(void); u32 GetCurrentBattleWeather(void); bool32 EndOrContinueWeather(void); +bool32 IsUnnerveBlocked(u32 battler, u32 itemId); bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move); bool32 HandleMoveTargetRedirection(void); void HandleAction_UseMove(void); @@ -262,10 +259,12 @@ bool32 HandleFaintedMonActions(void); void TryClearRageAndFuryCutter(void); enum MoveCanceller AtkCanceller_MoveSuccessOrder(struct BattleContext *ctx); bool32 HasNoMonsToSwitch(u32 battler, u8 partyIdBattlerOn1, u8 partyIdBattlerOn2); -bool32 TryChangeBattleWeather(u32 battler, u32 battleWeatherId, bool32 viaAbility); +bool32 TryChangeBattleWeather(u32 battler, u32 battleWeatherId, u32 ability); +bool32 TryChangeBattleTerrain(u32 battler, u32 statusFlag); bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum Ability abilityDef, u32 move, enum FunctionCallOption option); -bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef, u32 move, u32 moveType, enum FunctionCallOption option); -u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 special, u32 moveArg); +bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef, u32 move, enum Type moveType, enum FunctionCallOption option); +bool32 TryFieldEffects(enum FieldEffectCases caseId); +u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ability, u32 special, u32 moveArg); bool32 TryPrimalReversion(u32 battler); bool32 IsNeutralizingGasOnField(void); bool32 IsMoldBreakerTypeAbility(u32 battler, enum Ability ability); @@ -283,20 +282,19 @@ u32 GetProtectType(enum ProtectMethod method); bool32 CanBattlerEscape(u32 battler); // no ability check void BattleScriptExecute(const u8 *BS_ptr); void BattleScriptPushCursorAndCallback(const u8 *BS_ptr); -u32 ItemBattleEffects(enum ItemCaseId, u32 battler); void ClearVariousBattlerFlags(u32 battler); void HandleAction_RunBattleScript(void); u32 SetRandomTarget(u32 battler); u32 GetBattleMoveTarget(u16 move, u8 setTarget); u8 GetAttackerObedienceForAction(); -enum ItemHoldEffect GetBattlerHoldEffect(u32 battler); -enum ItemHoldEffect GetBattlerHoldEffectIgnoreAbility(u32 battler); -enum ItemHoldEffect GetBattlerHoldEffectIgnoreNegation(u32 battler); -enum ItemHoldEffect GetBattlerHoldEffectInternal(u32 battler, u32 ability); +enum HoldEffect GetBattlerHoldEffect(u32 battler); +enum HoldEffect GetBattlerHoldEffectIgnoreAbility(u32 battler); +enum HoldEffect GetBattlerHoldEffectIgnoreNegation(u32 battler); +enum HoldEffect GetBattlerHoldEffectInternal(u32 battler, u32 ability); u32 GetBattlerHoldEffectParam(u32 battler); -bool32 CanBattlerAvoidContactEffects(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum ItemHoldEffect holdEffectAtk, u32 move); -bool32 IsMoveMakingContact(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum ItemHoldEffect holdEffectAtk, u32 move); -bool32 IsBattlerGrounded(u32 battler, enum Ability ability, enum ItemHoldEffect holdEffect); +bool32 CanBattlerAvoidContactEffects(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum HoldEffect holdEffectAtk, u32 move); +bool32 IsMoveMakingContact(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum HoldEffect holdEffectAtk, u32 move); +bool32 IsBattlerGrounded(u32 battler, enum Ability ability, enum HoldEffect holdEffect); u32 GetMoveSlot(u16 *moves, u32 move); u32 GetBattlerWeight(u32 battler); u32 CalcRolloutBasePower(u32 battlerAtk, u32 basePower, u32 rolloutTimer); @@ -307,11 +305,11 @@ s32 DoFixedDamageMoveCalc(struct DamageContext *ctx); s32 ApplyModifiersAfterDmgRoll(struct DamageContext *ctx, s32 dmg); uq4_12_t CalcTypeEffectivenessMultiplier(struct DamageContext *ctx); uq4_12_t CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, enum Ability abilityDef); -uq4_12_t GetTypeModifier(u32 atkType, u32 defType); -uq4_12_t GetOverworldTypeEffectiveness(struct Pokemon *mon, u8 moveType); +uq4_12_t GetTypeModifier(enum Type atkType, enum Type defType); +uq4_12_t GetOverworldTypeEffectiveness(struct Pokemon *mon, enum Type moveType); void UpdateMoveResultFlags(uq4_12_t modifier, u16 *resultFlags); s32 GetStealthHazardDamage(enum TypeSideHazard hazardType, u32 battler); -s32 GetStealthHazardDamageByTypesAndHP(enum TypeSideHazard hazardType, u8 type1, u8 type2, u32 maxHp); +s32 GetStealthHazardDamageByTypesAndHP(enum TypeSideHazard hazardType, enum Type type1, enum Type type2, u32 maxHp); bool32 CanMegaEvolve(u32 battler); bool32 CanUltraBurst(u32 battler); void ActivateMegaEvolution(u32 battler); @@ -320,24 +318,27 @@ bool32 IsBattlerMegaEvolved(u32 battler); bool32 IsBattlerPrimalReverted(u32 battler); bool32 IsBattlerUltraBursted(u32 battler); u16 GetBattleFormChangeTargetSpecies(u32 battler, enum FormChanges method); +bool32 TryRevertPartyMonFormChange(u32 partyIndex); bool32 TryBattleFormChange(u32 battler, enum FormChanges method); bool32 DoBattlersShareType(u32 battler1, u32 battler2); bool32 CanBattlerGetOrLoseItem(u32 battler, u16 itemId); u32 GetBattlerVisualSpecies(u32 battler); -bool32 TryClearIllusion(u32 battler, u32 caseID); +bool32 TryClearIllusion(u32 battler, enum AbilityEffect caseID); u32 GetIllusionMonSpecies(u32 battler); struct Pokemon *GetIllusionMonPtr(u32 battler); void ClearIllusionMon(u32 battler); u32 GetIllusionMonPartyId(struct Pokemon *party, struct Pokemon *mon, struct Pokemon *partnerMon, u32 battler); bool32 SetIllusionMon(struct Pokemon *mon, u32 battler); +u32 TryImmunityAbilityHealStatus(u32 battler, enum AbilityEffect caseID); bool32 ShouldGetStatBadgeBoost(u16 flagId, u32 battler); +uq4_12_t GetBadgeBoostModifier(void); enum DamageCategory GetBattleMoveCategory(u32 move); void SetDynamicMoveCategory(u32 battlerAtk, u32 battlerDef, u32 move); bool32 CanFling(u32 battler); bool32 IsTelekinesisBannedSpecies(u16 species); bool32 IsHealBlockPreventingMove(u32 battler, u32 move); bool32 IsBelchPreventingMove(u32 battler, u32 move); -bool32 HasEnoughHpToEatBerry(u32 battler, u32 hpFraction, u32 itemId); +bool32 HasEnoughHpToEatBerry(u32 battler, enum Ability ability, u32 hpFraction, u32 itemId); bool32 IsPartnerMonFromSameTrainer(u32 battler); enum DamageCategory GetCategoryBasedOnStats(u32 battler); void SetShellSideArmCategory(void); @@ -347,13 +348,10 @@ void TryRestoreHeldItems(void); bool32 CanStealItem(u32 battlerStealing, u32 battlerItem, u16 item); void TrySaveExchangedItem(u32 battler, u16 stolenItem); bool32 IsPartnerMonFromSameTrainer(u32 battler); -enum ItemEffect TryHandleSeed(u32 battler, u32 terrainFlag, u32 statId, u32 itemId, enum ItemCaseId caseID); bool32 IsBattlerAffectedByHazards(u32 battler, bool32 toxicSpikes); void SortBattlersBySpeed(u8 *battlers, bool32 slowToFast); -bool32 CompareStat(u32 battler, u8 statId, u8 cmpTo, u8 cmpKind); -bool32 TryRoomService(u32 battler); +bool32 CompareStat(u32 battler, enum Stat statId, u8 cmpTo, u8 cmpKind, enum Ability ability); bool32 BlocksPrankster(u16 move, u32 battlerPrankster, u32 battlerDef, bool32 checkTarget); -u16 GetUsedHeldItem(u32 battler); bool32 PickupHasValidTarget(u32 battler); bool32 CantPickupItem(u32 battler); bool32 IsBattlerWeatherAffected(u32 battler, u32 weatherFlags); @@ -381,7 +379,7 @@ bool32 CanBeFrozen(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef); bool32 CanGetFrostbite(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef); bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum Ability abilityDef, enum MoveEffect secondaryMoveEffect, enum FunctionCallOption option); bool32 CanBeConfused(u32 battler); -bool32 IsBattlerTerrainAffected(u32 battler, enum Ability ability, enum ItemHoldEffect holdEffect, u32 terrainFlag); +bool32 IsBattlerTerrainAffected(u32 battler, enum Ability ability, enum HoldEffect holdEffect, u32 terrainFlag); u32 GetBattlerAffectionHearts(u32 battler); void TryToRevertMimicryAndFlags(void); bool32 BattleArenaTurnEnd(void); @@ -393,12 +391,12 @@ bool32 AreBattlersOfOppositeGender(u32 battler1, u32 battler2); bool32 AreBattlersOfSameGender(u32 battler1, u32 battler2); u32 CalcSecondaryEffectChance(u32 battler, enum Ability battlerAbility, const struct AdditionalEffect *additionalEffect); bool32 MoveEffectIsGuaranteed(u32 battler, enum Ability battlerAbility, const struct AdditionalEffect *additionalEffect); -void GetBattlerTypes(u32 battler, bool32 ignoreTera, u32 types[static 3]); -u32 GetBattlerType(u32 battler, u32 typeIndex, bool32 ignoreTera); +void GetBattlerTypes(u32 battler, bool32 ignoreTera, enum Type types[static 3]); +enum Type GetBattlerType(u32 battler, u32 typeIndex, bool32 ignoreTera); bool8 CanMonParticipateInSkyBattle(struct Pokemon *mon); bool8 IsMonBannedFromSkyBattles(u16 species); -void RemoveBattlerType(u32 battler, u8 type); -u32 GetBattleMoveType(u32 move); +void RemoveBattlerType(u32 battler, enum Type type); +enum Type GetBattleMoveType(u32 move); void TryActivateSleepClause(u32 battler, u32 indexInParty); void TryDeactivateSleepClause(u32 battlerSide, u32 indexInParty); bool32 IsSleepClauseActiveForSide(u32 battlerSide); @@ -410,14 +408,14 @@ bool32 IsPursuitTargetSet(void); void ClearPursuitValuesIfSet(u32 battler); void ClearPursuitValues(void); bool32 HasWeatherEffect(void); +bool32 IsAnyTargetAffected(u32 battlerAtk); bool32 IsFutureSightAttackerInParty(u32 battlerAtk, u32 battlerDef, u32 move); bool32 HadMoreThanHalfHpNowDoesnt(u32 battler); +void ChooseStatBoostAnimation(u32 battler); void UpdateStallMons(void); -bool32 TryRestoreHPBerries(u32 battler, enum ItemCaseId caseId); -bool32 TrySwitchInEjectPack(enum ItemCaseId caseID); +bool32 TrySwitchInEjectPack(enum EjectPackTiming timing); u32 GetBattlerVolatile(u32 battler, enum Volatile _volatile); void SetMonVolatile(u32 battler, enum Volatile _volatile, u32 newValue); -u32 TryBoosterEnergy(u32 battler, enum Ability ability, enum ItemCaseId caseID); bool32 ItemHealMonVolatile(u32 battler, u16 itemId); void PushHazardTypeToQueue(u32 side, enum Hazards hazardType); bool32 IsHazardOnSide(u32 side, enum Hazards hazardType); @@ -426,13 +424,17 @@ void RemoveAllHazardsFromField(u32 side); bool32 IsHazardOnSideAndClear(u32 side, enum Hazards hazardType); void RemoveHazardFromField(u32 side, enum Hazards hazardType); bool32 CanMoveSkipAccuracyCalc(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum Ability abilityDef, u32 move, enum FunctionCallOption option); -u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, enum Ability atkAbility, enum Ability defAbility, u32 atkHoldEffect, u32 defHoldEffect); +u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, enum Ability atkAbility, enum Ability defAbility, enum HoldEffect atkHoldEffect, enum HoldEffect defHoldEffect); bool32 IsSemiInvulnerable(u32 battler, enum SemiInvulnerableExclusion excludeCommander); bool32 BreaksThroughSemiInvulnerablity(u32 battler, u32 move); +bool32 HasPartnerTrainer(u32 battler); +bool32 IsAffectedByPowderMove(u32 battler, u32 ability, enum HoldEffect holdEffect); u32 GetNaturePowerMove(u32 battler); u32 GetNaturePowerMove(u32 battler); void RemoveAbilityFlags(u32 battler); bool32 IsDazzlingAbility(enum Ability ability); bool32 IsAllowedToUseBag(void); +bool32 IsAnyTargetTurnDamaged(u32 battlerAtk); +bool32 IsMimikyuDisguised(u32 battler); #endif // GUARD_BATTLE_UTIL_H diff --git a/include/config/battle.h b/include/config/battle.h index 8533c339a..3a702ef22 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -19,7 +19,7 @@ #define B_LEVEL_UP_NOTIFICATION GEN_LATEST // In Gen9+, if the Pokémon gets enough experience to level up multiple times, the message is only displayed once. // Stat settings -#define B_BADGE_BOOST GEN_LATEST // In Gen4+, Gym Badges no longer boost a Pokémon's stats. +#define B_BADGE_BOOST GEN_LATEST // In Gen4+, Gym Badges no longer boost a Pokémon's stats. (Gen2 does not include the additional boost to the type matching the gym the badge is from) #define B_FRIENDSHIP_BOOST FALSE // In LGPE only, all stats except HP are boosted up to 10% based on Friendship. Unlike B_BADGE_BOOST, these boosts are accounted when calculating base stats. #define B_MAX_LEVEL_EV_GAINS GEN_LATEST // In Gen5+, Lv100 Pokémon can obtain Effort Values normally. #define B_RECALCULATE_STATS GEN_LATEST // In Gen5+, the stats of the Pokémon who participate in battle are recalculated at the end of each battle. @@ -166,10 +166,9 @@ #define B_BATTLE_BOND GEN_LATEST // In Gen9+, Battle Bond increases Atk, SpAtk and Speed by one stage, once per battle #define B_ATE_MULTIPLIER GEN_LATEST // In Gen7+, -ate abilities (Aerilate, Galvanize, Normalize, Pixilate, Refrigerate) multiply damage by 1.2. Otherwise, it's 1.3, except Normalize which has no multiplier. #define B_DEFIANT_STICKY_WEB GEN_LATEST // In Gen9+, Defiant activates on Sticky Web regardless of who set it up. In Gen8, Defiant does not activate on Sticky Web set up by an ally after Court Change swaps its side. +#define B_POWDER_OVERCOAT GEN_LATEST // In Gen6+, Overcoat blocks powder and spore moves from affecting the user. // Item settings -#define B_HP_BERRIES GEN_LATEST // In Gen4+, berries which restore HP activate immediately after HP drops to half. In Gen3, the effect occurs at the end of the turn. -#define B_BERRIES_INSTANT GEN_LATEST // In Gen4+, most berries activate on battle start/switch-in if applicable. In Gen3, they only activate either at the move end or turn end. #define B_CONFUSE_BERRIES_HEAL GEN_LATEST // Before Gen7, Figy and similar berries restore 1/8th of HP and trigger at half HP. In Gen7 they restore half HP, triggering at 25% HP. In Gen8 they heal 1/3rd of HP. #define B_X_ITEMS_BUFF GEN_LATEST // In Gen7+, the X Items raise a stat by 2 stages instead of 1. #define B_MENTAL_HERB GEN_LATEST // In Gen5+, the Mental Herb cures Taunt, Encore, Torment, Heal Block, and Disable in addition to Infatuation from before. @@ -317,6 +316,7 @@ #define B_TOXIC_REVERSAL GEN_LATEST // In Gen5+, bad poison will change to regular poison at the end of battles. #define B_TRY_CATCH_TRAINER_BALL GEN_LATEST // In Gen4+, trying to catch a Trainer's Pokémon does not consume the Poké Ball. #define B_SLEEP_CLAUSE FALSE // Enables Sleep Clause all the time in every case, overriding B_FLAG_SLEEP_CLAUSE. Use that for modularity. +#define B_PARTNER_MONS_MARKED_SEEN FALSE // If TRUE, if your double battle partner sends out a Pokémon you haven't encountered yet, it will be marked as SEEN in your Pokédex. #define NUM_BEEPS_GEN_LATEST 4 // Loops 4 times #define NUM_BEEPS_GEN_3 -1 // Loops infinitely diff --git a/include/config/contest.h b/include/config/contest.h new file mode 100644 index 000000000..8ad2bef25 --- /dev/null +++ b/include/config/contest.h @@ -0,0 +1,10 @@ +#ifndef GUARD_CONFIG_CONTEST_H +#define GUARD_CONFIG_CONTEST_H + +// unused in fire red but kept for consistency with expansion + +// Move data settings +#define C_UPDATED_MOVE_CATEGORIES GEN_LATEST // Updates contest category. +#define C_UPDATED_MOVE_EFFECTS GEN_LATEST // Updates contest effects. + +#endif // GUARD_CONFIG_CONTEST_H diff --git a/include/config/fishing.h b/include/config/fishing.h new file mode 100644 index 000000000..0cbf666a5 --- /dev/null +++ b/include/config/fishing.h @@ -0,0 +1,13 @@ +#ifndef GUARD_CONFIG_FISHING_H +#define GUARD_CONFIG_FISHING_H + +#define I_FISHING_BITE_ODDS GEN_LATEST // In Gen 1 and Gen 2, the Old Rod has a 100% chance for a bite, Good Rod has a 66% chance for a bite, and Super Rod has a 50% chance for a bite. In Gen 3, all rods have a base 50% chance for a bite. In Gen 4 onwards, the Old Rod has a base 25% chance for a bite, Good Rod has a 50% chance for a bite, and Super Rod has a 75% chance for a bite. +#define I_FISHING_MINIGAME GEN_3 // Each generation uses a variation of reeling in Pokémon once they have been hooked. NOTE: Only the Gen 1/2 and Gen 3 minigames are implemented right now! +#define I_FISHING_ENVIRONMENT GEN_LATEST // In Gen 3, the battle environment when fighting a hooked Pokémon is based on the tile the player is standing on. In Gen 4 onwards, the environment is based on tile that is being fished in, resulting in it usually being a water environment. +#define I_FISHING_STICKY_BOOST GEN_LATEST // In Gen 3, a Pokemon with Suction Cups or Sticky Hold in the first slot of the party causes the chance for a bite to increase by about 35%. In Gen 4 onwards, it doubles the base bite chance. +#define I_FISHING_FOLLOWER_BOOST FALSE // In HGSS, fishing bite odds are increased depending on the friendship of the current following Pokémon. +#define I_FISHING_CHAIN FALSE // Introduced in XY, hooking the same Pokémon repeatedly will increase the odds of that mon being shiny. NOTE: This implementation is an approximation of the actual feature, as XY have not been throughoutly documented or datamined. +#define I_FISHING_PROXIMITY FALSE // In XY, bite chance is boosted by the number of adjacent non-surfable tiles next to your fishing line +#define I_FISHING_TIME_OF_DAY_BOOST FALSE // In XY, bite chance is boosted during morning and evening + +#endif // GUARD_CONFIG_FISHING_H diff --git a/include/config/summary_screen.h b/include/config/summary_screen.h index 9407d93c7..e76cd478b 100644 --- a/include/config/summary_screen.h +++ b/include/config/summary_screen.h @@ -2,14 +2,16 @@ #define GUARD_CONFIG_SUMMARY_SCREEN_H // Settings -#define P_SUMMARY_SCREEN_MOVE_RELEARNER TRUE // If TRUE, shows an option for Pokémon to relearn moves on the summary screen moves page. -#define P_SUMMARY_MOVE_RELEARNER_FULL_PP TRUE // If TRUE, the move relearner in the summary screen restores relearned moves' PP to full. +#define P_SUMMARY_SCREEN_NATURE_COLORS TRUE // If TRUE, nature-based stat boosts and reductions will be red and blue in the summary screen. #define P_SUMMARY_SCREEN_RENAME TRUE // If TRUE, an option to change Pokémon nicknames replaces the cancel prompt on the summary screen info page. + +// IV/EV settings #define P_SUMMARY_SCREEN_IV_EV_INFO FALSE // If TRUE, will allow player to cycle through the Stats, IVs, and EVs in the summary screen skills page. #define P_SUMMARY_SCREEN_IV_EV_BOX_ONLY FALSE // If TRUE, will allow player to cycle through the Stats, IVs, and EVs in the summary screen skills page, but only in the PC storage box. +#define P_SUMMARY_SCREEN_IV_HYPERTRAIN TRUE // If TRUE, stats that have been hyper trained will show as 31/S when viewing them in the summary screen #define P_SUMMARY_SCREEN_IV_EV_TILESET FALSE // If TRUE, loads an alternate tileset to allow changing the "STATS" label in the summary screen skills page. Note: if it's still loading the alternate tileset after changing this and recompiling, you may need a `make clean` before compilation. #define P_SUMMARY_SCREEN_IV_EV_VALUES FALSE // If TRUE, will show the actual IV value instead of the letter grade. -/* +/* LETTER GRADE GUIDE: F = 0 @@ -24,7 +26,32 @@ Info taken from https://bulbapedia.bulbagarden.net/wiki/Stats_judge. #define P_SUMMARY_SCREEN_IV_ONLY FALSE // If TRUE, will only show IV info in the summary screen. #define P_SUMMARY_SCREEN_EV_ONLY FALSE // If TRUE, will only show EV info in the summary screen. -// Flags +// IV/EV flags #define P_FLAG_SUMMARY_SCREEN_IV_EV_INFO 0 // If this flag is set, will allow player to cycle through the Stats, IVs, and EVs in the summary screen skills page. Note: if P_SUMMARY_SCREEN_IV_EV_INFO is TRUE, this flag does nothing. +// Move Relearner settings +#define P_ENABLE_MOVE_RELEARNERS FALSE // If TRUE, it enables move relearners for egg, TM and tutor. (see below for specific configs /flags) +#define P_SORT_MOVES FALSE // If TRUE, sorts all moves alphabetically in the relearner's list. + +// Level up Relearner +#define P_PRE_EVO_MOVES FALSE // If TRUE, it enables the Pokémon to learn moves from it's pre evolution. +#define P_ENABLE_ALL_LEVEL_UP_MOVES FALSE // If TRUE, it enables the Pokémon to learn all level up moves, regardless of its level. + +// TM Relearner +#define P_TM_MOVES_RELEARNER TRUE // If TRUE, enables machine move relearner. +#define P_ENABLE_ALL_TM_MOVES FALSE // If TRUE, it enables the Pokémon to learn all TMs its compatible with, regardless of it being in the bag. + +// Relearner flags - Redundant if P_ENABLE_MOVE_RELEARNERS is TRUE, but still added here incase you don't want all relearners unlocked at the same time. +// To use the following features in scripting, replace the 0s with the flag ID you're assigning it to. +// Eg: Replace with FLAG_UNUSED_0x264 so you can use that flag to toggle the feature. +#define P_FLAG_EGG_MOVES 0 // If this flag is set, enables egg move relearner. +#define P_FLAG_TUTOR_MOVES 0 // If this flag is set, enables tutor move relearner. + +// Move Relearner summary screen +#define P_SUMMARY_SCREEN_MOVE_RELEARNER TRUE // If TRUE, shows an option for Pokémon to relearn moves on the summary screen moves page. +#define P_SUMMARY_MOVE_RELEARNER_FULL_PP TRUE // If TRUE, the move relearner in the summary screen restores relearned moves' PP to full. + +// Move Relearner party menu +#define P_PARTY_MOVE_RELEARNER FALSE // If TRUE, it enables the move relearner in the party menu. + #endif // GUARD_CONFIG_SUMMARY_SCREEN_H diff --git a/include/constants/battle.h b/include/constants/battle.h index eed6c6944..da4037ee3 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -1,6 +1,8 @@ #ifndef GUARD_CONSTANTS_BATTLE_H #define GUARD_CONSTANTS_BATTLE_H +#include "constants/moves.h" + /* * A battler may be in one of four positions on the field. The first bit determines * what side the battler is on, either the player's side or the opponent's side. @@ -45,9 +47,17 @@ enum BattlerId #define BATTLE_OPPOSITE(id) ((id) ^ BIT_SIDE) #define BATTLE_PARTNER(id) ((id) ^ BIT_FLANK) -#define B_SIDE_PLAYER 0 -#define B_SIDE_OPPONENT 1 -#define NUM_BATTLE_SIDES 2 +// Left and right are determined by how they're referred to in tests and everywhere else. +// Left is battlers 0 and 1, right 2 and 3; if you assume the battler referencing them is south, left is to the northeast and right to the northwest. +#define LEFT_FOE(battler) ((BATTLE_OPPOSITE(battler)) & BIT_SIDE) +#define RIGHT_FOE(battler) (((BATTLE_OPPOSITE(battler)) & BIT_SIDE) | BIT_FLANK) + +enum BattleSide +{ + B_SIDE_PLAYER = 0, + B_SIDE_OPPONENT = 1, + NUM_BATTLE_SIDES = 2, +}; #define B_FLANK_LEFT 0 #define B_FLANK_RIGHT 1 @@ -93,14 +103,20 @@ enum BattlerId #define BATTLE_TYPE_FRONTIER (BATTLE_TYPE_BATTLE_TOWER | BATTLE_TYPE_DOME | BATTLE_TYPE_PALACE | BATTLE_TYPE_ARENA | BATTLE_TYPE_FACTORY | BATTLE_TYPE_PIKE | BATTLE_TYPE_PYRAMID) #define BATTLE_TYPE_FRONTIER_NO_PYRAMID (BATTLE_TYPE_BATTLE_TOWER | BATTLE_TYPE_DOME | BATTLE_TYPE_PALACE | BATTLE_TYPE_ARENA | BATTLE_TYPE_FACTORY | BATTLE_TYPE_PIKE) #define BATTLE_TYPE_RECORDED_INVALID ((BATTLE_TYPE_LINK | BATTLE_TYPE_SAFARI | BATTLE_TYPE_FIRST_BATTLE \ - | BATTLE_TYPE_CATCH_TUTORIAL | BATTLE_TYPE_ROAMER | BATTLE_TYPE_EREADER_TRAINER \ + | BATTLE_TYPE_OLD_MAN_TUTORIAL | BATTLE_TYPE_ROAMER | BATTLE_TYPE_EREADER_TRAINER \ | BATTLE_TYPE_LEGENDARY \ | BATTLE_TYPE_RECORDED | BATTLE_TYPE_TRAINER_HILL | BATTLE_TYPE_SECRET_BASE)) -#define WILD_DOUBLE_BATTLE ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_TRAINER)))) -#define RECORDED_WILD_BATTLE ((gBattleTypeFlags & BATTLE_TYPE_RECORDED) && !(gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FRONTIER))) -#define BATTLE_TWO_VS_ONE_OPPONENT ((gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && TRAINER_BATTLE_PARAM.opponentB == 0xFFFF)) -#define BATTLE_TYPE_HAS_AI (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FIRST_BATTLE | BATTLE_TYPE_SAFARI | BATTLE_TYPE_ROAMER | BATTLE_TYPE_INGAME_PARTNER) +#define WILD_DOUBLE_BATTLE ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_TRAINER)))) +#define RECORDED_WILD_BATTLE ((gBattleTypeFlags & BATTLE_TYPE_RECORDED) && !(gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FRONTIER))) +#define BATTLE_TWO_VS_ONE_OPPONENT ((gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && TRAINER_BATTLE_PARAM.opponentB == 0xFFFF)) +#define BATTLE_TYPE_HAS_AI (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FIRST_BATTLE | BATTLE_TYPE_SAFARI | BATTLE_TYPE_ROAMER | BATTLE_TYPE_INGAME_PARTNER) +#define BATTLE_TYPE_MORE_THAN_TWO_BATTLERS (BATTLE_TYPE_DOUBLE | BATTLE_TYPE_MULTI | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_TWO_OPPONENTS) +#define BATTLE_TYPE_PLAYER_HAS_PARTNER (BATTLE_TYPE_MULTI | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_TOWER_LINK_MULTI) + +// Multibattle test composite flags +#define BATTLE_MULTI_TEST (BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_TRAINER | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS) +#define BATTLE_TWO_VS_ONE_TEST (BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_TRAINER | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_MULTI) #define RIVAL_BATTLE_HEAL_AFTER 1 #define RIVAL_BATTLE_TUTORIAL 3 @@ -159,12 +175,13 @@ enum VolatileFlags F(VOLATILE_LOCK_CONFUSE, lockConfusionTurns, (u32, 3)) \ F(VOLATILE_MULTIPLETURNS, multipleTurns, (u32, 1)) \ F(VOLATILE_WRAPPED, wrapped, (u32, 1)) \ + F(VOLATILE_WRAPPED_BY, wrappedBy, (enum BattlerId, MAX_BITS(4))) \ + F(VOLATILE_WRAPPED_MOVE, wrappedMove, (u32, MOVES_COUNT_ALL - 1)) \ F(VOLATILE_POWDER, powder, (u32, 1)) \ F(VOLATILE_UNUSED, padding, (u32, 1)) \ F(VOLATILE_INFATUATION, infatuation, (enum BattlerId, MAX_BITS(4))) \ F(VOLATILE_DEFENSE_CURL, defenseCurl, (u32, 1)) \ F(VOLATILE_TRANSFORMED, transformed, (u32, 1)) \ - F(VOLATILE_RECHARGE, recharge, (u32, 1)) \ F(VOLATILE_RAGE, rage, (u32, 1)) \ F(VOLATILE_SUBSTITUTE, substitute, (u32, 1), V_BATON_PASSABLE) \ F(VOLATILE_DESTINY_BOND, destinyBond, (u32, 2)) \ @@ -174,13 +191,14 @@ enum VolatileFlags F(VOLATILE_FORESIGHT, foresight, (u32, 1)) \ F(VOLATILE_DRAGON_CHEER, dragonCheer, (u32, 1), V_BATON_PASSABLE) \ F(VOLATILE_FOCUS_ENERGY, focusEnergy, (u32, 1), V_BATON_PASSABLE) \ - F(VOLATILE_SEMI_INVULNERABLE, semiInvulnerable, (u32, 5)) \ + F(VOLATILE_SEMI_INVULNERABLE, semiInvulnerable, (u32, SEMI_INVULNERABLE_COUNT - 1)) \ F(VOLATILE_ELECTRIFIED, electrified, (u32, 1)) \ F(VOLATILE_MUD_SPORT, mudSport, (u32, 1), V_BATON_PASSABLE) \ F(VOLATILE_WATER_SPORT, waterSport, (u32, 1), V_BATON_PASSABLE) \ F(VOLATILE_INFINITE_CONFUSION, infiniteConfusion, (u32, 1), V_BATON_PASSABLE) \ F(VOLATILE_SALT_CURE, saltCure, (u32, 1)) \ F(VOLATILE_SYRUP_BOMB, syrupBomb, (u32, 1)) \ + F(VOLATILE_STICKY_SYRUPED_BY, stickySyrupedBy, (enum BattlerId, MAX_BITS(4))) \ F(VOLATILE_GLAIVE_RUSH, glaiveRush, (u32, 1)) \ F(VOLATILE_LEECH_SEED, leechSeed, (enum BattlerId, MAX_BITS(4)), V_BATON_PASSABLE) \ F(VOLATILE_LOCK_ON, lockOn, (u32, 2), V_BATON_PASSABLE) \ @@ -234,6 +252,7 @@ enum SemiInvulnerableState STATE_PHANTOM_FORCE, STATE_SKY_DROP, STATE_COMMANDER, + SEMI_INVULNERABLE_COUNT, }; enum SemiInvulnerableExclusion @@ -242,46 +261,41 @@ enum SemiInvulnerableExclusion EXCLUDE_COMMANDER, }; -#define HITMARKER_STRING_PRINTED (1 << 4) -#define HITMARKER_IGNORE_BIDE (1 << 5) -#define HITMARKER_DESTINYBOND (1 << 6) #define HITMARKER_NO_ANIMATIONS (1 << 7) // set from battleSceneOff. Never changed during battle -#define HITMARKER_IGNORE_SUBSTITUTE (1 << 8) -#define HITMARKER_ATTACKSTRING_PRINTED (1 << 9) +#define HITMARKER_UNUSED_8 (1 << 8) +#define HITMARKER_UNUSED_9 (1 << 9) #define HITMARKER_UNUSED_10 (1 << 10) #define HITMARKER_UNUSED_11 (1 << 11) #define HITMARKER_UNUSED_12 (1 << 12) -#define HITMARKER_STATUS_ABILITY_EFFECT (1 << 13) +#define HITMARKER_UNUSED_13 (1 << 13) #define HITMARKER_UNUSED_14 (1 << 14) #define HITMARKER_RUN (1 << 15) -#define HITMARKER_IGNORE_DISGUISE (1 << 16) +#define HITMARKER_UNUSED_16 (1 << 16) #define HITMARKER_DISABLE_ANIMATION (1 << 17) // disable animations during battle scripts, e.g. for Bug Bite #define HITMARKER_UNUSED_18 (1 << 18) #define HITMARKER_UNABLE_TO_USE_MOVE (1 << 19) -#define HITMARKER_PASSIVE_HP_UPDATE (1 << 20) +#define HITMARKER_UNUSED_20 (1 << 20) #define HITMARKER_UNUSED_21 (1 << 21) #define HITMARKER_PLAYER_FAINTED (1 << 22) #define HITMARKER_UNUSED_23 (1 << 23) -#define HITMARKER_GRUDGE (1 << 24) +#define HITMARKER_UNUSED_24 (1 << 24) #define HITMARKER_OBEYS (1 << 25) #define HITMARKER_UNUSED_26 (1 << 26) #define HITMARKER_UNUSED_27 (1 << 27) -#define HITMARKER_FAINTED(battler) (1u << (battler + 28)) -#define HITMARKER_FAINTED2(battler) HITMARKER_FAINTED(battler) +#define HITMARKER_FAINTED(battler) (1u << (battler + 28)) // Also uses bits 29, 30 and 31 // Per-side statuses that affect an entire party #define SIDE_STATUS_REFLECT (1 << 0) #define SIDE_STATUS_LIGHTSCREEN (1 << 1) #define SIDE_STATUS_SAFEGUARD (1 << 2) -#define SIDE_STATUS_FUTUREATTACK (1 << 3) -#define SIDE_STATUS_MIST (1 << 4) -#define SIDE_STATUS_TAILWIND (1 << 5) -#define SIDE_STATUS_AURORA_VEIL (1 << 6) -#define SIDE_STATUS_LUCKY_CHANT (1 << 7) -#define SIDE_STATUS_DAMAGE_NON_TYPES (1 << 8) -#define SIDE_STATUS_RAINBOW (1 << 9) -#define SIDE_STATUS_SEA_OF_FIRE (1 << 10) -#define SIDE_STATUS_SWAMP (1 << 11) +#define SIDE_STATUS_MIST (1 << 3) +#define SIDE_STATUS_TAILWIND (1 << 4) +#define SIDE_STATUS_AURORA_VEIL (1 << 5) +#define SIDE_STATUS_LUCKY_CHANT (1 << 6) +#define SIDE_STATUS_DAMAGE_NON_TYPES (1 << 7) +#define SIDE_STATUS_RAINBOW (1 << 8) +#define SIDE_STATUS_SEA_OF_FIRE (1 << 9) +#define SIDE_STATUS_SWAMP (1 << 10) #define SIDE_STATUS_SCREEN_ANY (SIDE_STATUS_REFLECT | SIDE_STATUS_LIGHTSCREEN | SIDE_STATUS_AURORA_VEIL) #define SIDE_STATUS_PLEDGE_ANY (SIDE_STATUS_RAINBOW | SIDE_STATUS_SEA_OF_FIRE | SIDE_STATUS_SWAMP) @@ -521,7 +535,7 @@ enum __attribute__((packed)) MoveEffect #define MOVE_EFFECT_CONTINUE 0x8000 // Battle environment defines for gBattleEnvironment. -enum BattleEnvironment +enum BattleEnvironments { BATTLE_ENVIRONMENT_GRASS, BATTLE_ENVIRONMENT_LONG_GRASS, @@ -650,6 +664,17 @@ enum BattleEnvironment // Constants for Torment #define PERMANENT_TORMENT 0xF +enum FaintedActions +{ + FAINTED_ACTIONS_NO_MONS_TO_SWITCH, + FAINTED_ACTIONS_GIVE_EXP, + FAINTED_ACTIONS_SET_ABSENT_FLAGS, + FAINTED_ACTIONS_WAIT_STATE, + FAINTED_ACTIONS_HANDLE_FAINTED_MON, + FAINTED_ACTIONS_HANDLE_NEXT_BATTLER, + FAINTED_ACTIONS_MAX_CASE, +}; + // Constants for B_VAR_STARTING_STATUS // Timer value controlled by B_VAR_STARTING_STATUS_TIMER enum StartingStatus diff --git a/include/constants/battle_end_turn.h b/include/constants/battle_end_turn.h new file mode 100644 index 000000000..81c0409ec --- /dev/null +++ b/include/constants/battle_end_turn.h @@ -0,0 +1,92 @@ +#ifndef GUARD_CONSTANTS_BATTLE_END_TURN_H +#define GUARD_CONSTANTS_BATTLE_END_TURN_H + +// General End Turn Effects based on research from smogon from vanilla games: +// https://www.smogon.com/forums/threads/sword-shield-battle-mechanics-research.3655528/page-64#post-9244179 +enum EndTurnResolutionOrder +{ + ENDTURN_ORDER, + ENDTURN_VARIOUS, + ENDTURN_WEATHER, + ENDTURN_WEATHER_DAMAGE, + ENDTURN_EMERGENCY_EXIT_1, + ENDTURN_AFFECTION, + ENDTURN_FUTURE_SIGHT, + ENDTURN_WISH, + ENDTURN_FIRST_EVENT_BLOCK, + ENDTURN_EMERGENCY_EXIT_2, + ENDTURN_AQUA_RING, + ENDTURN_INGRAIN, + ENDTURN_LEECH_SEED, + ENDTURN_POISON, + ENDTURN_BURN, + ENDTURN_FROSTBITE, + ENDTURN_NIGHTMARE, + ENDTURN_CURSE, + ENDTURN_WRAP, + ENDTURN_SALT_CURE, + ENDTURN_OCTOLOCK, + ENDTURN_SYRUP_BOMB, + ENDTURN_TAUNT, + ENDTURN_TORMENT, + ENDTURN_ENCORE, + ENDTURN_DISABLE, + ENDTURN_MAGNET_RISE, + ENDTURN_TELEKINESIS, + ENDTURN_HEAL_BLOCK, + ENDTURN_EMBARGO, + ENDTURN_YAWN, + ENDTURN_PERISH_SONG, + ENDTURN_ROOST, + ENDTURN_EMERGENCY_EXIT_3, + ENDTURN_SECOND_EVENT_BLOCK, + ENDTURN_TRICK_ROOM, + ENDTURN_GRAVITY, + ENDTURN_WATER_SPORT, + ENDTURN_MUD_SPORT, + ENDTURN_WONDER_ROOM, + ENDTURN_MAGIC_ROOM, + ENDTURN_TERRAIN, + ENDTURN_THIRD_EVENT_BLOCK, + ENDTURN_EMERGENCY_EXIT_4, + ENDTURN_FORM_CHANGE_ABILITIES, + ENDTURN_EJECT_PACK, + ENDTURN_DYNAMAX, + ENDTURN_COUNT, +}; + +// Block that handles effects for each individual battler on the field (eg residual damage) +enum FirstEventBlock +{ + FIRST_EVENT_BLOCK_GMAX_MOVE_RESIDUAL, // Needs to be split + FIRST_EVENT_BLOCK_SEA_OF_FIRE_DAMAGE, + FIRST_EVENT_BLOCK_THRASH, // Thrash isn't handled here in vanilla but for now it is that best place for it. + FIRST_EVENT_BLOCK_GRASSY_TERRAIN_HEAL, + FIRST_EVENT_BLOCK_ABILITIES, + FIRST_EVENT_BLOCK_HEAL_ITEMS, +}; + +// Block that tries to remove side statuses +enum SecondEventBlock +{ + SECOND_EVENT_BLOCK_REFLECT, + SECOND_EVENT_BLOCK_LIGHT_SCREEN, + SECOND_EVENT_BLOCK_SAFEGUARD, + SECOND_EVENT_BLOCK_MIST, + SECOND_EVENT_BLOCK_TAILWIND, + SECOND_EVENT_BLOCK_LUCKY_CHANT, + SECOND_EVENT_BLOCK_RAINBOW, + SECOND_EVENT_BLOCK_SEA_OF_FIRE, + SECOND_EVENT_BLOCK_SWAMP, + SECOND_EVENT_BLOCK_AURORA_VEIL, +}; + +// Block that handles Uproar, items and non-form changing abilities +enum ThirdEventBlock +{ + THIRD_EVENT_BLOCK_UPROAR, + THIRD_EVENT_BLOCK_ABILITIES, + THIRD_EVENT_BLOCK_ITEMS, +}; + +#endif // GUARD_CONSTANTS_BATTLE_END_TURN_H diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index 2ddb75adf..f2ba76a55 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -133,7 +133,7 @@ enum __attribute__((packed)) BattleMoveEffects EFFECT_STOCKPILE, EFFECT_SPIT_UP, EFFECT_SWALLOW, - EFFECT_WORRY_SEED, + EFFECT_OVERWRITE_ABILITY, EFFECT_HAIL, EFFECT_TORMENT, EFFECT_FLATTER, @@ -218,7 +218,6 @@ enum __attribute__((packed)) BattleMoveEffects EFFECT_METAL_BURST, EFFECT_LUCKY_CHANT, EFFECT_SUCKER_PUNCH, - EFFECT_SIMPLE_BEAM, EFFECT_ENTRAINMENT, EFFECT_HEAL_PULSE, EFFECT_QUASH, @@ -311,7 +310,6 @@ enum __attribute__((packed)) BattleMoveEffects EFFECT_MAX_HP_50_RECOIL, EFFECT_CHLOROBLAST, // Same effect as EFFECT_MAX_HP_50_RECOIL but follows the same rules as EFFECT_RECOIL EFFECT_EXTREME_EVOBOOST, - EFFECT_HIT_SET_TERRAIN, EFFECT_DARK_VOID, EFFECT_VICTORY_DANCE, EFFECT_TEATIME, diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index d00b8331d..167649c4d 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -125,48 +125,59 @@ enum CmdVarious #define PARTY_SCREEN_OPTIONAL (1 << 7) // Flag for first argument to openpartyscreen +enum SetMoveEffectFlags +{ + NO_FLAGS = 0, + EFFECT_PRIMARY = (1 << 0), + EFFECT_CERTAIN = (1 << 1), +}; + // cases for Cmd_moveend - Order matters! enum MoveEndEffects { MOVEEND_SET_VALUES, MOVEEND_PROTECT_LIKE_EFFECT, + MOVEEND_GRUDGE, + MOVEEND_DESTINY_BOND, MOVEEND_ABSORB, MOVEEND_RAGE, MOVEEND_SYNCHRONIZE_TARGET, MOVEEND_ABILITIES, MOVEEND_ABILITIES_ATTACKER, - MOVEEND_STATUS_IMMUNITY_ABILITIES, + MOVEEND_STATUS_IMMUNITY_ABILITIES, // TODO: Do berries come before???? MOVEEND_SYNCHRONIZE_ATTACKER, MOVEEND_ATTACKER_INVISIBLE, MOVEEND_ATTACKER_VISIBLE, MOVEEND_TARGET_VISIBLE, MOVEEND_ITEM_EFFECTS_TARGET, - MOVEEND_ITEM_EFFECTS_ALL, + MOVEEND_ITEM_EFFECTS_ATTACKER_1, MOVEEND_SYMBIOSIS, - MOVEEND_KINGSROCK, // These item effects will occur each strike of a multi-hit move MOVEEND_SUBSTITUTE, 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_THRESHHOLD_ITEMS_TARGET, // Activation only during a multi hit move / ability (Parental Bond) MOVEEND_MULTIHIT_MOVE, MOVEEND_MOVE_BLOCK, - MOVEEND_ITEM_EFFECTS_ATTACKER, + MOVEEND_ITEM_EFFECTS_ATTACKER_2, MOVEEND_ABILITY_BLOCK, - MOVEEND_SHEER_FORCE, // If move is Sheer Force affected, skip until Opportunist + MOVEEND_SHEER_FORCE, // If move is Sheer Force affected, skip to Hit Escape + One MOVEEND_COLOR_CHANGE, // Color Change / Berserk / Anger Shell - MOVEEND_RED_CARD, + MOVEEND_KEE_MARANGA_HP_THRESHOLD_ITEM_TARGET, + MOVEEND_RED_CARD, MOVEEND_EJECT_BUTTON, - MOVEEND_LIFEORB_SHELLBELL, + MOVEEND_LIFE_ORB_SHELL_BELL, MOVEEND_FORM_CHANGE, MOVEEND_EMERGENCY_EXIT, MOVEEND_EJECT_PACK, MOVEEND_HIT_ESCAPE, + MOVEEND_ITEMS_EFFECTS_ALL, + MOVEEND_WHITE_HERB, MOVEEND_OPPORTUNIST, MOVEEND_MIRROR_HERB, MOVEEND_PICKPOCKET, - MOVEEND_WHITE_HERB, MOVEEND_THIRD_MOVE_BLOCK, MOVEEND_CHANGED_ITEMS, MOVEEND_SAME_MOVE_TURNS, @@ -174,6 +185,9 @@ enum MoveEndEffects MOVEEND_DANCER, MOVEEND_PURSUIT_NEXT_ACTION, MOVEEND_COUNT, + + // This guarantees a correct jump if new moveends are added directly after MOVEEND_HIT_ESCAPE + MOVEEND_JUMP_TO_HIT_ESCAPE_PLUS_ONE = (MOVEEND_HIT_ESCAPE + 1), }; // switch cases @@ -195,4 +209,10 @@ enum TriggerOnFieldStatus ON_WEATHER, }; +enum HealthUpdate +{ + PASSIVE_HP_UPDATE, + MOVE_DAMAGE_HP_UPDATE, +}; + #endif // GUARD_CONSTANTS_BATTLE_SCRIPT_COMMANDS_H diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index cbc815215..2d84b8bf6 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -28,8 +28,7 @@ enum StringID STRINGID_STATSWONTINCREASE2, STRINGID_AVOIDEDDAMAGE, STRINGID_ITDOESNTAFFECT, - STRINGID_ATTACKERFAINTED, - STRINGID_TARGETFAINTED, + STRINGID_BATTLERFAINTED, STRINGID_PLAYERGOTMONEY, STRINGID_PLAYERWHITEOUT, STRINGID_PLAYERWHITEOUT2_WILD, @@ -714,6 +713,11 @@ enum StringID STRINGID_POWERCONSTRUCTPRESENCEOFMANY, STRINGID_POWERCONSTRUCTTRANSFORM, STRINGID_ABILITYSHIELDPROTECTS, + STRINGID_MONTOOSCAREDTOMOVE, + STRINGID_GHOSTGETOUTGETOUT, + STRINGID_SILPHSCOPEUNVEILED, + STRINGID_GHOSTWASMAROWAK, + STRINGID_TRAINER1MON1COMEBACK, // pokefirered specific STRINGID_OLDMANUSEDITEM, @@ -725,11 +729,6 @@ enum StringID STRINGID_PKMNTRANSFERREDBILLSPC, STRINGID_PKMNBOXBILLSPCFULL, STRINGID_POKEDUDEUSED, - STRINGID_MONTOOSCAREDTOMOVE, - STRINGID_GHOSTGETOUTGETOUT, - STRINGID_SILPHSCOPEUNVEILED, - STRINGID_GHOSTWASMAROWAK, - STRINGID_TRAINER1MON1COMEBACK, STRINGID_TRAINER1MON2COMEBACK, STRINGID_TRAINER1MON1AND2COMEBACK, @@ -997,9 +996,15 @@ enum FlashFireStringID B_MSG_FLASH_FIRE_NO_BOOST, }; -// gBerryEffectStringIds -enum BerryEffectStringID +// CureStatusBerryEffectStringID +enum CureStatusBerryEffectStringID { + B_MSG_CURED_PARALYSIS, + B_MSG_CURED_POISON, + B_MSG_CURED_BURN, + B_MSG_CURED_FREEEZE, + B_MSG_CURED_FROSTBITE, + B_MSG_CURED_SLEEP, B_MSG_CURED_PROBLEM, B_MSG_NORMALIZED_STATUS, }; diff --git a/include/constants/generational_changes.h b/include/constants/generational_changes.h index b365a6ea8..88584e997 100644 --- a/include/constants/generational_changes.h +++ b/include/constants/generational_changes.h @@ -41,6 +41,12 @@ enum GenConfigTag GEN_CONFIG_PRANKSTER_DARK_TYPES, GEN_CONFIG_DESTINY_BOND_FAIL, GEN_CONFIG_POWDER_RAIN, + GEN_CONFIG_POWDER_GRASS, + GEN_CONFIG_POWDER_OVERCOAT, + GEN_CONFIG_OBLIVIOUS_TAUNT, + GEN_CONFIG_TOXIC_NEVER_MISS, + GEN_CONFIG_PARALYZE_ELECTRIC, + GEN_CONFIG_BADGE_BOOST, GEN_CONFIG_COUNT }; diff --git a/include/constants/global.h b/include/constants/global.h index 434afd2f7..017e7b583 100644 --- a/include/constants/global.h +++ b/include/constants/global.h @@ -4,6 +4,7 @@ #include "config/general.h" #include "config/battle.h" #include "config/caps.h" +#include "config/contest.h" #include "config/debug.h" #include "config/item.h" #include "config/pokemon.h" @@ -11,6 +12,7 @@ #include "config/dexnav.h" #include "config/ai.h" #include "config/follower_npc.h" +#include "config/summary_screen.h" // Invalid Versions show as "----------" in Gen 4 and Gen 5's summary screen. // In Gens 6 and 7, invalid versions instead show "a distant land" in the summary screen. @@ -99,12 +101,14 @@ #define ALL_MOVES_MASK ((1 << MAX_MON_MOVES) - 1) #define CONTESTANT_COUNT 4 -#define CONTEST_CATEGORY_COOL 0 -#define CONTEST_CATEGORY_BEAUTY 1 -#define CONTEST_CATEGORY_CUTE 2 -#define CONTEST_CATEGORY_SMART 3 -#define CONTEST_CATEGORY_TOUGH 4 -#define CONTEST_CATEGORIES_COUNT 5 +#define CONTEST_CATEGORY_COOL 0 +#define CONTEST_CATEGORY_BEAUTIFUL 1 +#define CONTEST_CATEGORY_BEAUTY CONTEST_CATEGORY_BEAUTIFUL +#define CONTEST_CATEGORY_CUTE 2 +#define CONTEST_CATEGORY_CLEVER 3 +#define CONTEST_CATEGORY_SMART CONTEST_CATEGORY_CLEVER +#define CONTEST_CATEGORY_TOUGH 4 +#define CONTEST_CATEGORIES_COUNT 5 #define QUEST_LOG_SCENE_COUNT 4 diff --git a/include/constants/hold_effects.h b/include/constants/hold_effects.h index 101a198b8..32dacc36d 100644 --- a/include/constants/hold_effects.h +++ b/include/constants/hold_effects.h @@ -1,7 +1,7 @@ #ifndef GUARD_HOLD_EFFECTS_H #define GUARD_HOLD_EFFECTS_H -enum ItemHoldEffect +enum __attribute__((packed)) HoldEffect { HOLD_EFFECT_NONE, HOLD_EFFECT_RESTORE_HP, @@ -120,7 +120,7 @@ enum ItemHoldEffect // Gen7 hold effects HOLD_EFFECT_PROTECTIVE_PADS, HOLD_EFFECT_TERRAIN_EXTENDER, - HOLD_EFFECT_SEEDS, + HOLD_EFFECT_TERRAIN_SEED, HOLD_EFFECT_ADRENALINE_ORB, HOLD_EFFECT_MEMORY, HOLD_EFFECT_Z_CRYSTAL, @@ -151,4 +151,12 @@ enum ItemHoldEffect #define HOLD_EFFECT_PARAM_MISTY_TERRAIN 2 #define HOLD_EFFECT_PARAM_PSYCHIC_TERRAIN 3 +enum ItemActivationState +{ + ACTIVATION_ON_USABLE_AGAIN, + ACTIVATION_ON_PICK_UP, + ACTIVATION_ON_HARVEST, + ACTIVATION_ON_HP_THRESHOLD, +}; + #endif // GUARD_HOLD_EFFECTS_H diff --git a/include/constants/items.h b/include/constants/items.h index 05e2b2471..298b63e99 100644 --- a/include/constants/items.h +++ b/include/constants/items.h @@ -32,12 +32,6 @@ #define ITEM_BEAST_BALL 26 #define ITEM_CHERISH_BALL 27 -// Note: If moving ball IDs around, updating FIRST_BALL/LAST_BALL is not sufficient -// Several places expect the ball IDs to be first and contiguous (e.g. MON_DATA_POKEBALL) -// If adding new balls, it's easiest to insert them after the last ball and increment the below IDs (and removing ITEM_034 for example) -#define FIRST_BALL ITEM_POKE_BALL -#define LAST_BALL ITEM_CHERISH_BALL - // Medicine #define ITEM_POTION 28 #define ITEM_SUPER_POTION 29 @@ -1000,10 +994,34 @@ #define ITEM_STRANGE_BALL 828 -// HOPO BERRY -// LEGEND PLATE +#define ITEM_CLEFABLITE 829 +#define ITEM_VICTREEBELITE 830 +#define ITEM_STARMINITE 831 +#define ITEM_DRAGONINITE 832 +#define ITEM_MEGANIUMITE 833 +#define ITEM_FERALIGITE 834 +#define ITEM_SKARMORITE 835 +#define ITEM_FROSLASSITE 836 +#define ITEM_EMBOARITE 837 +#define ITEM_EXCADRITE 838 +#define ITEM_SCOLIPITE 839 +#define ITEM_SCRAFTINITE 840 +#define ITEM_EELEKTROSSITE 841 +#define ITEM_CHANDELURITE 842 +#define ITEM_CHESNAUGHTITE 843 +#define ITEM_DELPHOXITE 844 +#define ITEM_GRENINJITE 845 +#define ITEM_PYROARITE 846 +#define ITEM_FLOETTITE 847 +#define ITEM_MALAMARITE 848 +#define ITEM_BARBARACITE 849 +#define ITEM_DRAGALGITE 850 +#define ITEM_HAWLUCHANITE 851 +#define ITEM_ZYGARDITE 852 +#define ITEM_DRAMPANITE 853 +#define ITEM_FALINKSITE 854 -#define ITEMS_COUNT 829 +#define ITEMS_COUNT 855 #define ITEM_FIELD_ARROW ITEMS_COUNT // A special item id associated with "Cancel"/"Exit" etc. in a list of items or decorations @@ -1028,8 +1046,8 @@ #define NUM_ROUTE_114_MAN_BERRIES (LAST_ROUTE_114_MAN_BERRY - FIRST_ROUTE_114_MAN_BERRY + 1) #define NUM_ROUTE_114_MAN_BERRIES_SKIPPED (FIRST_ROUTE_114_MAN_BERRY - FIRST_BERRY_INDEX) -#define ITEM_TO_BERRY(itemId)(((itemId) - FIRST_BERRY_INDEX) + 1) -#define ITEM_TO_MAIL(itemId)((itemId) - FIRST_MAIL_INDEX) +#define ITEM_TO_BERRY(itemId) (((itemId) - FIRST_BERRY_INDEX) + 1) +#define ITEM_TO_MAIL(itemId) ((itemId) - FIRST_MAIL_INDEX) #define MAIL_NONE 0xFF #define ITEM_TO_MULCH(itemId)(((itemId) - ITEM_GROWTH_MULCH) + 1) diff --git a/include/constants/move_relearner.h b/include/constants/move_relearner.h new file mode 100644 index 000000000..0229cb7f1 --- /dev/null +++ b/include/constants/move_relearner.h @@ -0,0 +1,29 @@ +#ifndef GUARD_CONSTANTS_MOVE_RELEARNER_H +#define GUARD_CONSTANTS_MOVE_RELEARNER_H + +// Max number of moves shown by the move relearner. +// Increased from 25 to 60 so Mew can display all TMs/HMs. +// If you plan on adding more TMs, increase this number too. +#define MAX_RELEARNER_MOVES 60 + +// Move Relearner menu change constants +enum MoveRelearnerStates +{ + MOVE_RELEARNER_LEVEL_UP_MOVES, + MOVE_RELEARNER_EGG_MOVES, + MOVE_RELEARNER_TM_MOVES, + MOVE_RELEARNER_TUTOR_MOVES, + MOVE_RELEARNER_COUNT, +}; + +enum RelearnMode +{ + RELEARN_MODE_NONE = 0, + RELEARN_MODE_SCRIPT = 1, // Relearning moves through an event script + // These two must stay 2 and 3, they are tied to the summary screen pages + RELEARN_MODE_PSS_PAGE_BATTLE_MOVES = 2, // Relearning moves through the summary screen's battle moves page + RELEARN_MODE_PSS_PAGE_CONTEST_MOVES = 3, // Relearning moves through the summary screen's contest moves page (defaults to contest page on relearner screen) + RELEARN_MODE_PARTY_MENU = 4, // Relearning moves through the party menu's moves submenu +}; + +#endif // GUARD_CONSTANTS_MOVE_RELEARNER_H diff --git a/include/constants/pokemon.h b/include/constants/pokemon.h index 4e00f6544..26fb2081b 100644 --- a/include/constants/pokemon.h +++ b/include/constants/pokemon.h @@ -2,28 +2,31 @@ #define GUARD_CONSTANTS_POKEMON_H // Pokémon types -#define TYPE_NONE 0 -#define TYPE_NORMAL 1 -#define TYPE_FIGHTING 2 -#define TYPE_FLYING 3 -#define TYPE_POISON 4 -#define TYPE_GROUND 5 -#define TYPE_ROCK 6 -#define TYPE_BUG 7 -#define TYPE_GHOST 8 -#define TYPE_STEEL 9 -#define TYPE_MYSTERY 10 -#define TYPE_FIRE 11 -#define TYPE_WATER 12 -#define TYPE_GRASS 13 -#define TYPE_ELECTRIC 14 -#define TYPE_PSYCHIC 15 -#define TYPE_ICE 16 -#define TYPE_DRAGON 17 -#define TYPE_DARK 18 -#define TYPE_FAIRY 19 -#define TYPE_STELLAR 20 -#define NUMBER_OF_MON_TYPES 21 +enum __attribute__((packed)) Type +{ + TYPE_NONE = 0, + TYPE_NORMAL = 1, + TYPE_FIGHTING = 2, + TYPE_FLYING = 3, + TYPE_POISON = 4, + TYPE_GROUND = 5, + TYPE_ROCK = 6, + TYPE_BUG = 7, + TYPE_GHOST = 8, + TYPE_STEEL = 9, + TYPE_MYSTERY = 10, + TYPE_FIRE = 11, + TYPE_WATER = 12, + TYPE_GRASS = 13, + TYPE_ELECTRIC = 14, + TYPE_PSYCHIC = 15, + TYPE_ICE = 16, + TYPE_DRAGON = 17, + TYPE_DARK = 18, + TYPE_FAIRY = 19, + TYPE_STELLAR = 20, + NUMBER_OF_MON_TYPES +}; // Pokémon egg groups #define EGG_GROUP_NONE 0 @@ -74,16 +77,18 @@ #define NUM_NATURES 25 // Pokémon Stats -#define STAT_HP 0 -#define STAT_ATK 1 -#define STAT_DEF 2 -#define STAT_SPEED 3 -#define STAT_SPATK 4 -#define STAT_SPDEF 5 -#define NUM_STATS 6 - -#define STAT_ACC 6 // Only in battles. -#define STAT_EVASION 7 // Only in battles. +enum __attribute__((packed)) Stat +{ + STAT_HP, + STAT_ATK, + STAT_DEF, + STAT_SPEED, + STAT_SPATK, + STAT_SPDEF, + NUM_STATS, + STAT_ACC = NUM_STATS, // Only in battles. + STAT_EVASION, // Only in battles. +}; #define NUM_NATURE_STATS (NUM_STATS - 1) // excludes HP #define NUM_BATTLE_STATS (NUM_STATS + 2) // includes Accuracy and Evasion @@ -169,7 +174,6 @@ #define LEVEL_UP_MOVE_END 0xFFFF #define MAX_LEVEL_UP_MOVES 20 -#define MAX_RELEARNER_MOVES max(MAX_LEVEL_UP_MOVES, 25) #define MON_MALE 0x00 #define MON_FEMALE 0xFE @@ -219,7 +223,7 @@ #define EV_ITEM_RAISE_LIMIT ((I_VITAMIN_EV_CAP >= GEN_8) ? MAX_PER_STAT_EVS : 100) // Move category defines. -enum DamageCategory +enum __attribute__((packed)) DamageCategory { DAMAGE_CATEGORY_PHYSICAL, DAMAGE_CATEGORY_SPECIAL, @@ -350,6 +354,12 @@ enum EvoSpinDirections { SPIN_EITHER, // Player spins either clockwise or counter-clockwise }; +enum ShinyMode { + SHINY_MODE_ALWAYS, + SHINY_MODE_RANDOM, + SHINY_MODE_NEVER +}; + #define MON_PIC_WIDTH 64 #define MON_PIC_HEIGHT 64 #define MON_PIC_SIZE (MON_PIC_WIDTH * MON_PIC_HEIGHT / 2) diff --git a/include/field_player_avatar.h b/include/field_player_avatar.h index 4ef3e6e9a..b60bb86b5 100644 --- a/include/field_player_avatar.h +++ b/include/field_player_avatar.h @@ -20,7 +20,7 @@ void StopPlayerAvatar(void); void GetXYCoordsOneStepInFrontOfPlayer(s16 *xPtr, s16 *yPtr); u8 GetPlayerAvatarGraphicsIdByStateId(u8); void SetPlayerAvatarStateMask(u8 mask); -void AlignFishingAnimationFrames(struct Sprite *sprite); +void AlignFishingAnimationFrames(); void CreateStopSurfingTask_NoMusicChange(u8 direction); void SavePlayerFacingDirectionForTeleport(u8 direction); void SetPlayerAvatarTransitionFlags(u16 flags); @@ -68,5 +68,7 @@ u8 GetRSAvatarGraphicsIdByGender(u8 gender); //sideways stairs u8 GetRightSideStairsDirection(u8 direction); u8 GetLeftSideStairsDirection(u8 direction); +void SetPlayerAvatarFishing(u8 direction); +bool32 MetatileAtCoordsIsWaterTile(s16 x, s16 y); #endif //GUARD_FIELD_PLAYER_AVATAR_H diff --git a/include/fishing.h b/include/fishing.h new file mode 100644 index 000000000..ccad95edb --- /dev/null +++ b/include/fishing.h @@ -0,0 +1,10 @@ +#ifndef GUARD_FISHING_H +#define GUARD_FISHING_H + +void StartFishing(u8 rod); +void UpdateChainFishingStreak(); +u32 CalculateChainFishingShinyRolls(void); +bool32 ShouldUseFishingEnvironmentInBattle(); +void AlignFishingAnimationFrames(void); + +#endif // GUARD_FISHING_H \ No newline at end of file diff --git a/include/generational_changes.h b/include/generational_changes.h index a45325caa..e8b701d09 100644 --- a/include/generational_changes.h +++ b/include/generational_changes.h @@ -44,6 +44,12 @@ static const u8 sGenerationalChanges[GEN_CONFIG_COUNT] = [GEN_CONFIG_PRANKSTER_DARK_TYPES] = B_PRANKSTER_DARK_TYPES, [GEN_CONFIG_DESTINY_BOND_FAIL] = B_DESTINY_BOND_FAIL, [GEN_CONFIG_POWDER_RAIN] = B_POWDER_RAIN, + [GEN_CONFIG_POWDER_GRASS] = B_POWDER_GRASS, + [GEN_CONFIG_POWDER_OVERCOAT] = B_POWDER_OVERCOAT, + [GEN_CONFIG_OBLIVIOUS_TAUNT] = B_OBLIVIOUS_TAUNT, + [GEN_CONFIG_TOXIC_NEVER_MISS] = B_TOXIC_NEVER_MISS, + [GEN_CONFIG_PARALYZE_ELECTRIC] = B_PARALYZE_ELECTRIC, + [GEN_CONFIG_BADGE_BOOST] = B_BADGE_BOOST }; #if TESTING diff --git a/include/item.h b/include/item.h index 5476ab6c9..085459b32 100644 --- a/include/item.h +++ b/include/item.h @@ -258,7 +258,7 @@ const u8 *GetItemEffect(u32 itemId); u32 GetItemStatus1Mask(u16 itemId); bool32 ItemHasVolatileFlag(u16 itemId, enum Volatile volatile); u32 GetItemSellPrice(u32 itemId); -bool32 IsHoldEffectChoice(enum ItemHoldEffect holdEffect); +bool32 IsHoldEffectChoice(enum HoldEffect holdEffect); #endif // GUARD_ITEM_H diff --git a/include/move.h b/include/move.h index b1e8cba99..fe2587a22 100644 --- a/include/move.h +++ b/include/move.h @@ -65,7 +65,7 @@ struct MoveInfo const u8 *name; const u8 *description; enum BattleMoveEffects effect; - u16 type:5; // Up to 32 + enum Type type:5; // Up to 32 enum DamageCategory category:2; u16 power:9; // up to 511 // end of word @@ -81,7 +81,7 @@ struct MoveInfo u32 strikeCount:4; // Max 15 hits. Defaults to 1 if not set. May apply its effect on each hit. u32 criticalHitStage:2; bool32 alwaysCriticalHit:1; - u32 numAdditionalEffects:2; // limited to 3 - don't want to get too crazy + u32 numAdditionalEffects:3; // limited to 7 // Flags bool32 makesContact:1; bool32 ignoresProtect:1; @@ -101,8 +101,8 @@ struct MoveInfo bool32 minimizeDoubleDamage:1; bool32 ignoresTargetAbility:1; bool32 ignoresTargetDefenseEvasionStages:1; - bool32 damagesUnderground:1; // end of word + bool32 damagesUnderground:1; bool32 damagesUnderwater:1; bool32 damagesAirborne:1; bool32 damagesAirborneDoubleDamage:1; @@ -131,7 +131,7 @@ struct MoveInfo bool32 dampBanned:1; //Other bool32 validApprenticeMove:1; - u32 padding:6; + u32 padding:5; // end of word union { @@ -149,6 +149,7 @@ struct MoveInfo u32 absorbPercentage; u32 recoilPercentage; u32 nonVolatileStatus; + u32 overwriteAbility; } argument; // primary/secondary effects @@ -192,7 +193,7 @@ static inline const u8 *GetMoveDescription(u32 moveId) return gMovesInfo[moveId].description; } -static inline u32 GetMoveType(u32 moveId) +static inline enum Type GetMoveType(u32 moveId) { return gMovesInfo[SanitizeMoveId(moveId)].type; } @@ -564,6 +565,11 @@ static inline u32 GetMoveDamagePercentage(u32 move) return gMovesInfo[SanitizeMoveId(move)].argument.damagePercentage; } +static inline u32 GetMoveOverwriteAbility(u32 move) +{ + return gMovesInfo[SanitizeMoveId(move)].argument.overwriteAbility; +} + static inline const struct AdditionalEffect *GetMoveAdditionalEffectById(u32 moveId, u32 effect) { return &gMovesInfo[SanitizeMoveId(moveId)].additionalEffects[effect]; diff --git a/include/pokemon.h b/include/pokemon.h index a30a52218..f40e444fc 100644 --- a/include/pokemon.h +++ b/include/pokemon.h @@ -130,7 +130,7 @@ enum MonData { struct PokemonSubstruct0 { u16 species:11; // 2047 species. - u16 teraType:5; // 30 types. + enum Type teraType:5; // 30 types. u16 heldItem:10; // 1023 items. u16 unused_02:6; u32 experience:21; @@ -399,7 +399,7 @@ struct BattlePokemon /*0x17*/ u32 abilityNum:2; /*0x18*/ s8 statStages[NUM_BATTLE_STATS]; /*0x20*/ enum Ability ability; - /*0x22*/ u8 types[3]; + /*0x22*/ enum Type types[3]; /*0x25*/ u8 pp[MAX_MON_MOVES]; /*0x29*/ u16 hp; /*0x2B*/ u8 level; @@ -442,7 +442,7 @@ struct SpeciesInfo /*0xC4*/ u8 baseSpeed; u8 baseSpAttack; u8 baseSpDefense; - u8 types[2]; + enum Type types[2]; u8 catchRate; u8 forceTeraType; u16 expYield; // expYield was changed from u8 to u16 for the new Exp System. @@ -628,8 +628,8 @@ enum { struct NatureInfo { const u8 *name; - u8 statUp; - u8 statDown; + enum Stat statUp; + enum Stat statDown; u8 backAnim; u8 pokeBlockAnim[2]; u8 battlePalacePercents[4]; @@ -662,6 +662,13 @@ struct FormChange u16 param3; }; +enum FusionExtraMoveHandling +{ + FORGET_EXTRA_MOVES, + SWAP_EXTRA_MOVES_KYUREM_WHITE, + SWAP_EXTRA_MOVES_KYUREM_BLACK +}; + struct Fusion { u16 fusionStorageIndex; @@ -670,11 +677,22 @@ struct Fusion u16 targetSpecies2; u16 fusingIntoMon; u16 fusionMove; - u16 unfuseForgetMove; + enum FusionExtraMoveHandling extraMoveHandling; }; extern const struct Fusion *const gFusionTablePointers[NUM_SPECIES]; +#if P_FUSION_FORMS +#if P_FAMILY_KYUREM +#if P_FAMILY_RESHIRAM +extern const u16 gKyuremWhiteSwapMoveTable[][2]; +#endif //P_FAMILY_RESHIRAM +#if P_FAMILY_ZEKROM +extern const u16 gKyuremBlackSwapMoveTable[][2]; +#endif //P_FAMILY_ZEKROM +#endif //P_FAMILY_KYUREM +#endif //P_FUSION_FORMS + #define NUM_UNOWN_FORMS 28 #define GET_UNOWN_LETTER(personality) (( \ @@ -794,7 +812,7 @@ const u8 *GetSpeciesCategory(u16 species); const u8 *GetSpeciesPokedexDescription(u16 species); u32 GetSpeciesHeight(u16 species); u32 GetSpeciesWeight(u16 species); -u32 GetSpeciesType(u16 species, u8 slot); +enum Type GetSpeciesType(u16 species, u8 slot); enum Ability GetSpeciesAbility(u16 species, u8 slot); u32 GetSpeciesBaseHP(u16 species); u32 GetSpeciesBaseAttack(u16 species); @@ -802,6 +820,7 @@ u32 GetSpeciesBaseDefense(u16 species); u32 GetSpeciesBaseSpAttack(u16 species); u32 GetSpeciesBaseSpDefense(u16 species); u32 GetSpeciesBaseSpeed(u16 species); +u32 GetSpeciesBaseStat(u16 species, u32 statIndex); const struct LevelUpMove *GetSpeciesLevelUpLearnset(u16 species); const u16 *GetSpeciesTeachableLearnset(u16 species); const u16 *GetSpeciesEggMoves(u16 species); @@ -842,7 +861,7 @@ u8 GetPlayerFlankId(void); u16 GetLinkTrainerFlankId(u8 linkPlayerId); s32 GetBattlerMultiplayerId(u16 id); u8 GetTrainerEncounterMusicId(u16 trainerOpponentId); -u16 ModifyStatByNature(u8 nature, u16 stat, u8 statIndex); +u16 ModifyStatByNature(u8 nature, u16 stat, enum Stat statIndex); void AdjustFriendship(struct Pokemon *mon, u8 event); void MonGainEVs(struct Pokemon *mon, u16 defeatedSpecies); u16 GetMonEVCount(struct Pokemon *mon); @@ -853,6 +872,14 @@ void UpdatePartyPokerusTime(u16 days); void PartySpreadPokerus(struct Pokemon *party); bool8 TryIncrementMonLevel(struct Pokemon *mon); u8 CanLearnTeachableMove(u16 species, u16 move); +u8 GetRelearnerLevelUpMoves(struct Pokemon *mon, u16 *moves); +u8 GetRelearnerEggMoves(struct Pokemon *mon, u16 *moves); +u8 GetRelearnerTMMoves(struct Pokemon *mon, u16 *moves); +u8 GetRelearnerTutorMoves(struct Pokemon *mon, u16 *moves); +u8 GetNumberOfLevelUpMoves(struct Pokemon *mon); +u8 GetNumberOfEggMoves(struct Pokemon *mon); +u8 GetNumberOfTMMoves(struct Pokemon *mon); +u8 GetNumberOfTutorMoves(struct Pokemon *mon); u8 GetMoveRelearnerMoves(struct Pokemon *mon, u16 *moves); u8 GetLevelUpMovesBySpecies(u16 species, u16 *moves); u8 GetNumberOfRelearnableMoves(struct Pokemon *mon); @@ -887,6 +914,7 @@ u8 GetOpposingLinkMultiBattlerId(bool8 rightSide, u8 multiplayerId); u16 FacilityClassToPicIndex(u16 facilityClass); u16 PlayerGenderToFrontTrainerPicId(u8 playerGender); void HandleSetPokedexFlag(enum NationalDexOrder nationalNum, u8 caseId, u32 personality); +void HandleSetPokedexFlagFromMon(struct Pokemon *mon, u32 caseId); bool8 HasTwoFramesAnimation(u16 species); struct MonSpritesGfxManager *CreateMonSpritesGfxManager(u8 managerId, u8 mode); void DestroyMonSpritesGfxManager(u8 managerId); @@ -900,7 +928,7 @@ u16 MonTryLearningNewMoveEvolution(struct Pokemon *mon, bool8 firstMove); void RemoveIVIndexFromList(u8 *ivs, u8 selectedIv); void TrySpecialOverworldEvo(void); bool32 SpeciesHasGenderDifferences(u16 species); -bool32 TryFormChange(u32 monId, u32 side, enum FormChanges method); +bool32 TryFormChange(u32 monId, enum BattleSide side, enum FormChanges method); void TryToSetBattleFormChangeMoves(struct Pokemon *mon, enum FormChanges method); u32 GetMonFriendshipScore(struct Pokemon *pokemon); u32 GetMonAffectionHearts(struct Pokemon *pokemon); @@ -914,16 +942,16 @@ void HealPokemon(struct Pokemon *mon); void HealBoxPokemon(struct BoxPokemon *boxMon); void UpdateDaysPassedSinceFormChange(u16 days); void TrySetDayLimitToFormChange(struct Pokemon *mon); -u32 CheckDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum MonState state); +enum Type CheckDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum MonState state); uq4_12_t GetDynamaxLevelHPMultiplier(u32 dynamaxLevel, bool32 inverseMultiplier); u32 GetRegionalFormByRegion(u32 species, u32 region); bool32 IsSpeciesForeignRegionalForm(u32 species, u32 currentRegion); -u32 GetTeraTypeFromPersonality(struct Pokemon *mon); +enum Type GetTeraTypeFromPersonality(struct Pokemon *mon); bool8 ShouldSkipFriendshipChange(void); struct Pokemon *GetSavedPlayerPartyMon(u32 index); u8 *GetSavedPlayerPartyCount(void); void SavePlayerPartyMon(u32 index, struct Pokemon *mon); -u32 IsSpeciesOfType(u32 species, u32 type); +bool32 IsSpeciesOfType(u32 species, enum Type type); // pokefirered u16 GetFirstPartnerMove(u16 species); diff --git a/include/random.h b/include/random.h index f6c870ce8..0a3a711da 100644 --- a/include/random.h +++ b/include/random.h @@ -218,8 +218,11 @@ enum RandomTag RNG_WRAP, RNG_BALLTHROW_CRITICAL, RNG_BALLTHROW_SHAKE, + RNG_PROTECT_FAIL, RNG_PRESENT, RNG_MAGNITUDE, + RNG_FISHING_BITE, + RNG_FISHING_GEN3_STICKY, }; #define RandomWeighted(tag, ...) \ @@ -269,4 +272,13 @@ const void *RandomElementArrayDefault(enum RandomTag, const void *array, size_t u8 RandomWeightedIndex(u8 *weights, u8 length); +#if TESTING +u32 RandomUniformTrials(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32), void *caller); +u32 RandomUniformDefaultValue(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32), void *caller); +u32 RandomWeightedArrayTrials(enum RandomTag tag, u32 sum, u32 n, const u8 *weights, void *caller); +u32 RandomWeightedArrayDefaultValue(enum RandomTag tag, u32 n, const u8 *weights, void *caller); +const void *RandomElementArrayTrials(enum RandomTag tag, const void *array, size_t size, size_t count, void *caller); +const void *RandomElementArrayDefaultValue(enum RandomTag tag, const void *array, size_t size, size_t count, void *caller); +#endif + #endif // GUARD_RANDOM_H diff --git a/include/recorded_battle.h b/include/recorded_battle.h index 88e47f623..ab8694de7 100644 --- a/include/recorded_battle.h +++ b/include/recorded_battle.h @@ -27,7 +27,7 @@ struct RecordedBattleSave u8 frontierBrainSymbol; u8 battleScene:1; u8 textSpeed:3; - u32 AI_scripts; + u64 AI_scripts[MAX_BATTLERS_COUNT]; u8 recordMixFriendName[PLAYER_NAME_LENGTH + 1]; u8 recordMixFriendClass; u8 apprenticeId; @@ -75,7 +75,7 @@ u8 GetBattleSceneInRecordedBattle(void); u8 GetTextSpeedInRecordedBattle(void); void RecordedBattle_CopyBattlerMoves(u32 battler); void RecordedBattle_CheckMovesetChanges(u8 mode); -u32 GetAiScriptsInRecordedBattle(void); +u64 GetAiScriptsInRecordedBattle(u32 battler); void RecordedBattle_SetPlaybackFinished(void); bool8 RecordedBattle_CanStopPlayback(void); u8 GetBattlerLinkPlayerGender(u32 battler); diff --git a/include/test/battle.h b/include/test/battle.h index ad36cd4f9..d0f0458a7 100644 --- a/include/test/battle.h +++ b/include/test/battle.h @@ -194,21 +194,22 @@ * ASSUME(GetMoveEffect(MOVE_POISON_STING) == EFFECT_POISON_HIT); * } * - * SINGLE_BATTLE_TEST(name, results...) and DOUBLE_BATTLE_TEST(name, results...) - * Define single- and double- battles. The names should start with the - * name of the mechanic being tested so that it is easier to run all the - * related tests. results contains variable declarations to be placed - * into the results array which is available in PARAMETRIZEd tests. - * The main differences for doubles are: + * SINGLE_BATTLE_TEST(name, results...), DOUBLE_BATTLE_TEST(name, results...), MULTI_BATTLE_TEST(name, results...), + * TWO_VS_ONE_BATTLE_TEST(name, results...), and ONE_VS_TWO_BATTLE_TEST(name, results...) + * Define single-, double-, 2v2-multi-, 2v1-multi-, and 1v2- battles. The names should start with + * the name of the mechanic being tested so that it is easier to run all the related tests. results contains variable + * declarations to be placed into the `results` array which is available in tests using `PARAMETRIZE` commands. + * The main differences for doubles, 2v2, 2v1, and 1v2 are: * - Move targets sometimes need to be explicit. * - Instead of player and opponent there is playerLeft, playerRight, * opponentLeft, and opponentRight. * - * AI_SINGLE_BATTLE_TEST(name, results...) and AI_DOUBLE_BATTLE_TEST(name, results...) + * AI_SINGLE_BATTLE_TEST(name, results...), AI_DOUBLE_BATTLE_TEST(name, results...), + * AI_MULTI_BATTLE_TEST(name, results...), AI_TWO_VS_ONE_BATTLE_TEST(name, results...), and AI_ONE_VS_TWO_BATTLE_TEST(name, results...) * Define battles where opponent mons are controlled by AI, the same that runs * when battling regular Trainers. The flags for AI should be specified by * the AI_FLAGS command. - * The rules remain the same as with the SINGLE and DOUBLE battle tests + * The rules remain the same as with the SINGLE, DOUBLE, MULTI, TWO_VS_ONE, and ONE_VS_TWO battle tests with some differences: * with some differences: * - opponent's action is specified by the EXPECT_MOVE(s) / EXPECT_SEND_OUT / EXPECT_SWITCH commands * - we don't control what opponent actually does, instead we make sure the opponent does what we expect it to do @@ -333,10 +334,39 @@ * Note if Moves is specified then MOVE will not automatically add moves * to the moveset. * + * For tests using MULTI_BATTLE_TEST, AI_MULTI_BATTLE_TEST, TWO_VS_ONE_BATTLE_TEST, + * AI_TWO_VS_ONE_BATTLE_TEST, ONE_VS_TWO_BATTLE_TEST, and AI_ONE_VS_TWO_BATTLE_TEST, + * the below must be used instead of PLAYER(species) and OPPONENT(species). + * MULTI_PLAYER(species), MULTI_PARTNER(species), MULTI_OPPONENT_A(species), and + * MULTI_OPPONENT_B(species) Adds the species to the player's, player partner's, + * opponent A's, or opponent B's party, respectively. + * Pokemon can be customised as per the guidance for PLAYER(species) and OPPONENT(species). + * The functions assign the Pokémon to the party of the trainer at B_POSITION_PLAYER_LEFT, + * B_POSITION_PLAYER_RIGHT, B_POSITION_OPPONENT_LEFT, and B_POSITION_OPPONENT_RIGHT, respectively. + * MULTI_PLAYER(species) and MULTI_OPPONENT_A(species) set Pokémon starting at party index 0, + * while MULTI_PARTNER(species) and MULTI_OPPONENT_B(species) set Pokémon starting at party + * index 3. + * For ONE_VS_TWO tests, MULTI_PLAYER(species) must be used for all player-side Pokémon, + * and for TWO_VS_ONE tests, MULTI_OPPONENT_A(species) must be used for all opponent-side + * Pokémon. + * All MULTI_PLAYER(species) Pokémon must be set before any MULTI_PARTNER(species) Pokémon, + * and all MULTI_OPPONENT_A(species) must be set before any MULTI_OPPONENT_B(species) Pokémon, + * else Pokémon will be set in the incorrect parties in the test. + * Note where a side in a test has two trainers, the test setup manages the assigning of correct + * multi-party orders, therefore when using functions such as SEND_OUT, Player and Opponent A + * Pokémon may be referenced using indexes 0, 1, and 2, and Player's Partner and Opponent B + * Pokémon may be referenced using indexes 3, 4, and 5. + * * AI_FLAGS - * Specifies which AI flags are run during the test. Has use only for AI tests. + * Specifies which AI flags are run for all battlers during the test. Has use only for AI tests. * The most common combination is AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT) * which is the general 'smart' AI. + * + * BATTLER_AI_FLAGS + * Specifies additional AI flags to be applied to specific battlers (battler 0/1/2/3). Has use only for AI tests. + * Must be used strictly after AI_FLAGS(flags), which overwrites all existing flags. + * Example: BATTLER_AI_FLAGS(3, AI_FLAG_RISKY) used after AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT) + * will set AI_FLAG_RISKY to only battler3 (Opponent B), in addition to the flags set by AI_FLAGS. * * WHEN * Contains the choices that battlers make during the battle. @@ -537,10 +567,13 @@ #define MAX_QUEUED_EVENTS 30 #define MAX_EXPECTED_ACTIONS 10 -enum { BATTLE_TEST_SINGLES, BATTLE_TEST_DOUBLES, BATTLE_TEST_WILD, BATTLE_TEST_AI_SINGLES, BATTLE_TEST_AI_DOUBLES }; +enum { BATTLE_TEST_SINGLES, BATTLE_TEST_DOUBLES, BATTLE_TEST_WILD, BATTLE_TEST_AI_SINGLES, BATTLE_TEST_AI_DOUBLES, BATTLE_TEST_MULTI, BATTLE_TEST_AI_MULTI, BATTLE_TEST_TWO_VS_ONE, BATTLE_TEST_AI_TWO_VS_ONE, BATTLE_TEST_ONE_VS_TWO, BATTLE_TEST_AI_ONE_VS_TWO }; typedef void (*SingleBattleTestFunction)(void *, const u32, struct BattlePokemon *, struct BattlePokemon *); typedef void (*DoubleBattleTestFunction)(void *, const u32, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *); +typedef void (*MultiBattleTestFunction)(void *, const u32, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *); +typedef void (*TwoVsOneBattleTestFunction)(void *, const u32, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *); +typedef void (*OneVsTwoBattleTestFunction)(void *, const u32, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *); struct BattleTest { @@ -549,6 +582,9 @@ struct BattleTest { SingleBattleTestFunction singles; DoubleBattleTestFunction doubles; + MultiBattleTestFunction multi; + TwoVsOneBattleTestFunction two_vs_one; + OneVsTwoBattleTestFunction one_vs_two; } function; size_t resultsSize; }; @@ -622,18 +658,12 @@ struct QueuedEvent } as; }; -struct TurnRNG -{ - u16 tag; - u16 value; -}; - struct BattlerTurn { u8 hit:2; u8 criticalHit:2; u8 secondaryEffect:2; - struct TurnRNG rng; + struct RiggedRNG rng; }; struct ExpectedAIAction @@ -688,11 +718,11 @@ struct BattleTestData u8 playerPartySize; u8 opponentPartySize; - u8 explicitMoves[NUM_BATTLE_SIDES]; + u8 explicitMoves[MAX_BATTLERS_COUNT]; bool8 hasExplicitSpeeds; - u8 explicitSpeeds[NUM_BATTLE_SIDES]; + u8 explicitSpeeds[MAX_BATTLERS_COUNT]; u16 slowerThan[NUM_BATTLE_SIDES][PARTY_SIZE]; - u8 currentSide; + u8 currentPosition; u8 currentPartyIndex; struct Pokemon *currentMon; u8 gender; @@ -700,6 +730,7 @@ struct BattleTestData bool8 isShiny; enum Ability forcedAbilities[NUM_BATTLE_SIDES][PARTY_SIZE]; u8 chosenGimmick[NUM_BATTLE_SIDES][PARTY_SIZE]; + u8 forcedEnvironment; u8 currentMonIndexes[MAX_BATTLERS_COUNT]; u8 turnState; @@ -767,6 +798,8 @@ extern struct BattleTestRunnerState *const gBattleTestRunnerState; #define R_APPEND_TRUE(...) __VA_OPT__(FIRST(__VA_ARGS__), TRUE RECURSIVELY(R_FOR_EACH(APPEND_COMMA_TRUE, EXCEPT_1(__VA_ARGS__)))) #define AI_TRAINER_NAME "{PKMN} TRAINER LEAF" +#define AI_TRAINER_2_NAME "{PKMN} TRAINER RED" +#define AI_PARTNER_NAME "{PKMN} TRAINER 1" /* Test */ @@ -812,6 +845,60 @@ extern struct BattleTestRunnerState *const gBattleTestRunnerState; }; \ static void CAT(Test, __LINE__)(struct CAT(Result, __LINE__) *results, const u32 i, struct BattlePokemon *playerLeft, struct BattlePokemon *opponentLeft, struct BattlePokemon *playerRight, struct BattlePokemon *opponentRight) + #define BATTLE_TEST_ARGS_MULTI(_name, _type, ...) \ + struct CAT(Result, __LINE__) { RECURSIVELY(R_FOR_EACH(APPEND_SEMICOLON, __VA_ARGS__)) }; \ + static void CAT(Test, __LINE__)(struct CAT(Result, __LINE__) *, const u32, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *); \ + __attribute__((section(".tests"), used)) static const struct Test CAT(sTest, __LINE__) = \ + { \ + .name = _name, \ + .filename = __FILE__, \ + .runner = &gBattleTestRunner, \ + .sourceLine = __LINE__, \ + .data = (void *)&(const struct BattleTest) \ + { \ + .type = _type, \ + .function = { .multi = (MultiBattleTestFunction)CAT(Test, __LINE__) }, \ + .resultsSize = sizeof(struct CAT(Result, __LINE__)), \ + }, \ + }; \ + static void CAT(Test, __LINE__)(struct CAT(Result, __LINE__) *results, const u32 i, struct BattlePokemon *playerLeft, struct BattlePokemon *opponentLeft, struct BattlePokemon *playerRight, struct BattlePokemon *opponentRight) + +#define BATTLE_TEST_ARGS_TWO_VS_ONE(_name, _type, ...) \ + struct CAT(Result, __LINE__) { RECURSIVELY(R_FOR_EACH(APPEND_SEMICOLON, __VA_ARGS__)) }; \ + static void CAT(Test, __LINE__)(struct CAT(Result, __LINE__) *, const u32, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *); \ + __attribute__((section(".tests"), used)) static const struct Test CAT(sTest, __LINE__) = \ + { \ + .name = _name, \ + .filename = __FILE__, \ + .runner = &gBattleTestRunner, \ + .sourceLine = __LINE__, \ + .data = (void *)&(const struct BattleTest) \ + { \ + .type = _type, \ + .function = { .two_vs_one = (TwoVsOneBattleTestFunction)CAT(Test, __LINE__) }, \ + .resultsSize = sizeof(struct CAT(Result, __LINE__)), \ + }, \ + }; \ + static void CAT(Test, __LINE__)(struct CAT(Result, __LINE__) *results, const u32 i, struct BattlePokemon *playerLeft, struct BattlePokemon *opponentLeft, struct BattlePokemon *playerRight, struct BattlePokemon *opponentRight) + +#define BATTLE_TEST_ARGS_ONE_VS_TWO(_name, _type, ...) \ + struct CAT(Result, __LINE__) { RECURSIVELY(R_FOR_EACH(APPEND_SEMICOLON, __VA_ARGS__)) }; \ + static void CAT(Test, __LINE__)(struct CAT(Result, __LINE__) *, const u32, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *); \ + __attribute__((section(".tests"), used)) static const struct Test CAT(sTest, __LINE__) = \ + { \ + .name = _name, \ + .filename = __FILE__, \ + .runner = &gBattleTestRunner, \ + .sourceLine = __LINE__, \ + .data = (void *)&(const struct BattleTest) \ + { \ + .type = _type, \ + .function = { .one_vs_two = (OneVsTwoBattleTestFunction)CAT(Test, __LINE__) }, \ + .resultsSize = sizeof(struct CAT(Result, __LINE__)), \ + }, \ + }; \ + static void CAT(Test, __LINE__)(struct CAT(Result, __LINE__) *results, const u32 i, struct BattlePokemon *playerLeft, struct BattlePokemon *opponentLeft, struct BattlePokemon *playerRight, struct BattlePokemon *opponentRight) + #define SINGLE_BATTLE_TEST(_name, ...) BATTLE_TEST_ARGS_SINGLE(_name, BATTLE_TEST_SINGLES, __VA_ARGS__) #define WILD_BATTLE_TEST(_name, ...) BATTLE_TEST_ARGS_SINGLE(_name, BATTLE_TEST_WILD, __VA_ARGS__) @@ -820,6 +907,15 @@ extern struct BattleTestRunnerState *const gBattleTestRunnerState; #define DOUBLE_BATTLE_TEST(_name, ...) BATTLE_TEST_ARGS_DOUBLE(_name, BATTLE_TEST_DOUBLES, __VA_ARGS__) #define AI_DOUBLE_BATTLE_TEST(_name, ...) BATTLE_TEST_ARGS_DOUBLE(_name, BATTLE_TEST_AI_DOUBLES, __VA_ARGS__) +#define MULTI_BATTLE_TEST(_name, ...) BATTLE_TEST_ARGS_MULTI(_name, BATTLE_TEST_MULTI, __VA_ARGS__) +#define AI_MULTI_BATTLE_TEST(_name, ...) BATTLE_TEST_ARGS_MULTI(_name, BATTLE_TEST_AI_MULTI, __VA_ARGS__) + +#define TWO_VS_ONE_BATTLE_TEST(_name, ...) BATTLE_TEST_ARGS_TWO_VS_ONE(_name, BATTLE_TEST_TWO_VS_ONE, __VA_ARGS__) +#define AI_TWO_VS_ONE_BATTLE_TEST(_name, ...) BATTLE_TEST_ARGS_TWO_VS_ONE(_name, BATTLE_TEST_AI_TWO_VS_ONE, __VA_ARGS__) + +#define ONE_VS_TWO_BATTLE_TEST(_name, ...) BATTLE_TEST_ARGS_ONE_VS_TWO(_name, BATTLE_TEST_ONE_VS_TWO, __VA_ARGS__) +#define AI_ONE_VS_TWO_BATTLE_TEST(_name, ...) BATTLE_TEST_ARGS_ONE_VS_TWO(_name, BATTLE_TEST_AI_ONE_VS_TWO, __VA_ARGS__) + /* Parametrize */ #undef PARAMETRIZE // Override test/test.h's implementation. @@ -848,13 +944,18 @@ struct moveWithPP { #define RNGSeed(seed) RNGSeed_(__LINE__, seed) #define AI_FLAGS(flags) AIFlags_(__LINE__, flags) +#define BATTLER_AI_FLAGS(battler, flags) BattlerAIFlags_(__LINE__, battler, flags) #define AI_LOG AILogScores(__LINE__) #define FLAG_SET(flagId) SetFlagForTest(__LINE__, flagId) #define WITH_CONFIG(configTag, value) TestSetConfig(__LINE__, configTag, value) -#define PLAYER(species) for (OpenPokemon(__LINE__, B_SIDE_PLAYER, species); gBattleTestRunnerState->data.currentMon; ClosePokemon(__LINE__)) -#define OPPONENT(species) for (OpenPokemon(__LINE__, B_SIDE_OPPONENT, species); gBattleTestRunnerState->data.currentMon; ClosePokemon(__LINE__)) +#define PLAYER(species) for (OpenPokemon(__LINE__, B_POSITION_PLAYER_LEFT, species); gBattleTestRunnerState->data.currentMon; ClosePokemon(__LINE__)) +#define OPPONENT(species) for (OpenPokemon(__LINE__, B_POSITION_OPPONENT_LEFT, species); gBattleTestRunnerState->data.currentMon; ClosePokemon(__LINE__)) +#define MULTI_PLAYER(species) for (OpenPokemonMulti(__LINE__, B_POSITION_PLAYER_LEFT, species); gBattleTestRunnerState->data.currentMon; ClosePokemon(__LINE__)) +#define MULTI_OPPONENT_A(species) for (OpenPokemonMulti(__LINE__, B_POSITION_OPPONENT_LEFT, species); gBattleTestRunnerState->data.currentMon; ClosePokemon(__LINE__)) +#define MULTI_PARTNER(species) for (OpenPokemonMulti(__LINE__, B_POSITION_PLAYER_RIGHT, species); gBattleTestRunnerState->data.currentMon; ClosePokemon(__LINE__)) +#define MULTI_OPPONENT_B(species) for (OpenPokemonMulti(__LINE__, B_POSITION_OPPONENT_RIGHT, species); gBattleTestRunnerState->data.currentMon; ClosePokemon(__LINE__)) #define Gender(gender) Gender_(__LINE__, gender) #define Nature(nature) Nature_(__LINE__, nature) @@ -884,15 +985,18 @@ struct moveWithPP { #define TeraType(teraType) TeraType_(__LINE__, teraType) #define Shadow(isShadow) Shadow_(__LINE__, isShadow) #define Shiny(isShiny) Shiny_(__LINE__, isShiny) +#define Environment(environment) Environment_(__LINE__, environment) void SetFlagForTest(u32 sourceLine, u16 flagId); void TestSetConfig(u32 sourceLine, enum GenConfigTag configTag, u32 value); void ClearFlagAfterTest(void); -void OpenPokemon(u32 sourceLine, u32 side, u32 species); +void OpenPokemon(u32 sourceLine, enum BattlerPosition position, u32 species); +void OpenPokemonMulti(u32 sourceLine, enum BattlerPosition position, u32 species); void ClosePokemon(u32 sourceLine); void RNGSeed_(u32 sourceLine, rng_value_t seed); void AIFlags_(u32 sourceLine, u64 flags); +void BattlerAIFlags_(u32 sourceLine, u32 battler, u64 flags); void AILogScores(u32 sourceLine); void Gender_(u32 sourceLine, u32 gender); void Nature_(u32 sourceLine, u32 nature); @@ -919,9 +1023,26 @@ void Status1_(u32 sourceLine, u32 status1); void OTName_(u32 sourceLine, const u8 *otName); void DynamaxLevel_(u32 sourceLine, u32 dynamaxLevel); void GigantamaxFactor_(u32 sourceLine, bool32 gigantamaxFactor); -void TeraType_(u32 sourceLine, u32 teraType); +void TeraType_(u32 sourceLine, enum Type teraType); void Shadow_(u32 sourceLine, bool32 isShadow); void Shiny_(u32 sourceLine, bool32 isShiny); +void Environment_(u32 sourceLine, u32 environment); + +static inline bool8 IsMultibattleTest(void) +{ + if (TESTING) + { + if (((gBattleTypeFlags & BATTLE_MULTI_TEST) == BATTLE_MULTI_TEST) + || ((gBattleTypeFlags & BATTLE_TWO_VS_ONE_TEST) == BATTLE_TWO_VS_ONE_TEST)) + return TRUE; + else + return FALSE; + } + else + { + return FALSE; + } +} // Created for easy use of EXPECT_MOVES, so the user can provide 1, 2, 3 or 4 moves for AI which can pass the test. struct FourMoves @@ -972,7 +1093,7 @@ enum { TURN_CLOSED, TURN_OPEN, TURN_CLOSING }; #define SKIP_TURN(battler) SkipTurn(__LINE__, battler) #define SEND_OUT(battler, partyIndex) SendOut(__LINE__, battler, partyIndex) #define USE_ITEM(battler, ...) UseItem(__LINE__, battler, (struct ItemContext) { R_APPEND_TRUE(__VA_ARGS__) }) -#define WITH_RNG(tag, value) rng: ((struct TurnRNG) { tag, value }) +#define WITH_RNG(tag, value) rng: ((struct RiggedRNG) { tag, value }) struct MoveContext { @@ -997,7 +1118,7 @@ struct MoveContext u16 explicitNotExpected:1; struct BattlePokemon *target; bool8 explicitTarget; - struct TurnRNG rng; + struct RiggedRNG rng; bool8 explicitRNG; }; @@ -1009,7 +1130,7 @@ struct ItemContext u16 explicitPartyIndex:1; u16 move; u16 explicitMove:1; - struct TurnRNG rng; + struct RiggedRNG rng; u16 explicitRNG:1; }; diff --git a/include/test/test.h b/include/test/test.h index 48a6e84aa..15f71d50b 100644 --- a/include/test/test.h +++ b/include/test/test.h @@ -2,8 +2,10 @@ #define GUARD_TEST_H #include "test_runner.h" +#include "random.h" #define MAX_PROCESSES 32 // See also tools/mgba-rom-test-hydra/main.c +#define RIGGED_RNG_COUNT 8 enum TestResult { @@ -26,6 +28,9 @@ struct TestRunner void (*tearDown)(void *); bool32 (*checkProgress)(void *); bool32 (*handleExitWithResult)(void *, enum TestResult); + u32 (*randomUniform)(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32), void *caller); + u32 (*randomWeightedArray)(enum RandomTag tag, u32 sum, u32 n, const u8 *weights, void *caller); + const void* (*randomElementArray)(enum RandomTag tag, const void *array, size_t size, size_t count, void *caller); }; struct Test @@ -76,11 +81,18 @@ extern const char gTestRunnerArgv[256]; extern const struct TestRunner gAssumptionsRunner; +struct RiggedRNG +{ + u16 tag; + u16 value; +}; + struct FunctionTestRunnerState { u16 parameters; u16 runParameter; u16 checkProgressParameter; + struct RiggedRNG rngList[RIGGED_RNG_COUNT]; }; extern const struct TestRunner gFunctionTestRunner; @@ -97,6 +109,8 @@ void Test_ExpectCrash(bool32); void Test_ExitWithResult(enum TestResult, u32 stopLine, const char *fmt, ...); u32 SourceLine(u32 sourceLineOffset); u32 SourceLineOffset(u32 sourceLine); +void SetupRiggedRng(u32 sourceLine, enum RandomTag randomTag, u32 value); +void ClearRiggedRng(); s32 Test_MgbaPrintf(const char *fmt, ...); @@ -143,7 +157,7 @@ s32 Test_MgbaPrintf(const char *fmt, ...); { \ typeof(a) _a = (a), _b = (b); \ if (_a != _b) \ - Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_EQ(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \ + Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_EQ(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, a, b); \ } while (0) #define EXPECT_NE(a, b) \ @@ -151,7 +165,7 @@ s32 Test_MgbaPrintf(const char *fmt, ...); { \ typeof(a) _a = (a), _b = (b); \ if (_a == _b) \ - Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_NE(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \ + Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_NE(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, a, b); \ } while (0) #define EXPECT_LT(a, b) \ @@ -159,7 +173,7 @@ s32 Test_MgbaPrintf(const char *fmt, ...); { \ typeof(a) _a = (a), _b = (b); \ if (_a >= _b) \ - Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_LT(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \ + Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_LT(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, a, b); \ } while (0) #define EXPECT_LE(a, b) \ @@ -167,7 +181,7 @@ s32 Test_MgbaPrintf(const char *fmt, ...); { \ typeof(a) _a = (a), _b = (b); \ if (_a > _b) \ - Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_LE(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \ + Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_LE(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, a, b); \ } while (0) #define EXPECT_GT(a, b) \ @@ -175,7 +189,7 @@ s32 Test_MgbaPrintf(const char *fmt, ...); { \ typeof(a) _a = (a), _b = (b); \ if (_a <= _b) \ - Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_GT(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \ + Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_GT(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, a, b); \ } while (0) #define EXPECT_GE(a, b) \ @@ -183,7 +197,7 @@ s32 Test_MgbaPrintf(const char *fmt, ...); { \ typeof(a) _a = (a), _b = (b); \ if (_a < _b) \ - Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_GE(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, _a, _b); \ + Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: EXPECT_GE(%d, %d) failed", gTestRunnerState.test->filename, __LINE__, a, b); \ } while (0) struct Benchmark { s32 ticks; }; @@ -245,6 +259,8 @@ static inline struct Benchmark BenchmarkStop(void) #define PARAMETRIZE_LABEL(f, label) if (gFunctionTestRunnerState->parameters++ == gFunctionTestRunnerState->runParameter && (Test_MgbaPrintf(":N%s: " f " (%d/%d)", gTestRunnerState.test->name, label, gFunctionTestRunnerState->runParameter + 1, gFunctionTestRunnerState->parameters), 1)) +#define SET_RNG(tag, value) SetupRiggedRng(__LINE__, tag, value) + #define TO_DO \ do { \ Test_ExpectedResult(TEST_RESULT_TODO); \ diff --git a/include/test/test_runner_battle.h b/include/test/test_runner_battle.h new file mode 100644 index 000000000..8a2c0dc64 --- /dev/null +++ b/include/test/test_runner_battle.h @@ -0,0 +1,6 @@ +#ifndef GUARD_BATTLE_TEST_RUNNER_H +#define GUARD_BATTLE_TEST_RUNNER_H + +bool8 IsMultibattleTest(void); + +#endif diff --git a/include/test_runner.h b/include/test_runner.h index a3b0826e8..493cfabc4 100644 --- a/include/test_runner.h +++ b/include/test_runner.h @@ -28,6 +28,7 @@ void TestRunner_Battle_CheckBattleRecordActionType(u32 battlerId, u32 recordInde u32 TestRunner_Battle_GetForcedAbility(u32 side, u32 partyIndex); u32 TestRunner_Battle_GetChosenGimmick(u32 side, u32 partyIndex); +u32 TestRunner_Battle_GetForcedEnvironment(void); #else @@ -51,6 +52,8 @@ u32 TestRunner_Battle_GetChosenGimmick(u32 side, u32 partyIndex); #define TestRunner_Battle_GetChosenGimmick(...) (u32)0 +#define TestRunner_Battle_GetForcedEnvironment(...) (u8)0 + #endif #endif diff --git a/include/wild_encounter.h b/include/wild_encounter.h index fc81a9714..7f1c49e55 100644 --- a/include/wild_encounter.h +++ b/include/wild_encounter.h @@ -74,7 +74,6 @@ void SeedWildEncounterRng(u16 randVal); void ResetEncounterRateModifiers(void); bool8 TryStandardWildEncounter(u32 currMetatileAttrs); bool8 TryDoDoubleWildBattle(void); -u32 CalculateChainFishingShinyRolls(void); void CreateWildMon(u16 species, u8 level, u8 unownSlot); u16 GetCurrentMapWildMonHeaderId(void); u8 ChooseWildMonIndex_Land(void); diff --git a/src/battle_ai_field_statuses.c b/src/battle_ai_field_statuses.c index 4579b5d9a..80efa6b4d 100644 --- a/src/battle_ai_field_statuses.c +++ b/src/battle_ai_field_statuses.c @@ -20,7 +20,6 @@ #include "constants/abilities.h" #include "constants/battle_ai.h" #include "constants/battle_move_effects.h" -#include "constants/hold_effects.h" #include "constants/moves.h" #include "constants/items.h" @@ -399,7 +398,7 @@ static enum FieldEffectOutcome BenefitsFromPsychicTerrain(u32 battler) if (DoesAbilityBenefitFromFieldStatus(gAiLogicData->abilities[battler], STATUS_FIELD_PSYCHIC_TERRAIN)) return FIELD_EFFECT_POSITIVE; - if (HasMoveWithEffect(battler, EFFECT_EXPANDING_FORCE)) + if (HasBattlerSideMoveWithEffect(battler, EFFECT_EXPANDING_FORCE)) return FIELD_EFFECT_POSITIVE; bool32 grounded = AI_IsBattlerGrounded(battler); @@ -411,9 +410,9 @@ static enum FieldEffectOutcome BenefitsFromPsychicTerrain(u32 battler) if (grounded || allyGrounded) { // harass priority - if (HasBattlerSideAbility(LEFT_FOE(battler), ABILITY_GALE_WINGS, gAiLogicData) - || HasBattlerSideAbility(LEFT_FOE(battler), ABILITY_TRIAGE, gAiLogicData) - || HasBattlerSideAbility(LEFT_FOE(battler), ABILITY_PRANKSTER, gAiLogicData)) + if (AI_IsAbilityOnSide(LEFT_FOE(battler), ABILITY_GALE_WINGS) + || AI_IsAbilityOnSide(LEFT_FOE(battler), ABILITY_TRIAGE) + || AI_IsAbilityOnSide(LEFT_FOE(battler), ABILITY_PRANKSTER)) return FIELD_EFFECT_POSITIVE; } @@ -423,9 +422,9 @@ static enum FieldEffectOutcome BenefitsFromPsychicTerrain(u32 battler) if (HasBattlerSideMoveWithEffect(LEFT_FOE(battler), EFFECT_EXPANDING_FORCE)) return FIELD_EFFECT_NEGATIVE; - if (HasBattlerSideAbility(battler, ABILITY_GALE_WINGS, gAiLogicData) - || HasBattlerSideAbility(battler, ABILITY_TRIAGE, gAiLogicData) - || HasBattlerSideAbility(battler, ABILITY_PRANKSTER, gAiLogicData)) + if (AI_IsAbilityOnSide(battler, ABILITY_GALE_WINGS) + || AI_IsAbilityOnSide(battler, ABILITY_TRIAGE) + || AI_IsAbilityOnSide(battler, ABILITY_PRANKSTER)) return FIELD_EFFECT_NEGATIVE; return FIELD_EFFECT_NEUTRAL; @@ -436,7 +435,7 @@ static enum FieldEffectOutcome BenefitsFromGravity(u32 battler) if (!AI_IsBattlerGrounded(battler)) return FIELD_EFFECT_NEGATIVE; - if (HasBattlerSideAbility(battler, ABILITY_HUSTLE, gAiLogicData)) + if (AI_IsAbilityOnSide(battler, ABILITY_HUSTLE)) return FIELD_EFFECT_POSITIVE; if (HasMoveWithFlag(battler, IsMoveGravityBanned)) diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 33f4cdcc5..13ae0ad00 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -23,7 +23,6 @@ #include "constants/abilities.h" #include "constants/battle_ai.h" #include "constants/battle_move_effects.h" -#include "constants/hold_effects.h" #include "constants/moves.h" #include "constants/items.h" #include "constants/trainers.h" @@ -38,7 +37,7 @@ static u32 ChooseMoveOrAction_Singles(u32 battler); static u32 ChooseMoveOrAction_Doubles(u32 battler); static inline void BattleAI_DoAIProcessing(struct AiThinkingStruct *aiThink, u32 battlerAtk, u32 battlerDef); static inline void BattleAI_DoAIProcessing_PredictedSwitchin(struct AiThinkingStruct *aiThink, struct AiLogicData *aiData, u32 battlerAtk, u32 battlerDef); -static bool32 IsPinchBerryItemEffect(enum ItemHoldEffect holdEffect); +static bool32 IsPinchBerryItemEffect(enum HoldEffect holdEffect); static void AI_CompareDamagingMoves(u32 battlerAtk, u32 battlerDef); // ewram @@ -183,7 +182,7 @@ static u64 GetWildAiFlags(void) return flags; } -static u64 GetAiFlags(u16 trainerId) +static u64 GetAiFlags(u16 trainerId, u32 battler) { u64 flags = 0; @@ -196,7 +195,7 @@ static u64 GetAiFlags(u16 trainerId) else { if (gBattleTypeFlags & BATTLE_TYPE_RECORDED) - flags = GetAiScriptsInRecordedBattle(); + flags = GetAiScriptsInRecordedBattle(battler); else if (gBattleTypeFlags & BATTLE_TYPE_SAFARI) flags = AI_FLAG_SAFARI; else if (gBattleTypeFlags & BATTLE_TYPE_ROAMER) @@ -235,7 +234,7 @@ static u64 GetAiFlags(u16 trainerId) void BattleAI_SetupFlags(void) { if (IsAiVsAiBattle()) - gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_LEFT] = GetAiFlags(gPartnerTrainerId); + gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_LEFT] = GetAiFlags(gPartnerTrainerId, B_POSITION_PLAYER_LEFT); else gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_LEFT] = 0; // player has no AI @@ -249,8 +248,8 @@ void BattleAI_SetupFlags(void) if (IsWildMonSmart() && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_TRAINER))) { // smart wild AI - gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT] = GetAiFlags(0xFFFF); - gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] = GetAiFlags(0xFFFF); + gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT] = GetAiFlags(0xFFFF, B_POSITION_OPPONENT_LEFT); + gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] = GetAiFlags(0xFFFF, B_POSITION_OPPONENT_RIGHT); // The check is here because wild natural enemies are not symmetrical. if (B_WILD_NATURAL_ENEMIES && IsDoubleBattle()) @@ -262,20 +261,19 @@ void BattleAI_SetupFlags(void) if (IsNaturalEnemy(speciesRight, speciesLeft)) gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] |= AI_FLAG_ATTACKS_PARTNER; } - } else { - gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT] = GetAiFlags(TRAINER_BATTLE_PARAM.opponentA); - if (TRAINER_BATTLE_PARAM.opponentB != 0 && TRAINER_BATTLE_PARAM.opponentB != 0xFFFF) - gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] = GetAiFlags(TRAINER_BATTLE_PARAM.opponentB); + gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT] = GetAiFlags(TRAINER_BATTLE_PARAM.opponentA, B_POSITION_OPPONENT_LEFT); + if ((TRAINER_BATTLE_PARAM.opponentB != 0) && (TRAINER_BATTLE_PARAM.opponentB != 0xFFFF)) + gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] = GetAiFlags(TRAINER_BATTLE_PARAM.opponentB, B_POSITION_OPPONENT_RIGHT); else gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] = gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT]; } if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) { - gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_RIGHT] = GetAiFlags(gPartnerTrainerId); + gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_RIGHT] = GetAiFlags(gPartnerTrainerId, B_POSITION_PLAYER_RIGHT); } else if (IsDoubleBattle() && IsAiVsAiBattle()) { @@ -283,7 +281,8 @@ void BattleAI_SetupFlags(void) } else // Assign ai flags for player for prediction { - u64 aiFlags = GetAiFlags(TRAINER_BATTLE_PARAM.opponentA) | GetAiFlags(TRAINER_BATTLE_PARAM.opponentB); + u64 aiFlags = GetAiFlags(TRAINER_BATTLE_PARAM.opponentA, B_POSITION_OPPONENT_LEFT) + | GetAiFlags(TRAINER_BATTLE_PARAM.opponentB, B_POSITION_OPPONENT_RIGHT); gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_RIGHT] = aiFlags; gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_LEFT] = aiFlags; } @@ -319,7 +318,7 @@ void BattleAI_SetupAIData(u8 defaultScoreMoves, u32 battler) gAiBattleData->chosenTarget[battler] = gBattlerTarget; } -bool32 BattlerChoseNonMoveAction(void) +bool32 BattlerChooseNonMoveAction(void) { if (gAiThinkingStruct->aiAction & AI_ACTION_FLEE) { @@ -361,10 +360,6 @@ void ComputeBattlerDecisions(u32 battler) bool32 isAiBattler = (gBattleTypeFlags & BATTLE_TYPE_HAS_AI || IsWildMonSmart()) && (BattlerHasAi(battler) && !(gBattleTypeFlags & BATTLE_TYPE_PALACE)); if (isAiBattler || CanAiPredictMove()) { - // If ai is about to flee or chosen to watch player, no need to calc anything - if (isAiBattler && BattlerChoseNonMoveAction()) - return; - // Risky AI switches aggressively even mid battle enum SwitchType switchType = (gAiThinkingStruct->aiFlags[battler] & AI_FLAG_RISKY) ? SWITCH_AFTER_KO : SWITCH_MID_BATTLE; @@ -385,6 +380,8 @@ void ComputeBattlerDecisions(u32 battler) // AI's move scoring gAiBattleData->chosenMoveIndex[battler] = BattleAI_ChooseMoveIndex(battler); // Calculate score and chose move index + if (isAiBattler) + BattlerChooseNonMoveAction(); ModifySwitchAfterMoveScoring(battler); gAiLogicData->aiCalcInProgress = FALSE; @@ -558,10 +555,10 @@ void SetBattlerAiData(u32 battler, struct AiLogicData *aiData) aiData->items[battler] = gBattleMons[battler].item; holdEffect = aiData->holdEffects[battler] = AI_DecideHoldEffectForTurn(battler); aiData->holdEffectParams[battler] = GetBattlerHoldEffectParam(battler); - aiData->lastUsedMove[battler] = gLastMoves[battler]; + aiData->lastUsedMove[battler] = (gLastMoves[battler] == MOVE_UNAVAILABLE) ? MOVE_NONE : gLastMoves[battler]; aiData->hpPercents[battler] = GetHealthPercentage(battler); aiData->moveLimitations[battler] = CheckMoveLimitations(battler, 0, MOVE_LIMITATIONS_ALL); - aiData->speedStats[battler] = GetBattlerTotalSpeedStatArgs(battler, ability, holdEffect); + aiData->speedStats[battler] = GetBattlerTotalSpeedStat(battler, ability, holdEffect); if (IsAiBattlerAssumingStab()) RecordMovesBasedOnStab(battler); @@ -717,7 +714,7 @@ static u32 PpStallReduction(u32 move, u32 battlerAtk) u32 species = GetMonData(&gPlayerParty[partyIndex], MON_DATA_SPECIES); enum Ability abilityAtk = ABILITY_NONE; enum Ability abilityDef = GetPartyMonAbility(&gPlayerParty[partyIndex]); - u32 moveType = GetBattleMoveType(move); // Probably doesn't handle dynamic types right now + enum Type moveType = GetBattleMoveType(move); // Probably doesn't handle dynamic types right now if (CanAbilityAbsorbMove(battlerAtk, tempBattleMonIndex, abilityDef, move, moveType, CHECK_TRIGGER) || CanAbilityBlockMove(battlerAtk, tempBattleMonIndex, abilityAtk, abilityDef, move, CHECK_TRIGGER) || (CalcPartyMonTypeEffectivenessMultiplier(move, species, abilityDef) == 0)) @@ -1075,7 +1072,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) // move data enum BattleMoveEffects moveEffect = GetMoveEffect(move); u32 nonVolatileStatus = GetMoveNonVolatileStatus(move); - s32 moveType; + enum Type moveType; u32 moveTarget = GetBattlerMoveTargetType(battlerAtk, move); struct AiLogicData *aiData = gAiLogicData; uq4_12_t effectiveness = aiData->effectiveness[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex]; @@ -1093,7 +1090,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) SetTypeBeforeUsingMove(move, battlerAtk); moveType = GetBattleMoveType(move); - if (IsPowderMove(move) && !IsAffectedByPowder(battlerDef, aiData->abilities[battlerDef], aiData->holdEffects[battlerDef])) + if (IsPowderMove(move) && !IsAffectedByPowderMove(battlerDef, aiData->abilities[battlerDef], aiData->holdEffects[battlerDef])) RETURN_SCORE_MINUS(10); if (!BreaksThroughSemiInvulnerablity(battlerDef, move) && moveEffect != EFFECT_SEMI_INVULNERABLE && AI_IsFaster(battlerAtk, battlerDef, move, predictedMoveSpeedCheck, CONSIDER_PRIORITY)) @@ -1294,7 +1291,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) // the following checks apply to any target (including user) // throat chop check - if (gDisableStructs[battlerAtk].throatChopTimer > gBattleTurnCounter && IsSoundMove(move)) + if (gDisableStructs[battlerAtk].throatChopTimer > 0 && IsSoundMove(move)) return 0; // Can't even select move at all // heal block check if (gBattleMons[battlerAtk].volatiles.healBlock && IsHealBlockPreventingMove(battlerAtk, move)) @@ -1458,7 +1455,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) break; case EFFECT_QUIVER_DANCE: case EFFECT_GEOMANCY: - if (HasBattlerSideAbility(battlerDef, ABILITY_UNAWARE, aiData)) + if (AI_IsAbilityOnSide(battlerDef, ABILITY_UNAWARE)) ADJUST_SCORE(-10); if (gBattleMons[battlerAtk].statStages[STAT_SPATK] >= MAX_STAT_STAGE || !HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_SPECIAL)) ADJUST_SCORE(-10); @@ -1793,7 +1790,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) { if (AI_IsFaster(battlerAtk, battlerDef, move, predictedMoveSpeedCheck, CONSIDER_PRIORITY)) // Attacker should go first { - if (gLastMoves[battlerDef] == MOVE_NONE || gLastMoves[battlerDef] == 0xFFFF) + if (aiData->lastUsedMove[battlerDef] == MOVE_NONE) ADJUST_SCORE(-10); // no anticipated move to disable } else if (predictedMove == MOVE_NONE) @@ -1815,7 +1812,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) { if (AI_IsFaster(battlerAtk, battlerDef, move, predictedMoveSpeedCheck, CONSIDER_PRIORITY)) // Attacker should go first { - if (gLastMoves[battlerDef] == MOVE_NONE || gLastMoves[battlerDef] == 0xFFFF) + if (aiData->lastUsedMove[battlerDef] == MOVE_NONE) ADJUST_SCORE(-10); // no anticipated move to encore } else if (predictedMove == MOVE_NONE) @@ -1990,7 +1987,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) break; case EFFECT_BELLY_DRUM: case EFFECT_FILLET_AWAY: - if (HasBattlerSideAbility(battlerDef, ABILITY_UNAWARE, aiData)) + if (AI_IsAbilityOnSide(battlerDef, ABILITY_UNAWARE)) ADJUST_SCORE(-10); if (aiData->abilities[battlerAtk] == ABILITY_CONTRARY) ADJUST_SCORE(-10); @@ -1998,8 +1995,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-10); break; case EFFECT_FUTURE_SIGHT: - if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_FUTUREATTACK - || gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_FUTUREATTACK) + if (gWishFutureKnock.futureSightCounter[LEFT_FOE(battlerAtk)] > 0 + || gWishFutureKnock.futureSightCounter[RIGHT_FOE(battlerAtk)] > 0) ADJUST_SCORE(-12); else ADJUST_SCORE(GOOD_EFFECT); @@ -2071,7 +2068,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-10); break; case EFFECT_RECYCLE: - if (GetUsedHeldItem(battlerAtk) == 0 || gBattleMons[battlerAtk].item != 0) + if (GetBattlerPartyState(battlerAtk)->usedHeldItem == 0 || gBattleMons[battlerAtk].item != 0) ADJUST_SCORE(-10); break; case EFFECT_IMPRISON: @@ -2196,10 +2193,13 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-10); else if (battlerDef == BATTLE_PARTNER(battlerAtk)) break; //Always heal your ally - else if (AI_BattlerAtMaxHp(battlerAtk)) - ADJUST_SCORE(-10); - else if (aiData->hpPercents[battlerAtk] >= 90) - ADJUST_SCORE(-8); //No point in healing, but should at least do it if nothing better + else if (!ShouldCureStatus(battlerAtk, battlerDef, aiData)) + { + if (AI_BattlerAtMaxHp(battlerAtk)) + ADJUST_SCORE(-10); + else if (aiData->hpPercents[battlerAtk] >= 90) + ADJUST_SCORE(-8); //No point in healing, but should at least do it if nothing better + } break; case EFFECT_RECOIL_IF_MISS: if (aiData->abilities[battlerAtk] != ABILITY_MAGIC_GUARD && gAiLogicData->moveAccuracy[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex] < 75 @@ -2216,13 +2216,12 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) case EFFECT_MIMIC: if (AI_IsFaster(battlerAtk, battlerDef, move, predictedMoveSpeedCheck, CONSIDER_PRIORITY)) // Attacker should go first { - if (gLastMoves[battlerDef] == MOVE_NONE - || gLastMoves[battlerDef] == 0xFFFF) + if (aiData->lastUsedMove[battlerDef] == MOVE_NONE) ADJUST_SCORE(-10); } else if (predictedMove == MOVE_NONE) { - // TODO predicted move separate from gLastMoves + // TODO predicted move separate from aiData->lastUsedMove ADJUST_SCORE(-10); } break; @@ -2246,13 +2245,13 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-8); break; case EFFECT_SKETCH: - if (gLastMoves[battlerDef] == MOVE_NONE) + if (aiData->lastUsedMove[battlerDef] == MOVE_NONE) ADJUST_SCORE(-10); break; case EFFECT_DESTINY_BOND: if (DoesDestinyBondFail(battlerAtk)) ADJUST_SCORE(-10); - if (gBattleMons[battlerDef].volatiles.destinyBond) + if (gBattleMons[battlerAtk].volatiles.destinyBond) ADJUST_SCORE(-10); else if (GetActiveGimmick(battlerDef) == GIMMICK_DYNAMAX) ADJUST_SCORE(-10); @@ -2279,7 +2278,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) } break; case PROTECT_WIDE_GUARD: - if(!(GetBattlerMoveTargetType(battlerAtk, predictedMove) & (MOVE_TARGET_FOES_AND_ALLY | MOVE_TARGET_BOTH))) + if (!(GetBattlerMoveTargetType(battlerAtk, predictedMove) & (MOVE_TARGET_FOES_AND_ALLY | MOVE_TARGET_BOTH))) { ADJUST_SCORE(-10); decreased = TRUE; @@ -2452,7 +2451,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-10); break; case EFFECT_WISH: - if (gWishFutureKnock.wishCounter[battlerAtk] > gBattleTurnCounter) + if (gWishFutureKnock.wishCounter[battlerAtk] > 0) ADJUST_SCORE(-10); break; case EFFECT_ASSIST: @@ -2475,10 +2474,9 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) case EFFECT_ENTRAINMENT: case EFFECT_GASTRO_ACID: case EFFECT_ROLE_PLAY: - case EFFECT_SIMPLE_BEAM: case EFFECT_SKILL_SWAP: - case EFFECT_WORRY_SEED: - if (!CanEffectChangeAbility(battlerAtk, battlerDef, moveEffect, aiData) + case EFFECT_OVERWRITE_ABILITY: + if (!CanEffectChangeAbility(battlerAtk, battlerDef, move, aiData) || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) ADJUST_AND_RETURN_SCORE(NO_DAMAGE_OR_FAILS); break; @@ -2623,7 +2621,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) { // This only happens if the ally already rolled on double trick room on final turn. // Both Pokemon use Trick Room on the final turn of Trick Room to anticipate both opponents Protecting to stall out. - if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer == (gBattleTurnCounter + 1)) + if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer == 1) ADJUST_SCORE(PERFECT_EFFECT); else ADJUST_SCORE(-10); @@ -2634,7 +2632,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) if (!(gFieldStatuses & STATUS_FIELD_TRICK_ROOM) && !ShouldSetFieldStatus(battlerAtk, STATUS_FIELD_TRICK_ROOM)) ADJUST_SCORE(-10); // Don't unset a trick room that doesn't harm you unless it's about to expire. - else if ((gFieldStatuses & STATUS_FIELD_TRICK_ROOM) && gFieldTimers.trickRoomTimer != (gBattleTurnCounter + 1) && !ShouldClearFieldStatus(battlerAtk, STATUS_FIELD_TRICK_ROOM)) + else if ((gFieldStatuses & STATUS_FIELD_TRICK_ROOM) && gFieldTimers.trickRoomTimer > 1 && !ShouldClearFieldStatus(battlerAtk, STATUS_FIELD_TRICK_ROOM)) ADJUST_SCORE(-10); } break; @@ -2710,7 +2708,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) break; case EFFECT_SOAK: { - u32 types[3]; + enum Type types[3]; u32 typeArg = GetMoveArgType(move); GetBattlerTypes(battlerDef, FALSE, types); @@ -2779,13 +2777,13 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) if (AI_IsSlower(battlerAtk, battlerDef, move, predictedMoveSpeedCheck, CONSIDER_PRIORITY)) instructedMove = predictedMove; else - instructedMove = gLastMoves[battlerDef]; + instructedMove = aiData->lastUsedMove[battlerDef]; if (instructedMove == MOVE_NONE || IsMoveInstructBanned(instructedMove) || MoveHasAdditionalEffectSelf(instructedMove, MOVE_EFFECT_RECHARGE) || IsZMove(instructedMove) - || (gLockedMoves[battlerDef] != 0 && gLockedMoves[battlerDef] != 0xFFFF) + || (gLockedMoves[battlerDef] != MOVE_NONE && gLockedMoves[battlerDef] != MOVE_UNAVAILABLE) || gBattleMons[battlerDef].volatiles.multipleTurns || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) { @@ -2833,7 +2831,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) case EFFECT_TAILWIND: if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_TAILWIND || PartnerMoveEffectIs(BATTLE_PARTNER(battlerAtk), aiData->partnerMove, EFFECT_TAILWIND) - || (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer != (gBattleTurnCounter + 1))) + || (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer == 1)) ADJUST_SCORE(-10); break; case EFFECT_LUCKY_CHANT: @@ -2843,7 +2841,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) break; case EFFECT_MAGNET_RISE: if (gFieldStatuses & STATUS_FIELD_GRAVITY - || gDisableStructs[battlerAtk].magnetRiseTimer > gBattleTurnCounter + || gDisableStructs[battlerAtk].magnetRiseTimer > 0 || aiData->holdEffects[battlerAtk] == HOLD_EFFECT_IRON_BALL || gBattleMons[battlerAtk].volatiles.smackDown || gBattleMons[battlerAtk].volatiles.root @@ -3004,6 +3002,19 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) return score; } +static s32 AI_GetWhichBattlerFasterOrTies(u32 battlerAtk, u32 battlerDef, bool32 ignoreChosenMoves) +{ + struct BattleContext ctx = {0}; + ctx.battlerAtk = battlerAtk; + ctx.battlerDef = battlerDef; + ctx.abilities[battlerAtk] = gAiLogicData->abilities[battlerAtk]; + ctx.abilities[battlerDef] = gAiLogicData->abilities[battlerDef]; + ctx.holdEffects[battlerAtk] = gAiLogicData->holdEffects[battlerAtk]; + ctx.holdEffects[battlerDef] = gAiLogicData->holdEffects[battlerDef]; + + return GetWhichBattlerFasterOrTies(&ctx, ignoreChosenMoves); +} + static s32 AI_TryToFaint(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) { u32 movesetIndex = gAiThinkingStruct->movesetIndex; @@ -3025,7 +3036,7 @@ static s32 AI_TryToFaint(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(SLOW_KILL); } else if (CanTargetFaintAi(battlerDef, battlerAtk) - && GetWhichBattlerFasterOrTies(battlerAtk, battlerDef, TRUE) != AI_IS_FASTER + && AI_GetWhichBattlerFasterOrTies(battlerAtk, battlerDef, TRUE) != AI_IS_FASTER && GetBattleMovePriority(battlerAtk, gAiLogicData->abilities[battlerAtk], move) > 0) { if (RandomPercentage(RNG_AI_PRIORITIZE_LAST_CHANCE, PRIORITIZE_LAST_CHANCE_CHANCE)) @@ -3041,7 +3052,7 @@ static s32 AI_TryToFaint(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) { // move data - u32 moveType = GetMoveType(move); + enum Type moveType = GetMoveType(move); enum BattleMoveEffects effect = GetMoveEffect(move); u32 moveTarget = GetBattlerMoveTargetType(battlerAtk, move); // ally data @@ -3212,7 +3223,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) // Both Pokemon use Trick Room on the final turn of Trick Room to anticipate both opponents Protecting to stall out. // This unsets Trick Room and resets it with a full timer. case EFFECT_TRICK_ROOM: - if (hasPartner && gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer == (gBattleTurnCounter + 1) + if (hasPartner && gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer == 1 && ShouldSetFieldStatus(battlerAtk, STATUS_FIELD_TRICK_ROOM) && HasMoveWithEffect(battlerAtkPartner, EFFECT_TRICK_ROOM) && RandomPercentage(RNG_AI_REFRESH_TRICK_ROOM_ON_LAST_TURN, DOUBLE_TRICK_ROOM_ON_LAST_TURN_CHANCE)) @@ -3220,7 +3231,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) break; case EFFECT_TAILWIND: // Anticipate both opponents protecting to stall out Trick Room, and apply Tailwind. - if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer == (gBattleTurnCounter + 1) + if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer == 1 && RandomPercentage(RNG_AI_APPLY_TAILWIND_ON_LAST_TURN_OF_TRICK_ROOM, TAILWIND_IN_TRICK_ROOM_CHANCE)) ADJUST_SCORE(BEST_EFFECT); break; @@ -3589,10 +3600,9 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) case EFFECT_ENTRAINMENT: case EFFECT_GASTRO_ACID: case EFFECT_ROLE_PLAY: - case EFFECT_SIMPLE_BEAM: case EFFECT_SKILL_SWAP: - case EFFECT_WORRY_SEED: - AbilityChangeScore(battlerAtk, battlerAtkPartner, effect, &score, aiData); + case EFFECT_OVERWRITE_ABILITY: + AbilityChangeScore(battlerAtk, battlerAtkPartner, move, &score, aiData); return score; case EFFECT_SPICY_EXTRACT: if (AI_ShouldSpicyExtract(battlerAtk, battlerAtkPartner, move, aiData)) @@ -3604,8 +3614,18 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) if (gBattleMons[battlerAtkPartner].status1 & STATUS1_ANY) { if (gBattleMons[battlerAtkPartner].status1 & STATUS1_CAN_MOVE) + { + if (ShouldCureStatus(battlerAtk, battlerAtkPartner, aiData)) + ADJUST_SCORE(DECENT_EFFECT); + } + else + { + ADJUST_SCORE(DECENT_EFFECT); + } + + if ((!IsBattlerAlive(LEFT_FOE(battlerAtk)) || ShouldRecover(battlerAtk, LEFT_FOE(battlerAtk), move, 50)) + && (!IsBattlerAlive(RIGHT_FOE(battlerAtk)) || ShouldRecover(battlerAtk, RIGHT_FOE(battlerAtk), move, 50))) RETURN_SCORE_PLUS(WEAK_EFFECT); - RETURN_SCORE_PLUS(GOOD_EFFECT); } break; case EFFECT_SWAGGER: @@ -3658,7 +3678,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) if (AI_IsFaster(battlerAtk, battlerAtkPartner, move, predictedMoveSpeedCheck, CONSIDER_PRIORITY)) instructedMove = aiData->partnerMove; else - instructedMove = gLastMoves[battlerAtkPartner]; + instructedMove = aiData->lastUsedMove[battlerAtkPartner]; if (instructedMove != MOVE_NONE && !IsBattleMoveStatus(instructedMove) @@ -3770,7 +3790,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) return score; } -static bool32 IsPinchBerryItemEffect(enum ItemHoldEffect holdEffect) +static bool32 IsPinchBerryItemEffect(enum HoldEffect holdEffect) { switch (holdEffect) { @@ -4003,7 +4023,7 @@ static void AI_CompareDamagingMoves(u32 battlerAtk, u32 battlerDef) static s32 AI_CalcHoldEffectMoveScore(u32 battlerAtk, u32 battlerDef, u32 move, struct AiLogicData *aiData) { - enum ItemHoldEffect holdEffect = aiData->holdEffects[battlerAtk]; + enum HoldEffect holdEffect = aiData->holdEffects[battlerAtk]; s32 score = 0; @@ -4040,7 +4060,7 @@ static s32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move, stru s32 score = 0; u32 predictedMove = GetIncomingMove(battlerAtk, battlerDef, aiData); u32 predictedMoveSpeedCheck = GetIncomingMoveSpeedCheck(battlerAtk, battlerDef, aiData); - u32 predictedType = GetMoveType(predictedMove); + enum Type predictedType = GetMoveType(predictedMove); u32 predictedMoveSlot = GetMoveSlot(GetMovesArray(battlerDef), predictedMove); bool32 isBattle1v1 = IsBattle1v1(); bool32 hasTwoOpponents = HasTwoOpponents(battlerAtk); @@ -4056,6 +4076,19 @@ static s32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move, stru if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_PREFER_STATUS_MOVES && IsBattleMoveStatus(move) && effectiveness != UQ_4_12(0.0)) ADJUST_SCORE(10); + // don't get baited into encore + if (gBattleMoveEffects[moveEffect].encourageEncore + && HasBattlerSideMoveWithEffect(battlerDef, EFFECT_ENCORE) + && (B_MENTAL_HERB < GEN_5 || aiData->holdEffects[battlerAtk] != HOLD_EFFECT_MENTAL_HERB)) + { + if (!AI_IsAbilityOnSide(battlerAtk, ABILITY_AROMA_VEIL) + || IsMoldBreakerTypeAbility(battlerDef, aiData->abilities[battlerDef]) + || aiData->abilities[battlerDef] == ABILITY_MYCELIUM_MIGHT + || IsMoldBreakerTypeAbility(BATTLE_PARTNER(battlerDef), aiData->abilities[BATTLE_PARTNER(battlerDef)]) + || aiData->abilities[BATTLE_PARTNER(battlerDef)] == ABILITY_MYCELIUM_MIGHT) + return score; + } + // check thawing moves if (gBattleMons[battlerAtk].status1 & STATUS1_ICY_ANY && MoveThawsUser(move)) ADJUST_SCORE(10); @@ -4436,9 +4469,9 @@ static s32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move, stru case EFFECT_MIMIC: if (AI_IsFaster(battlerAtk, battlerDef, move, predictedMoveSpeedCheck, CONSIDER_PRIORITY)) { - if (gLastMoves[battlerDef] != MOVE_NONE && gLastMoves[battlerDef] != 0xFFFF - && (GetMoveEffect(gLastMoves[battlerDef]) != GetMoveEffect(move))) - return AI_CheckViability(battlerAtk, battlerDef, gLastMoves[battlerDef], score); + if (aiData->lastUsedMove[battlerDef] != MOVE_NONE + && (GetMoveEffect(aiData->lastUsedMove[battlerDef]) != GetMoveEffect(move))) + return AI_CheckViability(battlerAtk, battlerDef, aiData->lastUsedMove[battlerDef], score); } break; case EFFECT_LEECH_SEED: @@ -4505,12 +4538,11 @@ static s32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move, stru if (GetActiveGimmick(battlerDef) == GIMMICK_DYNAMAX) break; else if (gDisableStructs[battlerDef].disableTimer == 0 - && (gLastMoves[battlerDef] != MOVE_NONE) - && (gLastMoves[battlerDef] != 0xFFFF) + && (aiData->lastUsedMove[battlerDef] != MOVE_NONE) && (B_MENTAL_HERB < GEN_5 || aiData->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB) && (AI_IsFaster(battlerAtk, battlerDef, move, predictedMoveSpeedCheck, CONSIDER_PRIORITY))) { - if (CanTargetMoveFaintAi(gLastMoves[battlerDef], battlerDef, battlerAtk, 1)) + if (CanTargetMoveFaintAi(aiData->lastUsedMove[battlerDef], battlerDef, battlerAtk, 1)) ADJUST_SCORE(GOOD_EFFECT); // Disable move that can kill attacker } break; @@ -4519,9 +4551,9 @@ static s32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move, stru if (GetActiveGimmick(battlerDef) == GIMMICK_DYNAMAX) break; - bool32 encourage = gBattleMoveEffects[GetMoveEffect(gLastMoves[battlerDef])].encourageEncore; + bool32 encourage = gBattleMoveEffects[GetMoveEffect(aiData->lastUsedMove[battlerDef])].encourageEncore; - switch(GetMoveNonVolatileStatus(gLastMoves[battlerDef])) + switch(GetMoveNonVolatileStatus(aiData->lastUsedMove[battlerDef])) { case MOVE_EFFECT_POISON: case MOVE_EFFECT_PARALYSIS: @@ -4559,6 +4591,15 @@ static s32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move, stru if (ShouldUseWishAromatherapy(battlerAtk, battlerDef, move)) ADJUST_SCORE(DECENT_EFFECT); break; + case EFFECT_PURIFY: + if (gBattleMons[battlerDef].status1 & STATUS1_ANY) + { + if (ShouldCureStatus(battlerAtk, battlerDef, aiData)) + ADJUST_SCORE(GOOD_EFFECT); + if (ShouldRecover(battlerAtk, battlerDef, move, 50)) + RETURN_SCORE_PLUS(WEAK_EFFECT); + } + break; case EFFECT_CURSE: if (IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GHOST)) { @@ -4574,7 +4615,7 @@ static s32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move, stru } break; case EFFECT_PROTECT: - if (predictedMove == 0xFFFF) + if (predictedMove == MOVE_UNAVAILABLE) predictedMove = MOVE_NONE; enum ProtectMethod protectMethod = GetMoveProtectMethod(move); switch (protectMethod) @@ -4874,10 +4915,10 @@ static s32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move, stru if (hasPartner && GetMoveTarget(move) == MOVE_TARGET_USER && !IsBattlerIncapacitated(battlerDef, aiData->abilities[battlerDef]) - && (!IsPowderMove(move) || IsAffectedByPowder(battlerDef, aiData->abilities[battlerDef], aiData->holdEffects[battlerDef]))) + && (!IsPowderMove(move) || IsAffectedByPowderMove(battlerDef, aiData->abilities[battlerDef], aiData->holdEffects[battlerDef]))) // Rage Powder doesn't affect powder immunities { - u32 predictedMoveOnPartner = gLastMoves[BATTLE_PARTNER(battlerAtk)]; + u32 predictedMoveOnPartner = aiData->lastUsedMove[BATTLE_PARTNER(battlerAtk)]; if (predictedMoveOnPartner != MOVE_NONE && !IsBattleMoveStatus(predictedMoveOnPartner)) ADJUST_SCORE(GOOD_EFFECT); } @@ -5015,19 +5056,19 @@ static s32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move, stru ADJUST_SCORE(GOOD_EFFECT); break; case EFFECT_RECYCLE: - if (GetUsedHeldItem(battlerAtk) != ITEM_NONE) + if (GetBattlerPartyState(battlerAtk)->usedHeldItem != ITEM_NONE) ADJUST_SCORE(WEAK_EFFECT); - if (IsRecycleEncouragedItem(GetUsedHeldItem(battlerAtk))) + if (IsRecycleEncouragedItem(GetBattlerPartyState(battlerAtk)->usedHeldItem)) ADJUST_SCORE(WEAK_EFFECT); if (aiData->abilities[battlerAtk] == ABILITY_RIPEN) { - u32 item = GetUsedHeldItem(battlerAtk); + u32 item = GetBattlerPartyState(battlerAtk)->usedHeldItem; u32 toHeal = (GetItemHoldEffectParam(item) == 10) ? 10 : gBattleMons[battlerAtk].maxHP / GetItemHoldEffectParam(item); if (IsStatBoostingBerry(item) && aiData->hpPercents[battlerAtk] > 60) ADJUST_SCORE(WEAK_EFFECT); else if (ShouldRestoreHpBerry(battlerAtk, item) && !CanAIFaintTarget(battlerAtk, battlerDef, 0) - && ((GetWhichBattlerFasterOrTies(battlerAtk, battlerDef, TRUE) == 1 && CanTargetFaintAiWithMod(battlerDef, battlerAtk, 0, 0)) + && ((AI_GetWhichBattlerFasterOrTies(battlerAtk, battlerDef, TRUE) == 1 && CanTargetFaintAiWithMod(battlerDef, battlerAtk, 0, 0)) || !CanTargetFaintAiWithMod(battlerDef, battlerAtk, toHeal, 0))) ADJUST_SCORE(WEAK_EFFECT); // Recycle healing berry if we can't otherwise faint the target and the target wont kill us after we activate the berry } @@ -5045,10 +5086,9 @@ static s32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move, stru case EFFECT_ENTRAINMENT: case EFFECT_GASTRO_ACID: case EFFECT_ROLE_PLAY: - case EFFECT_SIMPLE_BEAM: case EFFECT_SKILL_SWAP: - case EFFECT_WORRY_SEED: - AbilityChangeScore(battlerAtk, battlerDef, moveEffect, &score, aiData); + case EFFECT_OVERWRITE_ABILITY: + AbilityChangeScore(battlerAtk, battlerDef, move, &score, aiData); return score; case EFFECT_IMPRISON: if (predictedMove != MOVE_NONE && HasMove(battlerAtk, predictedMove)) @@ -5177,7 +5217,7 @@ static s32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move, stru if (gBattleMons[battlerDef].speed > gBattleMons[battlerAtk].speed) ADJUST_SCORE(DECENT_EFFECT); break; -case EFFECT_GUARD_SPLIT: + case EFFECT_GUARD_SPLIT: { u32 atkDefense = gBattleMons[battlerAtk].defense; u32 defDefense = gBattleMons[battlerDef].defense; @@ -5224,6 +5264,7 @@ case EFFECT_GUARD_SPLIT: ADJUST_AND_RETURN_SCORE(GOOD_EFFECT); ADJUST_SCORE(WORST_EFFECT); + break; } case EFFECT_ELECTRIC_TERRAIN: if (ShouldSetFieldStatus(battlerAtk, STATUS_FIELD_ELECTRIC_TERRAIN)) @@ -5292,7 +5333,7 @@ case EFFECT_GUARD_SPLIT: else if (!(gFieldStatuses & STATUS_FIELD_TRICK_ROOM) && !hasPartner && (CountUsablePartyMons(battlerAtk) != 0)) ADJUST_SCORE(DECENT_EFFECT); // Don't unset it on last turn. - else if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer != (gBattleTurnCounter + 1) && ShouldClearFieldStatus(battlerAtk, STATUS_FIELD_TRICK_ROOM)) + else if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer > 1 && ShouldClearFieldStatus(battlerAtk, STATUS_FIELD_TRICK_ROOM)) ADJUST_SCORE(GOOD_EFFECT); } break; @@ -5404,7 +5445,7 @@ case EFFECT_GUARD_SPLIT: break; case EFFECT_TAILWIND: { - if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer != (gBattleTurnCounter + 1)) + if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer > 1) break; if (HasBattlerSideMoveWithEffect(battlerAtk, EFFECT_ELECTRO_BALL)) @@ -5720,6 +5761,9 @@ static s32 AI_CalcAdditionalEffectScore(u32 battlerAtk, u32 battlerDef, u32 move } else // consider move effects that hinder the target { + if (IsAdditionalEffectBlocked(battlerAtk, aiData->abilities[battlerAtk], battlerDef, aiData->abilities[battlerDef])) + continue; + switch (additionalEffect->moveEffect) { case MOVE_EFFECT_FLINCH: @@ -5911,6 +5955,17 @@ static s32 AI_CalcAdditionalEffectScore(u32 battlerAtk, u32 battlerDef, u32 move if (ShouldSetScreen(battlerAtk, battlerDef, EFFECT_AURORA_VEIL)) ADJUST_SCORE(DECENT_EFFECT); break; + case MOVE_EFFECT_REMOVE_STATUS: + if (gBattleMons[battlerDef].status1 & GetMoveEffectArg_Status(move)) + { + if (ShouldCureStatus(battlerAtk, battlerDef, aiData)) + ADJUST_SCORE(DECENT_EFFECT); + else if (aiData->holdEffects[battlerDef] == HOLD_EFFECT_FLAME_ORB || aiData->holdEffects[battlerDef] == HOLD_EFFECT_TOXIC_ORB) + ADJUST_SCORE(WEAK_EFFECT); + else + ADJUST_SCORE(BAD_EFFECT); + } + break; default: break; } @@ -6209,7 +6264,7 @@ static s32 AI_PreferBatonPass(u32 battlerAtk, u32 battlerDef, u32 move, s32 scor ADJUST_SCORE(DECENT_EFFECT); break; case EFFECT_PROTECT: - if (GetProtectType(GetMoveProtectMethod(gLastMoves[battlerAtk])) == PROTECT_TYPE_SINGLE) + if (GetProtectType(GetMoveProtectMethod(gAiLogicData->lastUsedMove[battlerAtk])) == PROTECT_TYPE_SINGLE) ADJUST_SCORE(-2); else ADJUST_SCORE(DECENT_EFFECT); @@ -6231,7 +6286,7 @@ static s32 AI_PreferBatonPass(u32 battlerAtk, u32 battlerDef, u32 move, s32 scor static s32 AI_HPAware(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) { enum BattleMoveEffects effect = GetMoveEffect(move); - u32 moveType = 0; + enum Type moveType = 0; SetTypeBeforeUsingMove(move, battlerAtk); moveType = GetBattleMoveType(move); diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index 120d6f910..ba78ce467 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -7,7 +7,6 @@ #include "battle_anim.h" #include "battle_controllers.h" #include "battle_main.h" -#include "constants/hold_effects.h" #include "battle_setup.h" #include "data.h" #include "item.h" @@ -472,7 +471,7 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler) { u8 battlerIn1, battlerIn2; u8 numAbsorbingAbilities = 0; - u16 absorbingTypeAbilities[3]; // Array size is maximum number of absorbing abilities for a single type + enum Ability absorbingTypeAbilities[3]; // Array size is maximum number of absorbing abilities for a single type s32 firstId; s32 lastId; struct Pokemon *party; @@ -480,7 +479,7 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler) u16 aiMove; u32 opposingBattler = GetOppositeBattler(battler); u32 incomingMove = GetIncomingMove(battler, opposingBattler, gAiLogicData); - u32 incomingType = CheckDynamicMoveType(GetBattlerMon(opposingBattler), incomingMove, opposingBattler, MON_IN_BATTLE); + enum Type incomingType = CheckDynamicMoveType(GetBattlerMon(opposingBattler), incomingMove, opposingBattler, MON_IN_BATTLE); bool32 isOpposingBattlerChargingOrInvulnerable = !BreaksThroughSemiInvulnerablity(opposingBattler, incomingMove) || IsTwoTurnNotSemiInvulnerableMove(opposingBattler, incomingMove); s32 i, j; @@ -668,7 +667,7 @@ static bool32 ShouldSwitchIfBadlyStatused(u32 battler) { bool32 switchMon = FALSE; enum Ability monAbility = gAiLogicData->abilities[battler]; - enum ItemHoldEffect holdEffect = gAiLogicData->holdEffects[battler]; + enum HoldEffect holdEffect = gAiLogicData->holdEffects[battler]; u8 opposingPosition = BATTLE_OPPOSITE(GetBattlerPosition(battler)); u8 opposingBattler = GetBattlerAtPosition(opposingPosition); bool32 hasStatRaised = AnyStatIsRaised(battler); @@ -924,7 +923,7 @@ static bool32 FindMonWithFlagsAndSuperEffective(u32 battler, u16 flags, u32 perc for (j = 0; j < MAX_MON_MOVES; j++) { move = GetMonData(&party[i], MON_DATA_MOVE1 + j); - if (move == 0) + if (move == MOVE_NONE) continue; if (AI_GetMoveEffectiveness(move, battler, battlerIn1) >= UQ_4_12(2.0) && (RandomPercentage(RNG_AI_SWITCH_SE_DEFENSIVE, percentChance) || gAiLogicData->aiPredictionInProgress)) @@ -1027,7 +1026,7 @@ static bool32 ShouldSwitchIfEncored(u32 battler) static bool32 ShouldSwitchIfBadChoiceLock(u32 battler) { - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler); + enum HoldEffect holdEffect = GetBattlerHoldEffect(battler); u32 lastUsedMove = gAiLogicData->lastUsedMove[battler]; u32 opposingBattler = GetOppositeBattler(battler); bool32 moveAffectsTarget = TRUE; @@ -1120,7 +1119,7 @@ bool32 ShouldSwitch(u32 battler) if (IsDoubleBattle()) { - u32 partner = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerAtPosition(battler))); + u32 partner = BATTLE_PARTNER(battler); battlerIn1 = battler; if (gAbsentBattlerFlags & (1u << partner)) battlerIn2 = battler; @@ -1271,7 +1270,7 @@ void ModifySwitchAfterMoveScoring(u32 battler) if (IsDoubleBattle()) { - u32 partner = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerAtPosition(battler))); + u32 partner = BATTLE_PARTNER(battler); battlerIn1 = battler; if (gAbsentBattlerFlags & (1u << partner)) battlerIn2 = battler; @@ -1319,7 +1318,7 @@ bool32 IsSwitchinValid(u32 battler) // Edge case: See if partner already chose to switch into the same mon if (IsDoubleBattle()) { - u32 partner = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerAtPosition(battler))); + u32 partner = BATTLE_PARTNER(battler); if (gBattleStruct->AI_monToSwitchIntoId[battler] == PARTY_SIZE) // Generic switch { if ((gAiLogicData->shouldSwitch & (1u << partner)) && gAiLogicData->monToSwitchInId[partner] == gAiLogicData->mostSuitableMonId[battler]) @@ -1518,7 +1517,7 @@ static u32 GetBestMonDmg(struct Pokemon *party, int firstId, int lastId, u8 inva return bestMonId; } -static u32 GetFirstNonIvalidMon(u32 firstId, u32 lastId, u32 invalidMons, u32 battlerIn1, u32 battlerIn2) +static u32 GetFirstNonInvalidMon(u32 firstId, u32 lastId, u32 invalidMons, u32 battlerIn1, u32 battlerIn2) { if (!IsDoubleBattle()) return PARTY_SIZE; @@ -1536,7 +1535,7 @@ static u32 GetFirstNonIvalidMon(u32 firstId, u32 lastId, u32 invalidMons, u32 ba return PARTY_SIZE; } -bool32 IsMonGrounded(u16 heldItemEffect, enum Ability ability, u8 type1, u8 type2) +bool32 IsMonGrounded(enum HoldEffect heldItemEffect, enum Ability ability, enum Type type1, enum Type type2) { // List that makes mon not grounded if (type1 == TYPE_FLYING || type2 == TYPE_FLYING || ability == ABILITY_LEVITATE @@ -1555,7 +1554,8 @@ bool32 IsMonGrounded(u16 heldItemEffect, enum Ability ability, u8 type1, u8 type // Gets hazard damage static u32 GetSwitchinHazardsDamage(u32 battler, struct BattlePokemon *battleMon) { - u8 defType1 = battleMon->types[0], defType2 = battleMon->types[1], tSpikesLayers; + enum Type defType1 = battleMon->types[0], defType2 = battleMon->types[1]; + u8 tSpikesLayers; u16 heldItemEffect = GetItemHoldEffect(battleMon->item); u32 maxHP = battleMon->maxHP; enum Ability ability = battleMon->ability, status = battleMon->status1; @@ -1616,7 +1616,7 @@ static s32 GetSwitchinWeatherImpact(void) { s32 weatherImpact = 0, maxHP = gAiLogicData->switchinCandidate.battleMon.maxHP; enum Ability ability = gAiLogicData->switchinCandidate.battleMon.ability; - enum ItemHoldEffect holdEffect = GetItemHoldEffect(gAiLogicData->switchinCandidate.battleMon.item); + enum HoldEffect holdEffect = GetItemHoldEffect(gAiLogicData->switchinCandidate.battleMon.item); if (HasWeatherEffect()) { @@ -1681,7 +1681,7 @@ static u32 GetSwitchinRecurringHealing(void) { u32 recurringHealing = 0, maxHP = gAiLogicData->switchinCandidate.battleMon.maxHP; enum Ability ability = gAiLogicData->switchinCandidate.battleMon.ability; - enum ItemHoldEffect holdEffect = GetItemHoldEffect(gAiLogicData->switchinCandidate.battleMon.item); + enum HoldEffect holdEffect = GetItemHoldEffect(gAiLogicData->switchinCandidate.battleMon.item); // Items if (ability != ABILITY_KLUTZ) @@ -1716,7 +1716,7 @@ static u32 GetSwitchinRecurringDamage(void) { u32 passiveDamage = 0, maxHP = gAiLogicData->switchinCandidate.battleMon.maxHP; enum Ability ability = gAiLogicData->switchinCandidate.battleMon.ability; - enum ItemHoldEffect holdEffect = GetItemHoldEffect(gAiLogicData->switchinCandidate.battleMon.item); + enum HoldEffect holdEffect = GetItemHoldEffect(gAiLogicData->switchinCandidate.battleMon.item); // Items if (ability != ABILITY_MAGIC_GUARD && ability != ABILITY_KLUTZ) @@ -1746,7 +1746,7 @@ static u32 GetSwitchinRecurringDamage(void) // Gets one turn of status damage static u32 GetSwitchinStatusDamage(u32 battler) { - u8 defType1 = gAiLogicData->switchinCandidate.battleMon.types[0], defType2 = gAiLogicData->switchinCandidate.battleMon.types[1]; + enum Type defType1 = gAiLogicData->switchinCandidate.battleMon.types[0], defType2 = gAiLogicData->switchinCandidate.battleMon.types[1]; u8 tSpikesLayers = gSideTimers[GetBattlerSide(battler)].toxicSpikesAmount; u16 heldItemEffect = GetItemHoldEffect(gAiLogicData->switchinCandidate.battleMon.item); u32 status = gAiLogicData->switchinCandidate.battleMon.status1; @@ -1935,8 +1935,8 @@ static u32 GetBattleMonTypeMatchup(struct BattlePokemon opposingBattleMon, struc { // Check type matchup u32 typeEffectiveness1 = UQ_4_12(1.0), typeEffectiveness2 = UQ_4_12(1.0); - u8 atkType1 = opposingBattleMon.types[0], atkType2 = opposingBattleMon.types[1], - defType1 = battleMon.types[0], defType2 = battleMon.types[1]; + enum Type atkType1 = opposingBattleMon.types[0], atkType2 = opposingBattleMon.types[1]; + enum Type defType1 = battleMon.types[0], defType2 = battleMon.types[1]; // Add each independent defensive type matchup together typeEffectiveness1 = uq4_12_multiply(typeEffectiveness1, (GetTypeModifier(atkType1, defType1))); @@ -1996,7 +1996,10 @@ static s32 GetMaxDamagePlayerCouldDealToSwitchin(u32 battler, u32 opposingBattle { damageTaken = AI_CalcPartyMonDamage(playerMove, opposingBattler, battler, battleMon, &effectiveness, AI_DEFENDING); if (playerMove == gBattleStruct->choicedMove[opposingBattler]) // If player is choiced, only care about the choice locked move + { + *bestPlayerMove = playerMove; return damageTaken; + } if (damageTaken > maxDamageTaken) { maxDamageTaken = damageTaken; @@ -2017,13 +2020,19 @@ static s32 GetMaxPriorityDamagePlayerCouldDealToSwitchin(u32 battler, u32 opposi for (i = 0; i < MAX_MON_MOVES; i++) { + // If player is choiced into a non-priority move, AI understands that it can't deal priority damage + if (gBattleStruct->choicedMove[opposingBattler] !=MOVE_NONE && GetMovePriority(gBattleStruct->choicedMove[opposingBattler]) < 1) + break; playerMove = SMART_SWITCHING_OMNISCIENT ? gBattleMons[opposingBattler].moves[i] : playerMoves[i]; if (GetBattleMovePriority(opposingBattler, gAiLogicData->abilities[opposingBattler], playerMove) > 0 && playerMove != MOVE_NONE && !IsBattleMoveStatus(playerMove) && GetMoveEffect(playerMove) != EFFECT_FOCUS_PUNCH && gBattleMons[opposingBattler].pp[i] > 0) { damageTaken = AI_CalcPartyMonDamage(playerMove, opposingBattler, battler, battleMon, &effectiveness, AI_DEFENDING); if (playerMove == gBattleStruct->choicedMove[opposingBattler]) // If player is choiced, only care about the choice locked move + { + *bestPlayerPriorityMove = playerMove; return damageTaken; + } if (damageTaken > maxDamageTaken) { maxDamageTaken = damageTaken; @@ -2301,7 +2310,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId, return aceMonId; // Fallback - u32 bestMonId = GetFirstNonIvalidMon(firstId, lastId, invalidMons, battlerIn1, battlerIn2); + u32 bestMonId = GetFirstNonInvalidMon(firstId, lastId, invalidMons, battlerIn1, battlerIn2); if (bestMonId != PARTY_SIZE) return bestMonId; @@ -2423,7 +2432,7 @@ u32 GetMostSuitableMonToSwitchInto(u32 battler, enum SwitchType switchType) return aceMonId; // Fallback - bestMonId = GetFirstNonIvalidMon(firstId, lastId, invalidMons, battlerIn1, battlerIn2); + bestMonId = GetFirstNonInvalidMon(firstId, lastId, invalidMons, battlerIn1, battlerIn2); if (bestMonId != PARTY_SIZE) return bestMonId; @@ -2505,18 +2514,13 @@ static bool32 ShouldUseItem(u32 battler) shouldUse = AI_ShouldHeal(battler, healAmount); break; case EFFECT_ITEM_CURE_STATUS: - if (itemEffects[3] & ITEM3_SLEEP && gBattleMons[battler].status1 & STATUS1_SLEEP) - shouldUse = TRUE; - if (itemEffects[3] & ITEM3_POISON && gBattleMons[battler].status1 & STATUS1_PSN_ANY) - shouldUse = TRUE; - if (itemEffects[3] & ITEM3_BURN && gBattleMons[battler].status1 & STATUS1_BURN) - shouldUse = TRUE; - if (itemEffects[3] & ITEM3_FREEZE && gBattleMons[battler].status1 & STATUS1_ICY_ANY) - shouldUse = TRUE; - if (itemEffects[3] & ITEM3_PARALYSIS && gBattleMons[battler].status1 & STATUS1_PARALYSIS) - shouldUse = TRUE; - if (itemEffects[3] & ITEM3_CONFUSION && gBattleMons[battler].volatiles.confusionTurns > 0) - shouldUse = TRUE; + if ((itemEffects[3] & ITEM3_SLEEP && gBattleMons[battler].status1 & STATUS1_SLEEP) + || (itemEffects[3] & ITEM3_POISON && gBattleMons[battler].status1 & STATUS1_PSN_ANY) + || (itemEffects[3] & ITEM3_BURN && gBattleMons[battler].status1 & STATUS1_BURN) + || (itemEffects[3] & ITEM3_FREEZE && gBattleMons[battler].status1 & STATUS1_ICY_ANY) + || (itemEffects[3] & ITEM3_PARALYSIS && gBattleMons[battler].status1 & STATUS1_PARALYSIS) + || (itemEffects[3] & ITEM3_CONFUSION && gBattleMons[battler].volatiles.confusionTurns > 0)) + shouldUse = ShouldCureStatusWithItem(battler, battler, gAiLogicData); break; case EFFECT_ITEM_INCREASE_STAT: case EFFECT_ITEM_INCREASE_ALL_STATS: diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 46ff7aac8..d0b849618 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -20,7 +20,6 @@ #include "constants/abilities.h" #include "constants/battle_ai.h" #include "constants/battle_move_effects.h" -#include "constants/hold_effects.h" #include "constants/moves.h" #include "constants/items.h" @@ -272,7 +271,7 @@ void ClearBattlerAbilityHistory(u32 battlerId) gBattleHistory->abilities[battlerId] = ABILITY_NONE; } -void RecordItemEffectBattle(u32 battlerId, u32 itemEffect) +void RecordItemEffectBattle(u32 battlerId, enum HoldEffect itemEffect) { gBattleHistory->itemEffects[battlerId] = itemEffect; gAiPartyData->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].heldEffect = itemEffect; @@ -473,7 +472,7 @@ bool32 AI_BattlerAtMaxHp(u32 battlerId) bool32 AI_CanBattlerEscape(u32 battler) { - enum ItemHoldEffect holdEffect = gAiLogicData->holdEffects[battler]; + enum HoldEffect holdEffect = gAiLogicData->holdEffects[battler]; if (B_GHOSTS_ESCAPE >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST)) return TRUE; @@ -541,16 +540,6 @@ bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler) return FALSE; } -// move checks -bool32 IsAffectedByPowder(u32 battler, enum Ability ability, enum ItemHoldEffect holdEffect) -{ - if (ability == ABILITY_OVERCOAT - || (B_POWDER_GRASS >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GRASS)) - || holdEffect == HOLD_EFFECT_SAFETY_GOGGLES) - return FALSE; - return TRUE; -} - bool32 Ai_IsPriorityBlocked(u32 battlerAtk, u32 battlerDef, u32 move, struct AiLogicData *aiData) { s32 atkPriority = GetBattleMovePriority(battlerAtk, aiData->abilities[battlerAtk], move); @@ -569,6 +558,7 @@ bool32 Ai_IsPriorityBlocked(u32 battlerAtk, u32 battlerDef, u32 move, struct AiL return FALSE; } + // This function checks if all physical/special moves are either unusable or unreasonable to use. // Consider a pokemon boosting their attack against a ghost pokemon having only normal-type physical attacks. bool32 MovesWithCategoryUnusable(u32 attacker, u32 target, enum DamageCategory category) @@ -594,7 +584,7 @@ bool32 MovesWithCategoryUnusable(u32 attacker, u32 target, enum DamageCategory c if (GetBattleMoveCategory(moves[i]) == category) { SetTypeBeforeUsingMove(moves[i], attacker); - ctx.move = moves[i]; + ctx.move = ctx.chosenMove = moves[i]; ctx.moveType = GetBattleMoveType(moves[i]); if (CalcTypeEffectivenessMultiplier(&ctx)) @@ -733,6 +723,17 @@ bool32 IsDamageMoveUnusable(struct DamageContext *ctx) return FALSE; } +bool32 IsAdditionalEffectBlocked(u32 battlerAtk, u32 abilityAtk, u32 battlerDef, u32 abilityDef) +{ + if (gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_COVERT_CLOAK) + return TRUE; + + if (abilityDef == ABILITY_SHIELD_DUST && !IsMoldBreakerTypeAbility(battlerAtk, abilityAtk)) + return TRUE; + + return FALSE; +} + static inline s32 GetDamageByRollType(s32 dmg, enum DamageRollType rollType) { if (rollType == DMG_ROLL_LOWEST) @@ -762,14 +763,14 @@ static inline s32 SetFixedMoveBasePower(u32 battlerAtk, u32 move) return fixedBasePower; } -static inline void AI_StoreBattlerTypes(u32 battlerAtk, u32 *types) +static inline void AI_StoreBattlerTypes(u32 battlerAtk, enum Type *types) { types[0] = gBattleMons[battlerAtk].types[0]; types[1] = gBattleMons[battlerAtk].types[1]; types[2] = gBattleMons[battlerAtk].types[2]; } -static inline void AI_RestoreBattlerTypes(u32 battlerAtk, u32 *types) +static inline void AI_RestoreBattlerTypes(u32 battlerAtk, enum Type *types) { gBattleMons[battlerAtk].types[0] = types[0]; gBattleMons[battlerAtk].types[1] = types[1]; @@ -892,7 +893,7 @@ static inline bool32 ShouldCalcCritDamage(u32 battlerAtk, u32 battlerDef, u32 mo struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, uq4_12_t *typeEffectiveness, enum AIConsiderGimmick considerGimmickAtk, enum AIConsiderGimmick considerGimmickDef, u32 weather) { - struct SimulatedDamage simDamage; + struct SimulatedDamage simDamage = {0}; enum BattleMoveEffects moveEffect = GetMoveEffect(move); bool32 isDamageMoveUnusable = FALSE; bool32 toggledGimmickAtk = FALSE; @@ -925,10 +926,10 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u gBattleStruct->magnitudeBasePower = 70; gBattleStruct->presentBasePower = 80; - struct DamageContext ctx; + struct DamageContext ctx = {0}; ctx.battlerAtk = battlerAtk; ctx.battlerDef = battlerDef; - ctx.move = move; + ctx.move = ctx.chosenMove = move; ctx.moveType = GetBattleMoveType(move); ctx.isCrit = ShouldCalcCritDamage(battlerAtk, battlerDef, move, aiData); ctx.randomFactor = FALSE; @@ -947,7 +948,7 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u if (movePower && !isDamageMoveUnusable) { - u32 types[3]; + enum Type types[3]; AI_StoreBattlerTypes(battlerAtk, types); ProteanTryChangeType(battlerAtk, aiData->abilities[battlerAtk], move, ctx.moveType); @@ -1057,6 +1058,49 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3 { switch (additionalEffect->moveEffect) { + case MOVE_EFFECT_ATK_MINUS_1: + case MOVE_EFFECT_ATK_MINUS_2: + if (abilityAtk == ABILITY_CONTRARY && BattlerStatCanRise(battlerAtk, abilityAtk, STAT_ATK)) + return TRUE; + break; + case MOVE_EFFECT_DEF_MINUS_1: + case MOVE_EFFECT_DEF_MINUS_2: + if (abilityAtk == ABILITY_CONTRARY && BattlerStatCanRise(battlerAtk, abilityAtk, STAT_ATK)) + return TRUE; + break; + case MOVE_EFFECT_SPD_MINUS_1: + case MOVE_EFFECT_SPD_MINUS_2: + if (abilityAtk == ABILITY_CONTRARY && BattlerStatCanRise(battlerAtk, abilityAtk, STAT_DEF)) + return TRUE; + break; + case MOVE_EFFECT_SP_ATK_MINUS_1: + case MOVE_EFFECT_SP_ATK_MINUS_2: + if (abilityAtk == ABILITY_CONTRARY && BattlerStatCanRise(battlerAtk, abilityAtk, STAT_SPATK)) + return TRUE; + break; + case MOVE_EFFECT_SP_DEF_MINUS_1: + case MOVE_EFFECT_SP_DEF_MINUS_2: + if (abilityAtk == ABILITY_CONTRARY && BattlerStatCanRise(battlerAtk, abilityAtk, STAT_SPDEF)) + return TRUE; + break; + case MOVE_EFFECT_EVS_MINUS_1: + case MOVE_EFFECT_EVS_MINUS_2: + if (abilityAtk == ABILITY_CONTRARY && BattlerStatCanRise(battlerAtk, abilityAtk, STAT_EVASION)) + return TRUE; + break; + case MOVE_EFFECT_ACC_MINUS_1: + case MOVE_EFFECT_ACC_MINUS_2: + if (abilityAtk == ABILITY_CONTRARY && BattlerStatCanRise(battlerAtk, abilityAtk, STAT_ACC)) + return TRUE; + break; + case MOVE_EFFECT_ATK_DEF_DOWN: + if (abilityAtk == ABILITY_CONTRARY && (BattlerStatCanRise(battlerAtk, abilityAtk, STAT_ATK) || BattlerStatCanRise(battlerAtk, abilityAtk, STAT_DEF))) + return TRUE; + break; + case MOVE_EFFECT_DEF_SPDEF_DOWN: + if (abilityAtk == ABILITY_CONTRARY && (BattlerStatCanRise(battlerAtk, abilityAtk, STAT_DEF) || BattlerStatCanRise(battlerAtk, abilityAtk, STAT_SPDEF))) + return TRUE; + break; case MOVE_EFFECT_ATK_PLUS_1: case MOVE_EFFECT_ATK_PLUS_2: if (BattlerStatCanRise(battlerAtk, abilityAtk, STAT_ATK)) @@ -1100,6 +1144,9 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3 } else // consider move effects that hinder the target { + if (IsAdditionalEffectBlocked(battlerAtk, abilityAtk, battlerDef, abilityDef)) + continue; + switch (additionalEffect->moveEffect) { case MOVE_EFFECT_POISON: @@ -1134,7 +1181,7 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3 case MOVE_EFFECT_SP_DEF_MINUS_1: case MOVE_EFFECT_ACC_MINUS_1: case MOVE_EFFECT_EVS_MINUS_1: - if (CanLowerStat(battlerAtk, battlerDef, gAiLogicData, STAT_ATK + (additionalEffect->moveEffect - MOVE_EFFECT_ATK_MINUS_1)) && noOfHitsToKo != 1) + if (CanLowerStat(battlerAtk, battlerDef, gAiLogicData, STAT_ATK + (additionalEffect->moveEffect - MOVE_EFFECT_ATK_MINUS_1)) && noOfHitsToKo > 1) return TRUE; break; case MOVE_EFFECT_ATK_MINUS_2: @@ -1144,7 +1191,7 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3 case MOVE_EFFECT_SP_DEF_MINUS_2: case MOVE_EFFECT_ACC_MINUS_2: case MOVE_EFFECT_EVS_MINUS_2: - if (CanLowerStat(battlerAtk, battlerDef, gAiLogicData, STAT_ATK + (additionalEffect->moveEffect - MOVE_EFFECT_ATK_MINUS_2)) && noOfHitsToKo != 1) + if (CanLowerStat(battlerAtk, battlerDef, gAiLogicData, STAT_ATK + (additionalEffect->moveEffect - MOVE_EFFECT_ATK_MINUS_2)) && noOfHitsToKo > 1) return TRUE; break; default: @@ -1201,7 +1248,7 @@ static bool32 AI_IsMoveEffectInMinus(u32 battlerAtk, u32 battlerDef, u32 move, s case MOVE_EFFECT_ATK_DEF_DOWN: case MOVE_EFFECT_DEF_SPDEF_DOWN: if ((additionalEffect->self && abilityAtk != ABILITY_CONTRARY) - || (noOfHitsToKo != 1 && abilityDef == ABILITY_CONTRARY && !DoesBattlerIgnoreAbilityChecks(battlerAtk, abilityAtk, move))) + || (noOfHitsToKo > 1 && !additionalEffect->self && abilityDef == ABILITY_CONTRARY && !DoesBattlerIgnoreAbilityChecks(battlerAtk, abilityAtk, move))) return TRUE; break; case MOVE_EFFECT_RECHARGE: @@ -1222,7 +1269,7 @@ static bool32 AI_IsMoveEffectInMinus(u32 battlerAtk, u32 battlerDef, u32 move, s case MOVE_EFFECT_ACC_PLUS_2: case MOVE_EFFECT_ALL_STATS_UP: if ((additionalEffect->self && abilityAtk == ABILITY_CONTRARY) - || (noOfHitsToKo != 1 && !(abilityDef == ABILITY_CONTRARY && !DoesBattlerIgnoreAbilityChecks(battlerAtk, abilityAtk, move)))) + || (noOfHitsToKo > 1 && !additionalEffect->self && !(abilityDef == ABILITY_CONTRARY && !DoesBattlerIgnoreAbilityChecks(battlerAtk, abilityAtk, move)))) return TRUE; break; default: @@ -1335,7 +1382,7 @@ uq4_12_t AI_GetMoveEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef) struct DamageContext ctx = {0}; ctx.battlerAtk = battlerAtk; ctx.battlerDef = battlerDef; - ctx.move = move; + ctx.move = ctx.chosenMove = move; ctx.moveType = GetBattleMoveType(move); ctx.updateFlags = FALSE; ctx.abilityAtk = gAiLogicData->abilities[battlerAtk]; @@ -1359,8 +1406,8 @@ uq4_12_t AI_GetMoveEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef) s32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler, u32 aiMoveConsidered, u32 playerMoveConsidered, enum ConsiderPriority considerPriority) { u32 speedBattlerAI, speedBattler; - enum ItemHoldEffect holdEffectAI = gAiLogicData->holdEffects[battlerAI]; - enum ItemHoldEffect holdEffectPlayer = gAiLogicData->holdEffects[battler]; + enum HoldEffect holdEffectAI = gAiLogicData->holdEffects[battlerAI]; + enum HoldEffect holdEffectPlayer = gAiLogicData->holdEffects[battler]; enum Ability abilityAI = gAiLogicData->abilities[battlerAI]; enum Ability abilityPlayer = gAiLogicData->abilities[battler]; @@ -1375,8 +1422,8 @@ s32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler, u32 aiMoveConsidered, u32 pla return AI_IS_SLOWER; } - speedBattlerAI = GetBattlerTotalSpeedStatArgs(battlerAI, abilityAI, holdEffectAI); - speedBattler = GetBattlerTotalSpeedStatArgs(battler, abilityPlayer, holdEffectPlayer); + speedBattlerAI = GetBattlerTotalSpeedStat(battlerAI, abilityAI, holdEffectAI); + speedBattler = GetBattlerTotalSpeedStat(battler, abilityPlayer, holdEffectPlayer); if (holdEffectAI == HOLD_EFFECT_LAGGING_TAIL && holdEffectPlayer != HOLD_EFFECT_LAGGING_TAIL) return AI_IS_SLOWER; @@ -1413,7 +1460,7 @@ s32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler, u32 aiMoveConsidered, u32 pla bool32 CanEndureHit(u32 battler, u32 battlerTarget, u32 move) { enum BattleMoveEffects effect = GetMoveEffect(move); - if (!AI_BattlerAtMaxHp(battlerTarget) || effect == EFFECT_MULTI_HIT) + if (!AI_BattlerAtMaxHp(battlerTarget) || effect == EFFECT_MULTI_HIT || gAiLogicData->abilities[battler] == ABILITY_PARENTAL_BOND) return FALSE; if (GetMoveStrikeCount(move) > 1 && !(effect == EFFECT_DRAGON_DARTS && !HasTwoOpponents(battler))) return FALSE; @@ -1424,7 +1471,7 @@ bool32 CanEndureHit(u32 battler, u32 battlerTarget, u32 move) { if (B_STURDY >= GEN_5 && gAiLogicData->abilities[battlerTarget] == ABILITY_STURDY) return TRUE; - if (gBattleMons[battlerTarget].species == SPECIES_MIMIKYU_DISGUISED) + if (IsMimikyuDisguised(battlerTarget)) return TRUE; } @@ -1698,9 +1745,12 @@ enum Ability AI_DecideKnownAbilityForTurn(u32 battlerId) return ABILITY_NONE; // Unknown. } -enum ItemHoldEffect AI_DecideHoldEffectForTurn(u32 battlerId) +enum HoldEffect AI_DecideHoldEffectForTurn(u32 battlerId) { - enum ItemHoldEffect holdEffect; + enum HoldEffect holdEffect = HOLD_EFFECT_NONE; + + if (gBattleMons[battlerId].item == ITEM_NONE) // Failsafe for when user recorded an item but it was consumed + return holdEffect; if (!IsAiBattlerAware(battlerId)) holdEffect = gAiPartyData->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].heldEffect; @@ -1956,7 +2006,7 @@ bool32 IsMoveRedirectionPrevented(u32 battlerAtk, u32 move, enum Ability atkAbil bool32 ShouldTryOHKO(u32 battlerAtk, u32 battlerDef, enum Ability atkAbility, enum Ability defAbility, u32 move) { - enum ItemHoldEffect holdEffect = gAiLogicData->holdEffects[battlerDef]; + enum HoldEffect holdEffect = gAiLogicData->holdEffects[battlerDef]; u32 accuracy = gAiLogicData->moveAccuracy[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex]; gPotentialItemEffectBattler = battlerDef; @@ -1992,7 +2042,7 @@ bool32 ShouldRaiseAnyStat(u32 battlerAtk, u32 battlerDef) return FALSE; // Don't increase stats if opposing battler has Unaware - if (HasBattlerSideAbility(battlerDef, ABILITY_UNAWARE, gAiLogicData)) + if (AI_IsAbilityOnSide(battlerDef, ABILITY_UNAWARE)) return FALSE; // Don't set up if AI is dead to residual damage from weather @@ -2000,11 +2050,7 @@ bool32 ShouldRaiseAnyStat(u32 battlerAtk, u32 battlerDef) return FALSE; // Don't increase stats if opposing battler has Opportunist - if (HasBattlerSideAbility(battlerDef, ABILITY_OPPORTUNIST, gAiLogicData)) - return FALSE; - - // Don't increase stats if opposing battler has Encore - if (HasBattlerSideMoveWithEffect(battlerDef, EFFECT_ENCORE)) + if (AI_IsAbilityOnSide(battlerDef, ABILITY_OPPORTUNIST)) return FALSE; // Don't increase stats if opposing battler has used Haze effect or AI effect @@ -2025,6 +2071,9 @@ bool32 ShouldRaiseAnyStat(u32 battlerAtk, u32 battlerDef) bool32 ShouldSetWeather(u32 battler, u32 weather) { + if (AI_GetWeather() & weather) + return FALSE; + return WeatherChecker(battler, weather, FIELD_EFFECT_POSITIVE); } @@ -2035,6 +2084,15 @@ bool32 ShouldClearWeather(u32 battler, u32 weather) bool32 ShouldSetFieldStatus(u32 battler, u32 fieldStatus) { + if (gFieldStatuses & fieldStatus) + { + if (!(fieldStatus & STATUS_FIELD_TRICK_ROOM)) + return FALSE; + // DOUBLE_TRICK_ROOM_ON_LAST_TURN_CHANCE + else if (gFieldTimers.trickRoomTimer != 1) + return FALSE; + } + return FieldStatusChecker(battler, fieldStatus, FIELD_EFFECT_POSITIVE); } @@ -2097,7 +2155,7 @@ s32 ProtectChecks(u32 battlerAtk, u32 battlerDef, u32 move, u32 predictedMove) } // stat stages -bool32 CanLowerStat(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData, u32 stat) +bool32 CanLowerStat(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData, enum Stat stat) { if (gBattleMons[battlerDef].statStages[stat] == MIN_STAT_STAGE) return FALSE; @@ -2160,7 +2218,7 @@ bool32 CanLowerStat(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData, return TRUE; } -u32 IncreaseStatDownScore(u32 battlerAtk, u32 battlerDef, u32 stat) +u32 IncreaseStatDownScore(u32 battlerAtk, u32 battlerDef, enum Stat stat) { u32 tempScore = NO_INCREASE; @@ -2172,10 +2230,6 @@ u32 IncreaseStatDownScore(u32 battlerAtk, u32 battlerDef, u32 stat) if (GetBattlerSecondaryDamage(battlerDef) >= gBattleMons[battlerDef].hp) return NO_INCREASE; - // Don't decrease stat if opposing battler has Encore - if (HasBattlerSideMoveWithEffect(battlerDef, EFFECT_ENCORE)) - return NO_INCREASE; - if (DoesAbilityRaiseStatsWhenLowered(gAiLogicData->abilities[battlerDef])) return NO_INCREASE; @@ -2230,12 +2284,14 @@ u32 IncreaseStatDownScore(u32 battlerAtk, u32 battlerDef, u32 stat) if (gBattleMons[battlerDef].volatiles.cursed) tempScore += WEAK_EFFECT; break; + default: + break; } return (tempScore > BEST_EFFECT) ? BEST_EFFECT : tempScore; // don't inflate score so only max +4 } -bool32 BattlerStatCanRise(u32 battler, enum Ability battlerAbility, u32 stat) +bool32 BattlerStatCanRise(u32 battler, enum Ability battlerAbility, enum Stat stat) { if ((gBattleMons[battler].statStages[stat] < MAX_STAT_STAGE && battlerAbility != ABILITY_CONTRARY) || (battlerAbility == ABILITY_CONTRARY && gBattleMons[battler].statStages[stat] > MIN_STAT_STAGE)) @@ -2245,7 +2301,7 @@ bool32 BattlerStatCanRise(u32 battler, enum Ability battlerAbility, u32 stat) bool32 AreBattlersStatsMaxed(u32 battlerId) { - u32 i; + enum Stat i; for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) { if (gBattleMons[battlerId].statStages[i] < MAX_STAT_STAGE) @@ -2256,7 +2312,7 @@ bool32 AreBattlersStatsMaxed(u32 battlerId) bool32 AnyStatIsRaised(u32 battlerId) { - u32 i; + enum Stat i; for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) { @@ -2269,7 +2325,7 @@ bool32 AnyStatIsRaised(u32 battlerId) u32 CountPositiveStatStages(u32 battlerId) { u32 count = 0; - u32 i; + enum Stat i; for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) { if (gBattleMons[battlerId].statStages[i] > DEFAULT_STAT_STAGE) @@ -2281,7 +2337,7 @@ u32 CountPositiveStatStages(u32 battlerId) u32 CountNegativeStatStages(u32 battlerId) { u32 count = 0; - u32 i; + enum Stat i; for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) { if (gBattleMons[battlerId].statStages[i] < DEFAULT_STAT_STAGE) @@ -2354,7 +2410,7 @@ bool32 HasMoveWithCategory(u32 battler, enum DamageCategory category) return FALSE; } -bool32 HasMoveWithType(u32 battler, u32 type) +bool32 HasMoveWithType(u32 battler, enum Type type) { s32 i; u16 *moves = GetMovesArray(battler); @@ -2960,7 +3016,7 @@ bool32 HasDamagingMove(u32 battler) return FALSE; } -bool32 HasDamagingMoveOfType(u32 battler, u32 type) +bool32 HasDamagingMoveOfType(u32 battler, enum Type type) { s32 i; u16 *moves = GetMovesArray(battler); @@ -2969,7 +3025,7 @@ bool32 HasDamagingMoveOfType(u32 battler, u32 type) { if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && GetMovePower(moves[i]) > 0) { - u32 moveType = GetDynamicMoveType(GetBattlerMon(battler), moves[i], battler, MON_IN_BATTLE); + enum Type moveType = GetDynamicMoveType(GetBattlerMon(battler), moves[i], battler, MON_IN_BATTLE); if (moveType != TYPE_NONE && type == moveType) return TRUE; @@ -3049,17 +3105,16 @@ static u32 GetCurseDamage(u32 battlerId) return damage; } -static u32 GetTrapDamage(u32 battlerId) +static u32 GetTrapDamage(u32 battler) { // ai has no knowledge about turns remaining u32 damage = 0; - enum ItemHoldEffect holdEffect = gAiLogicData->holdEffects[gBattleStruct->wrappedBy[battlerId]]; - if (gBattleMons[battlerId].volatiles.wrapped) + if (gBattleMons[battler].volatiles.wrapped) { - if (holdEffect == HOLD_EFFECT_BINDING_BAND) - damage = GetNonDynamaxMaxHP(battlerId) / (B_BINDING_DAMAGE >= GEN_6 ? 6 : 8); + if (gAiLogicData->holdEffects[gBattleMons[battler].volatiles.wrappedBy] == HOLD_EFFECT_BINDING_BAND) + damage = GetNonDynamaxMaxHP(battler) / (B_BINDING_DAMAGE >= GEN_6 ? 6 : 8); else - damage = GetNonDynamaxMaxHP(battlerId) / (B_BINDING_DAMAGE >= GEN_6 ? 8 : 16); + damage = GetNonDynamaxMaxHP(battler) / (B_BINDING_DAMAGE >= GEN_6 ? 8 : 16); if (damage == 0) damage = 1; @@ -3117,7 +3172,7 @@ static bool32 BattlerAffectedByHail(u32 battlerId, enum Ability ability) static u32 GetWeatherDamage(u32 battlerId) { enum Ability ability = gAiLogicData->abilities[battlerId]; - enum ItemHoldEffect holdEffect = gAiLogicData->holdEffects[battlerId]; + enum HoldEffect holdEffect = gAiLogicData->holdEffects[battlerId]; u32 damage = 0; u32 weather = AI_GetWeather(); if (!weather) @@ -3186,7 +3241,7 @@ bool32 BattlerWillFaintFromSecondaryDamage(u32 battler, enum Ability ability) static bool32 AnyUsefulStatIsRaised(u32 battler) { - u32 statId; + enum Stat statId; for (statId = STAT_ATK; statId < NUM_BATTLE_STATS; statId++) { @@ -3204,6 +3259,8 @@ static bool32 AnyUsefulStatIsRaised(u32 battler) break; case STAT_SPEED: return TRUE; + default: + break; } } } @@ -3215,11 +3272,11 @@ static bool32 PartyBattlerShouldAvoidHazards(u32 currBattler, u32 switchBattler) { struct Pokemon *mon = &GetBattlerParty(currBattler)[switchBattler]; enum Ability ability = GetMonAbility(mon); // we know our own party data - enum ItemHoldEffect holdEffect; + enum HoldEffect holdEffect; u32 species = GetMonData(mon, MON_DATA_SPECIES); s32 hazardDamage = 0; - u32 type1 = GetSpeciesType(species, 0); - u32 type2 = GetSpeciesType(species, 1); + enum Type type1 = GetSpeciesType(species, 0); + enum Type type2 = GetSpeciesType(species, 1); u32 maxHp = GetMonData(mon, MON_DATA_MAX_HP); u32 side = GetBattlerSide(currBattler); @@ -3261,14 +3318,16 @@ enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, enum Ability defAbility u32 battlerToSwitch; u32 predictedMoveSpeedCheck = GetIncomingMoveSpeedCheck(battlerAtk, battlerDef, gAiLogicData); - battlerToSwitch = gBattleStruct->AI_monToSwitchIntoId[battlerAtk]; - // Palafin always wants to activate Zero to Hero if (gBattleMons[battlerAtk].species == SPECIES_PALAFIN_ZERO && gBattleMons[battlerAtk].ability == ABILITY_ZERO_TO_HERO && CountUsablePartyMons(battlerAtk) != 0) return SHOULD_PIVOT; + battlerToSwitch = gAiLogicData->mostSuitableMonId[battlerAtk]; + // This shouldn't ever happen, but it's there to make sure we don't accidentally read past the gParty array. + if (battlerToSwitch >= PARTY_SIZE) + battlerToSwitch = 0; if (PartyBattlerShouldAvoidHazards(battlerAtk, battlerToSwitch)) return DONT_PIVOT; @@ -3463,7 +3522,7 @@ bool32 IsBattlerIncapacitated(u32 battler, enum Ability ability) if (gBattleMons[battler].status1 & STATUS1_SLEEP && !HasMoveWithEffect(battler, EFFECT_SLEEP_TALK)) return TRUE; - if (gBattleMons[battler].volatiles.recharge || (ability == ABILITY_TRUANT && gDisableStructs[battler].truantCounter != 0)) + if (gDisableStructs[battler].rechargeTimer > 0 || (ability == ABILITY_TRUANT && gDisableStructs[battler].truantCounter != 0)) return TRUE; return FALSE; @@ -3744,7 +3803,7 @@ bool32 HasChoiceEffect(u32 battler) if (ability == ABILITY_KLUTZ) return FALSE; - enum ItemHoldEffect holdEffect = gAiLogicData->holdEffects[battler]; + enum HoldEffect holdEffect = gAiLogicData->holdEffects[battler]; switch (holdEffect) { case HOLD_EFFECT_CHOICE_BAND: @@ -3928,8 +3987,104 @@ bool32 ShouldSetScreen(u32 battlerAtk, u32 battlerDef, enum BattleMoveEffects mo return FALSE; } +static bool32 ShouldCureStatusInternal(u32 battlerAtk, u32 battlerDef, bool32 usingItem, struct AiLogicData *aiData) +{ + bool32 targetingSelf = (battlerAtk == battlerDef); + bool32 targetingAlly = IsTargetingPartner(battlerAtk, battlerDef); + u32 status = gBattleMons[battlerDef].status1; + + if (status & STATUS1_SLEEP) + { + if (targetingAlly || targetingSelf) + { + if (HasMoveWithEffect(battlerDef, EFFECT_SLEEP_TALK) || HasMoveWithEffect(battlerDef, EFFECT_SNORE)) + return FALSE; + else + return usingItem || targetingAlly; + } + return FALSE; + } + + if (status & STATUS1_FREEZE) + { + if (targetingAlly || targetingSelf) + { + if (HasThawingMove(battlerDef)) + return FALSE; + return usingItem || targetingAlly; + } + return FALSE; + } + + bool32 isHarmless = FALSE; + + if (DoesBattlerBenefitFromAllVolatileStatus(battlerDef, aiData->abilities[battlerDef])) + isHarmless = TRUE; + + if (status & STATUS1_PSN_ANY) + { + if (aiData->holdEffects[battlerDef] == HOLD_EFFECT_TOXIC_ORB) + return FALSE; + + if (aiData->abilities[battlerDef] == ABILITY_POISON_HEAL) + isHarmless = TRUE; + + if (aiData->abilities[battlerDef] == ABILITY_TOXIC_BOOST && !isHarmless) + { + if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL)) + isHarmless = TRUE; + else if (!(targetingSelf || targetingAlly) && !HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL)) + isHarmless = TRUE; + } + } + + if (status & STATUS1_BURN) + { + if (aiData->holdEffects[battlerDef] == HOLD_EFFECT_FLAME_ORB) + return FALSE; + + if (aiData->abilities[battlerDef] == ABILITY_FLARE_BOOST && !isHarmless) + { + if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL)) + isHarmless = TRUE; + else if (!(targetingSelf || targetingAlly) && !HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL)) + isHarmless = TRUE; + } + } + +/* + if (status & STATUS1_PARALYSIS) + if (status & STATUS1_FROSTBITE) +*/ + + if (isHarmless) + { + if (targetingSelf || targetingAlly) + return FALSE; + else + return TRUE; + } + else + { + if (targetingSelf || targetingAlly) + return TRUE; + else + return FALSE; + } +} + +bool32 ShouldCureStatus(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData) +{ + return ShouldCureStatusInternal(battlerAtk, battlerDef, FALSE, aiData); +} + +bool32 ShouldCureStatusWithItem(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData) +{ + return ShouldCureStatusInternal(battlerAtk, battlerDef, TRUE, aiData); +} + // Partner Logic -bool32 IsBattle1v1() +bool32 IsBattle1v1(void) { if (IsDoubleBattle() && ((IsBattlerAlive(B_POSITION_PLAYER_LEFT) && IsBattlerAlive(B_POSITION_PLAYER_RIGHT)) @@ -3981,7 +4136,7 @@ u32 GetAllyChosenMove(u32 battlerId) if (!IsBattlerAlive(partnerBattler) || !IsAiBattlerAware(partnerBattler)) return MOVE_NONE; else if (partnerBattler > battlerId) // Battler with the lower id chooses the move first. - return gLastMoves[partnerBattler]; + return gAiLogicData->lastUsedMove[partnerBattler]; else return GetChosenMoveFromPosition(partnerBattler); } @@ -4077,9 +4232,8 @@ static u32 GetAIEffectGroup(enum BattleMoveEffects effect) case EFFECT_ENTRAINMENT: case EFFECT_GASTRO_ACID: case EFFECT_ROLE_PLAY: - case EFFECT_SIMPLE_BEAM: case EFFECT_SKILL_SWAP: - case EFFECT_WORRY_SEED: + case EFFECT_OVERWRITE_ABILITY: aiEffect |= AI_EFFECT_CHANGE_ABILITY; break; default: @@ -4602,7 +4756,7 @@ static bool32 HasMoveThatChangesKOThreshold(u32 battlerId, u32 noOfHitsToFaint, return FALSE; } -static u32 GetStatBeingChanged(enum StatChange statChange) +static enum Stat GetStatBeingChanged(enum StatChange statChange) { switch(statChange) { @@ -4670,7 +4824,7 @@ static enum AIScore IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, u32 aiIsFaster = AI_IsFaster(battlerAtk, battlerDef, MOVE_NONE, predictedMoveSpeedCheck, DONT_CONSIDER_PRIORITY); // Don't care about the priority of our setup move, care about outspeeding otherwise u32 shouldSetUp = ((noOfHitsToFaint >= 2 && aiIsFaster) || (noOfHitsToFaint >= 3 && !aiIsFaster) || noOfHitsToFaint == UNKNOWN_NO_OF_HITS); u32 i; - u32 statId = GetStatBeingChanged(statChange); + enum Stat statId = GetStatBeingChanged(statChange); u32 stages = GetStagesOfStatChange(statChange); if (considerContrary && gAiLogicData->abilities[battlerAtk] == ABILITY_CONTRARY) @@ -4774,6 +4928,8 @@ static enum AIScore IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, else tempScore += DECENT_EFFECT; break; + default: + break; } // if already inclined to boost, be slightly more likely to if boost levels matter @@ -4924,7 +5080,7 @@ void IncreaseFrostbiteScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score } } -bool32 AI_MoveMakesContact(enum Ability ability, enum ItemHoldEffect holdEffect, u32 move) +bool32 AI_MoveMakesContact(enum Ability ability, enum HoldEffect holdEffect, u32 move) { if (MoveMakesContact(move) && ability != ABILITY_LONG_REACH @@ -5080,7 +5236,7 @@ bool32 ShouldUseZMove(u32 battlerAtk, u32 battlerDef, u32 chosenMove) if (gBattleMons[battlerDef].ability == ABILITY_DISGUISE && !MoveIgnoresTargetAbility(zMove) - && (gBattleMons[battlerDef].species == SPECIES_MIMIKYU_DISGUISED || gBattleMons[battlerDef].species == SPECIES_MIMIKYU_TOTEM_DISGUISED)) + && IsMimikyuDisguised(battlerDef)) return FALSE; // Don't waste a Z-Move busting disguise if (gBattleMons[battlerDef].ability == ABILITY_ICE_FACE && !MoveIgnoresTargetAbility(zMove) @@ -5198,7 +5354,8 @@ void DecideTerastal(u32 battler) #define takenWithTera altCalcs->takenWithTera #define takenWithoutTera gAiLogicData->simulatedDmg[opposingBattler][battler] -enum AIConsiderGimmick ShouldTeraFromCalcs(u32 battler, u32 opposingBattler, struct AltTeraCalcs *altCalcs) { +enum AIConsiderGimmick ShouldTeraFromCalcs(u32 battler, u32 opposingBattler, struct AltTeraCalcs *altCalcs) +{ struct Pokemon* party = GetBattlerParty(battler); // Check how many pokemon we have that could tera @@ -5375,7 +5532,7 @@ s32 AI_TryToClearStats(u32 battlerAtk, u32 battlerDef, bool32 isDoubleBattle) bool32 AI_ShouldCopyStatChanges(u32 battlerAtk, u32 battlerDef) { - u8 i; + enum Stat i; // Want to copy positive stat changes for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) { @@ -5395,6 +5552,8 @@ bool32 AI_ShouldCopyStatChanges(u32 battlerAtk, u32 battlerDef) case STAT_DEF: case STAT_SPDEF: return (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_STALL); + default: + break; } } } @@ -5532,15 +5691,6 @@ bool32 IsBattlerItemEnabled(u32 battler) return TRUE; } -bool32 HasBattlerSideAbility(u32 battler, enum Ability ability, struct AiLogicData *aiData) -{ - if (aiData->abilities[battler] == ability) - return TRUE; - if (HasPartnerIgnoreFlags(battler) && gAiLogicData->abilities[BATTLE_PARTNER(battler)] == ability) - return TRUE; - return FALSE; -} - u32 GetFriendlyFireKOThreshold(u32 battler) { if (gAiThinkingStruct->aiFlags[battler] & AI_FLAG_RISKY) @@ -5653,8 +5803,10 @@ bool32 ShouldTriggerAbility(u32 battlerAtk, u32 battlerDef, enum Ability ability // Used by CheckBadMove; this is determining purely if the effect CAN change an ability, not if it SHOULD. // At the moment, the parts about Mummy and Wandering Spirit are not actually used. -bool32 CanEffectChangeAbility(u32 battlerAtk, u32 battlerDef, u32 effect, struct AiLogicData *aiData) +bool32 CanEffectChangeAbility(u32 battlerAtk, u32 battlerDef, u32 move, struct AiLogicData *aiData) { + u32 effect = GetMoveEffect(move); + // Dynamaxed Pokemon are immune to some ability-changing effects. if (GetActiveGimmick(battlerDef) == GIMMICK_DYNAMAX) { @@ -5730,13 +5882,8 @@ bool32 CanEffectChangeAbility(u32 battlerAtk, u32 battlerDef, u32 effect, struct return FALSE; break; - case EFFECT_SIMPLE_BEAM: - if (defAbility == ABILITY_SIMPLE || gAbilitiesInfo[defAbility].cantBeOverwritten) - return FALSE; - break; - - case EFFECT_WORRY_SEED: - if (defAbility == ABILITY_INSOMNIA || gAbilitiesInfo[defAbility].cantBeOverwritten) + case EFFECT_OVERWRITE_ABILITY: + if (defAbility == GetMoveOverwriteAbility(move) || gAbilitiesInfo[defAbility].cantBeOverwritten) return FALSE; break; @@ -5751,9 +5898,8 @@ bool32 CanEffectChangeAbility(u32 battlerAtk, u32 battlerDef, u32 effect, struct case EFFECT_ENTRAINMENT: case EFFECT_GASTRO_ACID: case EFFECT_ROLE_PLAY: - case EFFECT_SIMPLE_BEAM: case EFFECT_SKILL_SWAP: - case EFFECT_WORRY_SEED: + case EFFECT_OVERWRITE_ABILITY: return FALSE; default: break; @@ -5782,17 +5928,17 @@ bool32 DoesEffectReplaceTargetAbility(u32 effect) { case EFFECT_ENTRAINMENT: case EFFECT_GASTRO_ACID: - case EFFECT_SIMPLE_BEAM: case EFFECT_SKILL_SWAP: - case EFFECT_WORRY_SEED: + case EFFECT_OVERWRITE_ABILITY: return TRUE; default: return FALSE; } } -void AbilityChangeScore(u32 battlerAtk, u32 battlerDef, u32 effect, s32 *score, struct AiLogicData *aiData) +void AbilityChangeScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score, struct AiLogicData *aiData) { + u32 effect = GetMoveEffect(move); bool32 isTargetingPartner = IsTargetingPartner(battlerAtk, battlerDef); enum Ability abilityAtk = aiData->abilities[battlerAtk]; enum Ability abilityDef = aiData->abilities[battlerDef]; @@ -5810,10 +5956,8 @@ void AbilityChangeScore(u32 battlerAtk, u32 battlerDef, u32 effect, s32 *score, if (effect == EFFECT_GASTRO_ACID) abilityAtk = ABILITY_NONE; - else if (effect == EFFECT_SIMPLE_BEAM) - abilityAtk = ABILITY_SIMPLE; - else if (effect == EFFECT_WORRY_SEED) - abilityAtk = ABILITY_INSOMNIA; + else if (effect == EFFECT_OVERWRITE_ABILITY) + abilityAtk = GetMoveOverwriteAbility(move); if (effect == EFFECT_DOODLE || effect == EFFECT_ROLE_PLAY || effect == EFFECT_SKILL_SWAP) { diff --git a/src/battle_anim_effects_1.c b/src/battle_anim_effects_1.c index 05b0b9ee3..35cd31f33 100644 --- a/src/battle_anim_effects_1.c +++ b/src/battle_anim_effects_1.c @@ -6831,10 +6831,10 @@ static void TrySwapStickyWebBattlerId(u32 battlerAtk, u32 battlerPartner) static void TrySwapWishBattlerIds(u32 battlerAtk, u32 battlerPartner) { u32 i, temp; - u32 oppSide = GetBattlerSide(BATTLE_OPPOSITE(battlerAtk)); // if used future sight on opposing side, properly track who used it - if (gSideStatuses[oppSide] & SIDE_STATUS_FUTUREATTACK) + if (gWishFutureKnock.futureSightCounter[LEFT_FOE(battlerAtk)] > 0 + || gWishFutureKnock.futureSightCounter[RIGHT_FOE(battlerAtk)] > 0) { for (i = 0; i < gBattlersCount; i++) { @@ -6858,8 +6858,8 @@ static void TrySwapWishBattlerIds(u32 battlerAtk, u32 battlerPartner) } // swap wish party indices - if (gWishFutureKnock.wishCounter[battlerAtk] > gBattleTurnCounter - || gWishFutureKnock.wishCounter[battlerPartner] > gBattleTurnCounter) + if (gWishFutureKnock.wishCounter[battlerAtk] > 0 + || gWishFutureKnock.wishCounter[battlerPartner] > 0) SWAP(gWishFutureKnock.wishPartyId[battlerAtk], gWishFutureKnock.wishPartyId[battlerPartner], temp); } diff --git a/src/battle_debug.c b/src/battle_debug.c index 5c2e0735a..23e8a74ff 100644 --- a/src/battle_debug.c +++ b/src/battle_debug.c @@ -35,7 +35,6 @@ #include "constants/moves.h" #include "constants/items.h" #include "constants/rgb.h" -#include "constants/hold_effects.h" #define MAX_MODIFY_DIGITS 4 @@ -230,7 +229,7 @@ enum }; // Static Declarations -static const u8 *GetHoldEffectName(enum ItemHoldEffect holdEffect); +static const u8 *GetHoldEffectName(enum HoldEffect holdEffect); // const rom data static const u8 sText_Ability[] = _("Ability"); @@ -361,7 +360,6 @@ static const struct ListMenuItem sVolatileStatusListItems[] = {COMPOUND_STRING("Torment"), VOLATILE_TORMENT}, {COMPOUND_STRING("Powder"), VOLATILE_POWDER}, {COMPOUND_STRING("DefenseCurl"), VOLATILE_DEFENSE_CURL}, - {COMPOUND_STRING("Recharge"), VOLATILE_RECHARGE}, {COMPOUND_STRING("Rage"), VOLATILE_RAGE}, {COMPOUND_STRING("DestinyBond"), VOLATILE_DESTINY_BOND}, {COMPOUND_STRING("EscapePrevention"), VOLATILE_ESCAPE_PREVENTION}, @@ -921,7 +919,7 @@ static void PutAiInfoText(struct BattleDebugMenu *data) if (IsOnPlayerSide(i) && IsBattlerAlive(i)) { enum Ability ability = gAiLogicData->abilities[i]; - enum ItemHoldEffect holdEffect = gAiLogicData->holdEffects[i]; + enum HoldEffect holdEffect = gAiLogicData->holdEffects[i]; u16 item = gAiLogicData->items[i]; u8 x = (i == B_POSITION_PLAYER_LEFT) ? 83 + (i) * 75 : 83 + (i-1) * 75; AddTextPrinterParameterized(data->aiMovesWindowId, FONT_SMALL, gAbilitiesInfo[ability].name, x, 0, 0, NULL); @@ -1496,7 +1494,7 @@ static void PrintSecondaryEntries(struct BattleDebugMenu *data) case LIST_ITEM_TYPES: for (i = 0; i < 3; i++) { - u8 *types = &gBattleMons[data->battlerId].types[0]; + enum Type *types = &gBattleMons[data->battlerId].types[0]; PadString(gTypesInfo[types[i]].name, text); printer.currentY = printer.y = (i * yMultiplier) + sSecondaryListTemplate.upText_Y; @@ -2272,7 +2270,7 @@ static const u8 *const sHoldEffectNames[HOLD_EFFECT_COUNT] = [HOLD_EFFECT_PRIMAL_ORB] = COMPOUND_STRING("Primal Orb"), [HOLD_EFFECT_PROTECTIVE_PADS] = COMPOUND_STRING("Protective Pads"), [HOLD_EFFECT_TERRAIN_EXTENDER] = COMPOUND_STRING("Terrain Extender"), - [HOLD_EFFECT_SEEDS] = COMPOUND_STRING("Seeds"), + [HOLD_EFFECT_TERRAIN_SEED] = COMPOUND_STRING("Seeds"), [HOLD_EFFECT_ADRENALINE_ORB] = COMPOUND_STRING("Adrenaline Orb"), [HOLD_EFFECT_MEMORY] = COMPOUND_STRING("Memory"), [HOLD_EFFECT_Z_CRYSTAL] = COMPOUND_STRING("Z-Crystal"), @@ -2292,7 +2290,8 @@ static const u8 *const sHoldEffectNames[HOLD_EFFECT_COUNT] = [HOLD_EFFECT_OGERPON_MASK] = COMPOUND_STRING("Ogerpon Mask"), [HOLD_EFFECT_BERSERK_GENE] = COMPOUND_STRING("Berserk Gene"), }; -static const u8 *GetHoldEffectName(enum ItemHoldEffect holdEffect) + +static const u8 *GetHoldEffectName(enum HoldEffect holdEffect) { if (sHoldEffectNames[holdEffect] == NULL) return sHoldEffectNames[0]; diff --git a/src/battle_dynamax.c b/src/battle_dynamax.c index 1ddc2b2b0..d5edbc0e6 100644 --- a/src/battle_dynamax.c +++ b/src/battle_dynamax.c @@ -19,7 +19,6 @@ #include "constants/battle_move_effects.h" #include "constants/battle_string_ids.h" #include "constants/flags.h" -#include "constants/hold_effects.h" #include "constants/items.h" #include "constants/moves.h" @@ -28,7 +27,7 @@ static u32 GetMaxPowerTier(u32 move); struct GMaxMove { u16 species; - u8 moveType; + enum Type moveType; u16 gmaxMove; }; @@ -66,15 +65,15 @@ static const struct GMaxMove sGMaxMoveTable[] = {SPECIES_ALCREMIE_GMAX, TYPE_FAIRY, MOVE_G_MAX_FINALE}, {SPECIES_COPPERAJAH_GMAX, TYPE_STEEL, MOVE_G_MAX_STEELSURGE}, {SPECIES_DURALUDON_GMAX, TYPE_DRAGON, MOVE_G_MAX_DEPLETION}, - {SPECIES_URSHIFU_SINGLE_STRIKE_GMAX,TYPE_DARK, MOVE_G_MAX_ONE_BLOW}, - {SPECIES_URSHIFU_RAPID_STRIKE_GMAX, TYPE_WATER, MOVE_G_MAX_RAPID_FLOW}, + {SPECIES_URSHIFU_SINGLE_STRIKE_GMAX, TYPE_DARK, MOVE_G_MAX_ONE_BLOW}, + {SPECIES_URSHIFU_RAPID_STRIKE_GMAX, TYPE_WATER, MOVE_G_MAX_RAPID_FLOW}, }; // Returns whether a battler can Dynamax. bool32 CanDynamax(u32 battler) { u16 species = GetBattlerVisualSpecies(battler); - enum ItemHoldEffect holdEffect = GetBattlerHoldEffectIgnoreNegation(battler); + enum HoldEffect holdEffect = GetBattlerHoldEffectIgnoreNegation(battler); // Prevents Zigzagoon from dynamaxing in vanilla. if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE && !IsOnPlayerSide(battler)) @@ -178,7 +177,7 @@ void ActivateDynamax(u32 battler) // Set appropriate use flags. SetActiveGimmick(battler, GIMMICK_DYNAMAX); SetGimmickAsActivated(battler, GIMMICK_DYNAMAX); - gBattleStruct->dynamax.dynamaxTurns[battler] = gBattleTurnCounter + DYNAMAX_TURNS_COUNT; + gBattleStruct->dynamax.dynamaxTurns[battler] = DYNAMAX_TURNS_COUNT; // Substitute is removed upon Dynamaxing. gBattleMons[battler].volatiles.substitute = FALSE; @@ -234,7 +233,7 @@ bool32 IsMoveBlockedByMaxGuard(u32 move) return FALSE; } -static u16 GetTypeBasedMaxMove(u32 battler, u32 type) +static u16 GetTypeBasedMaxMove(u32 battler, enum Type type) { // Gigantamax check u32 i; @@ -265,7 +264,7 @@ static u16 GetTypeBasedMaxMove(u32 battler, u32 type) // Returns the appropriate Max Move or G-Max Move for a battler to use. u16 GetMaxMove(u32 battler, u32 baseMove) { - u32 moveType; + enum Type moveType; SetTypeBeforeUsingMove(baseMove, battler); moveType = GetBattleMoveType(baseMove); @@ -318,7 +317,7 @@ u32 GetMaxMovePower(u32 move) } tier = GetMaxPowerTier(move); - u32 moveType = GetMoveType(move); + enum Type moveType = GetMoveType(move); if (moveType == TYPE_FIGHTING || moveType == TYPE_POISON || move == MOVE_MULTI_ATTACK) @@ -438,7 +437,7 @@ bool32 IsMaxMove(u32 move) } // Assigns the multistring to use for the "Damage Non- Types" G-Max effect. -void ChooseDamageNonTypesString(u8 type) +void ChooseDamageNonTypesString(enum Type type) { switch (type) { @@ -454,6 +453,8 @@ void ChooseDamageNonTypesString(u8 type) case TYPE_ROCK: gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SURROUNDED_BY_ROCKS; break; + default: + break; } } diff --git a/src/battle_end_turn.c b/src/battle_end_turn.c index 3b2c0f8cf..991393de9 100644 --- a/src/battle_end_turn.c +++ b/src/battle_end_turn.c @@ -1,5 +1,6 @@ #include "global.h" #include "battle.h" +#include "battle_hold_effects.h" #include "battle_util.h" #include "battle_controllers.h" #include "battle_ai_util.h" @@ -7,107 +8,10 @@ #include "battle_scripts.h" #include "constants/battle.h" #include "constants/battle_string_ids.h" -#include "constants/hold_effects.h" #include "constants/abilities.h" #include "constants/items.h" #include "constants/moves.h" -// General End Turn Effects based on research from smogon from vanilla games: -// https://www.smogon.com/forums/threads/sword-shield-battle-mechanics-research.3655528/page-64#post-9244179 -enum EndTurnResolutionOrder -{ - ENDTURN_ORDER, - ENDTURN_VARIOUS, - ENDTURN_WEATHER, - ENDTURN_WEATHER_DAMAGE, - ENDTURN_GEN_3_BERRY_ACTIVATION, - ENDTURN_EMERGENCY_EXIT_1, - ENDTURN_AFFECTION, - ENDTURN_FUTURE_SIGHT, - ENDTURN_WISH, - ENDTURN_FIRST_EVENT_BLOCK, - ENDTURN_EMERGENCY_EXIT_2, - ENDTURN_AQUA_RING, - ENDTURN_INGRAIN, - ENDTURN_LEECH_SEED, - ENDTURN_POISON, - ENDTURN_BURN, - ENDTURN_FROSTBITE, - ENDTURN_NIGHTMARE, - ENDTURN_CURSE, - ENDTURN_WRAP, - ENDTURN_SALT_CURE, - ENDTURN_OCTOLOCK, - ENDTURN_SYRUP_BOMB, - ENDTURN_TAUNT, - ENDTURN_TORMENT, - ENDTURN_ENCORE, - ENDTURN_DISABLE, - ENDTURN_MAGNET_RISE, - ENDTURN_TELEKINESIS, - ENDTURN_HEAL_BLOCK, - ENDTURN_EMBARGO, - ENDTURN_YAWN, - ENDTURN_PERISH_SONG, - ENDTURN_ROOST, - ENDTURN_EMERGENCY_EXIT_3, - ENDTURN_SECOND_EVENT_BLOCK, - ENDTURN_TRICK_ROOM, - ENDTURN_GRAVITY, - ENDTURN_WATER_SPORT, - ENDTURN_MUD_SPORT, - ENDTURN_WONDER_ROOM, - ENDTURN_MAGIC_ROOM, - ENDTURN_TERRAIN, - ENDTURN_THIRD_EVENT_BLOCK, - ENDTURN_EMERGENCY_EXIT_4, - ENDTURN_ABILITIES, - ENDTURN_FOURTH_EVENT_BLOCK, - ENDTURN_DYNAMAX, - ENDTURN_COUNT, -}; - -// Block that handles effects for each individual battler on the field (eg residual damage) -enum FirstEventBlock -{ - FIRST_EVENT_BLOCK_GMAX_MOVE_RESIDUAL, // Needs to be split - FIRST_EVENT_BLOCK_SEA_OF_FIRE_DAMAGE, - FIRST_EVENT_BLOCK_THRASH, // Thrash isn't handled here in vanilla but for now it is that best place for it. - FIRST_EVENT_BLOCK_GRASSY_TERRAIN_HEAL, - FIRST_EVENT_BLOCK_ABILITIES, - FIRST_EVENT_BLOCK_HEAL_ITEMS, -}; - -// Block that tries to remove side statuses -enum SecondEventBlock -{ - SECOND_EVENT_BLOCK_REFLECT, - SECOND_EVENT_BLOCK_LIGHT_SCREEN, - SECOND_EVENT_BLOCK_SAFEGUARD, - SECOND_EVENT_BLOCK_MIST, - SECOND_EVENT_BLOCK_TAILWIND, - SECOND_EVENT_BLOCK_LUCKY_CHANT, - SECOND_EVENT_BLOCK_RAINBOW, - SECOND_EVENT_BLOCK_SEA_OF_FIRE, - SECOND_EVENT_BLOCK_SWAMP, - SECOND_EVENT_BLOCK_AURORA_VEIL, -}; - -// Block that handles Uproar, items and non-form changing abilities -enum ThirdEventBlock -{ - THIRD_EVENT_BLOCK_UPROAR, - THIRD_EVENT_BLOCK_ABILITIES, - THIRD_EVENT_BLOCK_ITEMS, -}; - -// Form changing abilities and Eject Pack -enum FourthEventBlock -{ - FOURTH_EVENT_BLOCK_HUNGER_SWITCH, - FOURTH_EVENT_BLOCK_EJECT_PACK, -}; - static u32 GetBattlerSideForMessage(u32 side) { u32 battler = 0; @@ -126,18 +30,24 @@ static bool32 HandleEndTurnOrder(u32 battler) bool32 effect = FALSE; gBattleTurnCounter++; - gBattleStruct->endTurnEventsCounter++; + gBattleStruct->eventState.endTurn++; u32 i, j; + struct BattleContext ctx = {0}; for (i = 0; i < gBattlersCount; i++) { gBattlerByTurnOrder[i] = i; + ctx.abilities[i] = GetBattlerAbility(i); + ctx.holdEffects[i] = GetBattlerHoldEffect(i); } for (i = 0; i < gBattlersCount - 1; i++) { for (j = i + 1; j < gBattlersCount; j++) { - if (GetWhichBattlerFaster(gBattlerByTurnOrder[i], gBattlerByTurnOrder[j], FALSE) == -1) + ctx.battlerAtk = gBattlerByTurnOrder[i]; + ctx.battlerDef = gBattlerByTurnOrder[j]; + + if (GetWhichBattlerFaster(&ctx, FALSE) == -1) SwapTurnOrder(i, j); } } @@ -150,29 +60,43 @@ static bool32 HandleEndTurnVarious(u32 battler) u32 i; bool32 effect = FALSE; - gBattleStruct->endTurnEventsCounter++; + gBattleStruct->eventState.endTurn++; - if (gFieldStatuses & STATUS_FIELD_FAIRY_LOCK && gFieldTimers.fairyLockTimer == gBattleTurnCounter) + if (gFieldTimers.fairyLockTimer > 0 && --gFieldTimers.fairyLockTimer == 0) gFieldStatuses &= ~STATUS_FIELD_FAIRY_LOCK; for (i = 0; i < NUM_BATTLE_SIDES; i++) { - if (gSideStatuses[i] & SIDE_STATUS_DAMAGE_NON_TYPES && gSideTimers[i].damageNonTypesTimer == gBattleTurnCounter) + if (gSideTimers[i].damageNonTypesTimer > 0 && --gSideTimers[i].damageNonTypesTimer == 0) gSideStatuses[i] &= ~SIDE_STATUS_DAMAGE_NON_TYPES; } for (i = 0; i < gBattlersCount; i++) { + if (gDisableStructs[i].throatChopTimer > 0) + gDisableStructs[i].throatChopTimer--; + if (gBattleMons[i].volatiles.lockOn > 0) gBattleMons[i].volatiles.lockOn--; - if (gDisableStructs[i].chargeTimer && --gDisableStructs[i].chargeTimer == 0) + if (gDisableStructs[i].chargeTimer > 0 && --gDisableStructs[i].chargeTimer == 0) gBattleMons[i].volatiles.charge = FALSE; - if (gBattleMons[i].volatiles.laserFocus && gDisableStructs[i].laserFocusTimer == gBattleTurnCounter) + if (gDisableStructs[i].laserFocusTimer > 0 && --gDisableStructs[i].laserFocusTimer == 0) gBattleMons[i].volatiles.laserFocus = FALSE; - gBattleStruct->hpBefore[i] = gBattleMons[i].hp; + gBattleStruct->battlerState[i].wasAboveHalfHp = gBattleMons[i].hp > gBattleMons[i].maxHP / 2; + } + + if (gBattleStruct->incrementEchoedVoice) + { + if (gBattleStruct->echoedVoiceCounter < 4) + gBattleStruct->echoedVoiceCounter++; + gBattleStruct->incrementEchoedVoice = FALSE; + } + else + { + gBattleStruct->echoedVoiceCounter = 0; } return effect; @@ -180,7 +104,7 @@ static bool32 HandleEndTurnVarious(u32 battler) static bool32 HandleEndTurnWeather(u32 battler) { - gBattleStruct->endTurnEventsCounter++; + gBattleStruct->eventState.endTurn++; return EndOrContinueWeather(); } @@ -194,12 +118,12 @@ static bool32 HandleEndTurnWeatherDamage(u32 battler) if (currBattleWeather == 0xFF) { // If there is no weather on the field, no need to check other battlers so go to next state - gBattleStruct->turnEffectsBattlerId = 0; - gBattleStruct->endTurnEventsCounter++; + gBattleStruct->eventState.endTurnBattler = 0; + gBattleStruct->eventState.endTurn++; return effect; } - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (!IsBattlerAlive(battler) || !HasWeatherEffect()) return effect; @@ -238,9 +162,7 @@ static bool32 HandleEndTurnWeatherDamage(u32 battler) && GetBattlerHoldEffect(battler) != HOLD_EFFECT_SAFETY_GOGGLES && !IsAbilityAndRecord(battler, ability, ABILITY_MAGIC_GUARD)) { - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 16; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; + SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / 16); gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SANDSTORM; BattleScriptExecute(BattleScript_DamagingWeather); effect = TRUE; @@ -263,9 +185,7 @@ static bool32 HandleEndTurnWeatherDamage(u32 battler) && GetBattlerHoldEffect(battler) != HOLD_EFFECT_SAFETY_GOGGLES && !IsAbilityAndRecord(battler, ability, ABILITY_MAGIC_GUARD)) { - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 16; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; + SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / 16); gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_HAIL; BattleScriptExecute(BattleScript_DamagingWeather); effect = TRUE; @@ -277,49 +197,24 @@ static bool32 HandleEndTurnWeatherDamage(u32 battler) return effect; } -static bool32 HandleEndTurnGenThreeBerryActivation(u32 battler) -{ - bool32 effect = FALSE; - - if (B_HP_BERRIES >= GEN_4) // Skip handler for > Gen3 - { - gBattleStruct->endTurnEventsCounter++; - return effect; - } - gBattleStruct->turnEffectsBattlerId++; - effect = TryRestoreHPBerries(battler, ITEMEFFECT_NORMAL); - return effect; -} - static bool32 HandleEndTurnEmergencyExit(u32 battler) { bool32 effect = FALSE; enum Ability ability = GetBattlerAbility(battler); - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; - if (ability == ABILITY_EMERGENCY_EXIT || ability == ABILITY_WIMP_OUT) + if (EmergencyExitCanBeTriggered(battler)) { - u32 cutoff = gBattleMons[battler].maxHP / 2; - bool32 HadMoreThanHalfHpNowDoesnt = gBattleStruct->hpBefore[battler] > cutoff && gBattleMons[battler].hp <= cutoff; + gBattlerAbility = battler; + gLastUsedAbility = ability; - if (HadMoreThanHalfHpNowDoesnt - && IsBattlerAlive(battler) - && (CanBattlerSwitch(battler) || !(gBattleTypeFlags & BATTLE_TYPE_TRAINER)) - && !(gBattleTypeFlags & BATTLE_TYPE_ARENA) - && CountUsablePartyMons(battler) > 0 - && gBattleMons[battler].volatiles.semiInvulnerable != STATE_SKY_DROP) // Not currently held by Sky Drop - { - gBattlerAbility = battler; - gLastUsedAbility = ability; + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + BattleScriptExecute(BattleScript_EmergencyExitEnd2); + else + BattleScriptExecute(BattleScript_EmergencyExitWildEnd2); - if (gBattleTypeFlags & BATTLE_TYPE_TRAINER || IsOnPlayerSide(battler)) - BattleScriptExecute(BattleScript_EmergencyExitEnd2); - else - BattleScriptExecute(BattleScript_EmergencyExitWildEnd2); - - effect = TRUE; - } + effect = TRUE; } return effect; @@ -329,7 +224,7 @@ static bool32 HandleEndTurnAffection(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (!B_AFFECTION_MECHANICS || !IsBattlerAlive(battler) @@ -352,16 +247,10 @@ static bool32 HandleEndTurnFutureSight(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; - if (gWishFutureKnock.futureSightCounter[battler] == gBattleTurnCounter) + if (gWishFutureKnock.futureSightCounter[battler] > 0 && --gWishFutureKnock.futureSightCounter[battler] == 0) { - if (gWishFutureKnock.futureSightCounter[battler] == gBattleTurnCounter - && gWishFutureKnock.futureSightCounter[BATTLE_PARTNER(battler)] <= gBattleTurnCounter) - { - gSideStatuses[GetBattlerSide(battler)] &= ~SIDE_STATUS_FUTUREATTACK; - } - if (!IsBattlerAlive(battler)) return effect; @@ -390,25 +279,26 @@ static bool32 HandleEndTurnWish(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; - if (gWishFutureKnock.wishCounter[battler] == gBattleTurnCounter && IsBattlerAlive(battler)) + if (gWishFutureKnock.wishCounter[battler] > 0 && --gWishFutureKnock.wishCounter[battler] == 0 && IsBattlerAlive(battler)) { + s32 wishHeal = 0; gBattlerTarget = battler; PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, battler, gWishFutureKnock.wishPartyId[battler]) if (B_WISH_HP_SOURCE >= GEN_5) { if (IsOnPlayerSide(battler)) - gBattleStruct->moveDamage[battler] = max(1, GetMonData(&gPlayerParty[gWishFutureKnock.wishPartyId[battler]], MON_DATA_MAX_HP) / 2); + wishHeal = GetMonData(&gPlayerParty[gWishFutureKnock.wishPartyId[battler]], MON_DATA_MAX_HP) / 2; else - gBattleStruct->moveDamage[battler] = max(1, GetMonData(&gEnemyParty[gWishFutureKnock.wishPartyId[battler]], MON_DATA_MAX_HP) / 2); + wishHeal = GetMonData(&gEnemyParty[gWishFutureKnock.wishPartyId[battler]], MON_DATA_MAX_HP) / 2; } else { - gBattleStruct->moveDamage[battler] = max(1, GetNonDynamaxMaxHP(battler) / 2); + wishHeal = GetNonDynamaxMaxHP(battler) / 2; } - gBattleStruct->moveDamage[battler] *= -1; + SetHealAmount(battler, wishHeal); if (gBattleMons[battler].volatiles.healBlock) BattleScriptExecute(BattleScript_WishButHealBlocked); else if (gBattleMons[battler].hp == gBattleMons[battler].maxHP) @@ -429,12 +319,12 @@ static bool32 HandleEndTurnFirstEventBlock(u32 battler) if (!IsBattlerAlive(battler)) { - gBattleStruct->eventBlockCounter = 0; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBlock = 0; + gBattleStruct->eventState.endTurnBattler++; return effect; } - switch (gBattleStruct->eventBlockCounter) + switch (gBattleStruct->eventState.endTurnBlock) { case FIRST_EVENT_BLOCK_GMAX_MOVE_RESIDUAL: // TODO: Has to be split into 3 statuses and needs a queue side = GetBattlerSide(battler); @@ -443,26 +333,25 @@ static bool32 HandleEndTurnFirstEventBlock(u32 battler) if (!IS_BATTLER_OF_TYPE(battler, gSideTimers[side].damageNonTypesType) && !IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD)) { - gBattlerAttacker = battler; - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 6; + SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / 6); ChooseDamageNonTypesString(gSideTimers[side].damageNonTypesType); BattleScriptExecute(BattleScript_DamageNonTypesContinues); effect = TRUE; } } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; case FIRST_EVENT_BLOCK_SEA_OF_FIRE_DAMAGE: if (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SEA_OF_FIRE) { gBattlerAttacker = battler; - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 8; + SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / 8); BtlController_EmitStatusAnimation(battler, B_COMM_TO_CONTROLLER, FALSE, STATUS1_BURN); MarkBattlerForControllerExec(battler); BattleScriptExecute(BattleScript_HurtByTheSeaOfFire); effect = TRUE; } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; case FIRST_EVENT_BLOCK_THRASH: if (gBattleMons[battler].volatiles.lockConfusionTurns && gBattleMons[battler].volatiles.semiInvulnerable != STATE_SKY_DROP) @@ -477,15 +366,14 @@ static bool32 HandleEndTurnFirstEventBlock(u32 battler) gBattleMons[battler].volatiles.multipleTurns = FALSE; if (!gBattleMons[battler].volatiles.confusionTurns) { - gBattleScripting.moveEffect = MOVE_EFFECT_CONFUSION; - SetMoveEffect(battler, battler, TRUE, FALSE); + SetMoveEffect(battler, battler, MOVE_EFFECT_CONFUSION, gBattlescriptCurrInstr, EFFECT_PRIMARY); if (gBattleMons[battler].volatiles.confusionTurns) BattleScriptExecute(BattleScript_ThrashConfuses); effect = TRUE; } } } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; case FIRST_EVENT_BLOCK_GRASSY_TERRAIN_HEAL: if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN @@ -494,14 +382,11 @@ static bool32 HandleEndTurnFirstEventBlock(u32 battler) && !IsSemiInvulnerable(battler, CHECK_ALL) && IsBattlerGrounded(battler, GetBattlerAbility(battler), GetBattlerHoldEffect(battler))) { - gBattlerAttacker = battler; - gBattleStruct->moveDamage[battler] = -(GetNonDynamaxMaxHP(battler) / 16); - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = -1; + SetHealAmount(battler, GetNonDynamaxMaxHP(battler) / 16); BattleScriptExecute(BattleScript_GrassyTerrainHeals); effect = TRUE; } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; case FIRST_EVENT_BLOCK_ABILITIES: { @@ -517,14 +402,14 @@ static bool32 HandleEndTurnFirstEventBlock(u32 battler) default: break; } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; } case FIRST_EVENT_BLOCK_HEAL_ITEMS: - if (ItemBattleEffects(ITEMEFFECT_LEFTOVERS, battler)) + if (ItemBattleEffects(battler, 0, GetBattlerHoldEffect(battler), IsLeftoversActivation)) effect = TRUE; - gBattleStruct->eventBlockCounter = 0; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBlock = 0; + gBattleStruct->eventState.endTurnBattler++; break; } @@ -535,14 +420,14 @@ static bool32 HandleEndTurnAquaRing(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gBattleMons[battler].volatiles.aquaRing && !gBattleMons[battler].volatiles.healBlock && !IsBattlerAtMaxHp(battler) && IsBattlerAlive(battler)) { - gBattleStruct->moveDamage[battler] = GetDrainedBigRootHp(battler, GetNonDynamaxMaxHP(battler) / 16); + SetHealAmount(battler, GetDrainedBigRootHp(battler, GetNonDynamaxMaxHP(battler) / 16)); BattleScriptExecute(BattleScript_AquaRingHeal); effect = TRUE; } @@ -554,14 +439,14 @@ static bool32 HandleEndTurnIngrain(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gBattleMons[battler].volatiles.root && !gBattleMons[battler].volatiles.healBlock && !IsBattlerAtMaxHp(battler) && IsBattlerAlive(battler)) { - gBattleStruct->moveDamage[battler] = GetDrainedBigRootHp(battler, GetNonDynamaxMaxHP(battler) / 16); + SetHealAmount(battler, GetDrainedBigRootHp(battler, GetNonDynamaxMaxHP(battler) / 16)); BattleScriptExecute(BattleScript_IngrainTurnHeal); effect = TRUE; } @@ -573,7 +458,7 @@ static bool32 HandleEndTurnLeechSeed(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gBattleMons[battler].volatiles.leechSeed && IsBattlerAlive(gBattleMons[battler].volatiles.leechSeed - 1) @@ -583,12 +468,12 @@ static bool32 HandleEndTurnLeechSeed(u32 battler) gBattlerTarget = gBattleMons[battler].volatiles.leechSeed - 1; // leech seed receiver gBattleScripting.animArg1 = gBattlerTarget; gBattleScripting.animArg2 = gBattlerAttacker; - gBattleStruct->moveDamage[gBattlerAttacker] = max(1, GetNonDynamaxMaxHP(battler) / 8); - gBattleStruct->moveDamage[gBattlerTarget] = GetDrainedBigRootHp(gBattlerTarget, gBattleStruct->moveDamage[gBattlerAttacker]); - gHitMarker |= HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE; + s32 drainAmount = GetNonDynamaxMaxHP(gBattlerAttacker) / 8; + s32 healAmount = GetDrainedBigRootHp(gBattlerTarget, drainAmount); if (GetBattlerAbility(battler) == ABILITY_LIQUID_OOZE) { - gBattleStruct->moveDamage[gBattlerTarget] = gBattleStruct->moveDamage[gBattlerTarget] * -1; + SetPassiveDamageAmount(gBattlerAttacker, drainAmount); + SetPassiveDamageAmount(gBattlerTarget, healAmount); gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_LEECH_SEED_OOZE; BattleScriptExecute(BattleScript_LeechSeedTurnDrainLiquidOoze); } @@ -598,6 +483,8 @@ static bool32 HandleEndTurnLeechSeed(u32 battler) } else { + SetPassiveDamageAmount(gBattlerAttacker, drainAmount); + SetHealAmount(gBattlerTarget, healAmount); gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_LEECH_SEED_DRAIN; BattleScriptExecute(BattleScript_LeechSeedTurnDrainRecovery); } @@ -613,7 +500,7 @@ static bool32 HandleEndTurnPoison(u32 battler) enum Ability ability = GetBattlerAbility(battler); - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if ((gBattleMons[battler].status1 & STATUS1_POISON || gBattleMons[battler].status1 & STATUS1_TOXIC_POISON) && IsBattlerAlive(battler) @@ -623,30 +510,23 @@ static bool32 HandleEndTurnPoison(u32 battler) { if (!IsBattlerAtMaxHp(battler) && !gBattleMons[battler].volatiles.healBlock) { - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 8; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; - gBattleStruct->moveDamage[battler] *= -1; + SetHealAmount(battler, GetNonDynamaxMaxHP(battler) / 8); BattleScriptExecute(BattleScript_PoisonHealActivates); effect = TRUE; } } else if (gBattleMons[battler].status1 & STATUS1_TOXIC_POISON) { - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 16; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; + SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / 16); if ((gBattleMons[battler].status1 & STATUS1_TOXIC_COUNTER) != STATUS1_TOXIC_TURN(15)) // not 16 turns gBattleMons[battler].status1 += STATUS1_TOXIC_TURN(1); - gBattleStruct->moveDamage[battler] *= (gBattleMons[battler].status1 & STATUS1_TOXIC_COUNTER) >> 8; + gBattleStruct->passiveHpUpdate[battler] *= (gBattleMons[battler].status1 & STATUS1_TOXIC_COUNTER) >> 8; BattleScriptExecute(BattleScript_PoisonTurnDmg); effect = TRUE; } else { - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 8; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; + SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / 8); BattleScriptExecute(BattleScript_PoisonTurnDmg); effect = TRUE; } @@ -661,21 +541,20 @@ static bool32 HandleEndTurnBurn(u32 battler) enum Ability ability = GetBattlerAbility(battler); - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gBattleMons[battler].status1 & STATUS1_BURN && IsBattlerAlive(battler) && !IsAbilityAndRecord(battler, ability, ABILITY_MAGIC_GUARD)) { - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / (B_BURN_DAMAGE >= GEN_7 ? 16 : 8); + s32 burnDamage = GetNonDynamaxMaxHP(battler) / (B_BURN_DAMAGE >= GEN_7 ? 16 : 8); if (ability == ABILITY_HEATPROOF) { - if (gBattleStruct->moveDamage[battler] > (gBattleStruct->moveDamage[battler] / 2) + 1) // Record ability if the burn takes less damage than it normally would. + if (burnDamage > (burnDamage / 2) + 1) // Record ability if the burn takes less damage than it normally would. RecordAbilityBattle(battler, ABILITY_HEATPROOF); - gBattleStruct->moveDamage[battler] /= 2; + burnDamage /= 2; } - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; + SetPassiveDamageAmount(battler, burnDamage); BattleScriptExecute(BattleScript_BurnTurnDmg); effect = TRUE; } @@ -687,15 +566,13 @@ static bool32 HandleEndTurnFrostbite(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gBattleMons[battler].status1 & STATUS1_FROSTBITE && IsBattlerAlive(battler) && !IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD)) { - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / (B_BURN_DAMAGE >= GEN_7 ? 16 : 8); - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; + SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / (B_BURN_DAMAGE >= GEN_7 ? 16 : 8)); BattleScriptExecute(BattleScript_FrostbiteTurnDmg); effect = TRUE; } @@ -707,7 +584,7 @@ static bool32 HandleEndTurnNightmare(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gBattleMons[battler].volatiles.nightmare && IsBattlerAlive(battler) @@ -715,9 +592,7 @@ static bool32 HandleEndTurnNightmare(u32 battler) { if (gBattleMons[battler].status1 & STATUS1_SLEEP) { - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 4; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; + SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / 4); BattleScriptExecute(BattleScript_NightmareTurnDmg); effect = TRUE; } @@ -734,15 +609,13 @@ static bool32 HandleEndTurnCurse(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gBattleMons[battler].volatiles.cursed && IsBattlerAlive(battler) && !IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD)) { - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 4; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; + SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / 4); BattleScriptExecute(BattleScript_CurseTurnDmg); effect = TRUE; } @@ -754,7 +627,7 @@ static bool32 HandleEndTurnWrap(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gBattleMons[battler].volatiles.wrapped && IsBattlerAlive(battler)) { @@ -764,22 +637,21 @@ static bool32 HandleEndTurnWrap(u32 battler) if (IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD)) return effect; - gBattleScripting.animArg1 = gBattleStruct->wrappedMove[battler]; - gBattleScripting.animArg2 = gBattleStruct->wrappedMove[battler] >> 8; - PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleStruct->wrappedMove[battler]); + gBattleScripting.animArg1 = gBattleMons[battler].volatiles.wrappedMove; + gBattleScripting.animArg2 = gBattleMons[battler].volatiles.wrappedMove >> 8; + PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleMons[battler].volatiles.wrappedMove); BattleScriptExecute(BattleScript_WrapTurnDmg); - if (GetBattlerHoldEffect(gBattleStruct->wrappedBy[battler]) == HOLD_EFFECT_BINDING_BAND) - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / (B_BINDING_DAMAGE >= GEN_6 ? 6 : 8); + s32 bindDamage = 0; + if (GetBattlerHoldEffect(gBattleMons[battler].volatiles.wrappedBy) == HOLD_EFFECT_BINDING_BAND) + bindDamage = GetNonDynamaxMaxHP(battler) / (B_BINDING_DAMAGE >= GEN_6 ? 6 : 8); else - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / (B_BINDING_DAMAGE >= GEN_6 ? 8 : 16); - - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; + bindDamage = GetNonDynamaxMaxHP(battler) / (B_BINDING_DAMAGE >= GEN_6 ? 8 : 16); + SetPassiveDamageAmount(battler, bindDamage); } else // broke free { gBattleMons[battler].volatiles.wrapped = FALSE; - PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleStruct->wrappedMove[battler]); + PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleMons[battler].volatiles.wrappedMove); BattleScriptExecute(BattleScript_WrapEnds); } effect = TRUE; @@ -792,18 +664,18 @@ static bool32 HandleEndTurnSaltCure(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gBattleMons[battler].volatiles.saltCure && IsBattlerAlive(battler) && !IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD)) { + s32 saltCureDamage = 0; if (IS_BATTLER_ANY_TYPE(battler, TYPE_STEEL, TYPE_WATER)) - gBattleStruct->moveDamage[battler] = gBattleMons[battler].maxHP / 4; + saltCureDamage = GetNonDynamaxMaxHP(battler) / 4; else - gBattleStruct->moveDamage[battler] = gBattleMons[battler].maxHP / 8; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; + saltCureDamage = GetNonDynamaxMaxHP(battler) / 8; + SetPassiveDamageAmount(battler, saltCureDamage); PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_SALT_CURE); BattleScriptExecute(BattleScript_SaltCureExtraDamage); effect = TRUE; @@ -816,7 +688,7 @@ static bool32 HandleEndTurnOctolock(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gDisableStructs[battler].octolock) { @@ -833,7 +705,7 @@ static bool32 HandleEndTurnSyrupBomb(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gBattleMons[battler].volatiles.syrupBomb && (IsBattlerAlive(battler))) { @@ -852,10 +724,11 @@ static bool32 HandleEndTurnTaunt(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gDisableStructs[battler].tauntTimer && --gDisableStructs[battler].tauntTimer == 0) { + gBattleScripting.battler = battler; BattleScriptExecute(BattleScript_BufferEndTurn); PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_TAUNT); effect = TRUE; @@ -868,11 +741,12 @@ static bool32 HandleEndTurnTorment(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; - if (gDisableStructs[battler].tormentTimer == gBattleTurnCounter) + if (gDisableStructs[battler].tormentTimer > 0 && --gDisableStructs[battler].tormentTimer == 0) { gBattleMons[battler].volatiles.torment = FALSE; + gBattleScripting.battler = battler; BattleScriptExecute(BattleScript_TormentEnds); effect = TRUE; } @@ -884,7 +758,7 @@ static bool32 HandleEndTurnEncore(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gDisableStructs[battler].encoreTimer != 0) { @@ -898,6 +772,7 @@ static bool32 HandleEndTurnEncore(u32 battler) { gDisableStructs[battler].encoredMove = 0; gDisableStructs[battler].encoreTimer = 0; + gBattleScripting.battler = battler; BattleScriptExecute(BattleScript_EncoredNoMore); effect = TRUE; } @@ -911,7 +786,7 @@ static bool32 HandleEndTurnDisable(u32 battler) bool32 effect = FALSE; u32 moveIndex = 0; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gDisableStructs[battler].disableTimer != 0) { @@ -928,6 +803,7 @@ static bool32 HandleEndTurnDisable(u32 battler) else if (--gDisableStructs[battler].disableTimer == 0) // disable ends { gDisableStructs[battler].disabledMove = 0; + gBattleScripting.battler = battler; BattleScriptExecute(BattleScript_DisabledNoMore); effect = TRUE; } @@ -940,9 +816,9 @@ static bool32 HandleEndTurnMagnetRise(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; - if (gBattleMons[battler].volatiles.magnetRise && gDisableStructs[battler].magnetRiseTimer == gBattleTurnCounter) + if (gDisableStructs[battler].magnetRiseTimer > 0 && --gDisableStructs[battler].magnetRiseTimer == 0) { gBattleMons[battler].volatiles.magnetRise = FALSE; BattleScriptExecute(BattleScript_BufferEndTurn); @@ -957,9 +833,9 @@ static bool32 HandleEndTurnTelekinesis(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; - if (gBattleMons[battler].volatiles.telekinesis && gDisableStructs[battler].telekinesisTimer == gBattleTurnCounter) + if (gDisableStructs[battler].telekinesisTimer > 0 && --gDisableStructs[battler].telekinesisTimer == 0) { gBattleMons[battler].volatiles.telekinesis = FALSE; BattleScriptExecute(BattleScript_TelekinesisEndTurn); @@ -973,11 +849,12 @@ static bool32 HandleEndTurnHealBlock(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; - if (gBattleMons[battler].volatiles.healBlock && gDisableStructs[battler].healBlockTimer == gBattleTurnCounter) + if (gDisableStructs[battler].healBlockTimer > 0 && --gDisableStructs[battler].healBlockTimer == 0) { gBattleMons[battler].volatiles.healBlock = FALSE; + gBattleScripting.battler = battler; BattleScriptExecute(BattleScript_BufferEndTurn); PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_HEAL_BLOCK); effect = TRUE; @@ -990,9 +867,9 @@ static bool32 HandleEndTurnEmbargo(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; - if (gBattleMons[battler].volatiles.embargo && gDisableStructs[battler].embargoTimer == gBattleTurnCounter) + if (gDisableStructs[battler].embargoTimer > 0 && --gDisableStructs[battler].embargoTimer == 0) { gBattleMons[battler].volatiles.embargo = FALSE; BattleScriptExecute(BattleScript_EmbargoEndTurn); @@ -1008,7 +885,7 @@ static bool32 HandleEndTurnYawn(u32 battler) enum Ability ability = GetBattlerAbility(battler); - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gBattleMons[battler].volatiles.yawn > 0) { @@ -1021,7 +898,7 @@ static bool32 HandleEndTurnYawn(u32 battler) && !IsLeafGuardProtected(battler, ability)) { gEffectBattler = gBattlerTarget = battler; - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler); + enum HoldEffect holdEffect = GetBattlerHoldEffect(battler); if (IsBattlerTerrainAffected(battler, ability, holdEffect, STATUS_FIELD_ELECTRIC_TERRAIN)) { gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAINPREVENTS_ELECTRIC; @@ -1068,7 +945,7 @@ static bool32 HandleEndTurnPerishSong(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (IsBattlerAlive(battler) && gBattleMons[battler].volatiles.perishSong) { @@ -1076,7 +953,7 @@ static bool32 HandleEndTurnPerishSong(u32 battler) if (gDisableStructs[battler].perishSongTimer == 0) { gBattleMons[battler].volatiles.perishSong = FALSE; - gBattleStruct->moveDamage[battler] = gBattleMons[battler].hp; + SetPassiveDamageAmount(battler, gBattleMons[battler].hp); BattleScriptExecute(BattleScript_PerishSongTakesLife); } else @@ -1094,7 +971,7 @@ static bool32 HandleEndTurnRoost(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gDisableStructs[battler].roostActive) gDisableStructs[battler].roostActive = FALSE; @@ -1106,12 +983,12 @@ static bool32 HandleEndTurnSecondEventBlock(u32 battler) { bool32 effect = FALSE; - u32 side = gBattleStruct->turnSideTracker; + u32 side = gBattleStruct->eventState.battlerSide; - switch (gBattleStruct->eventBlockCounter) + switch (gBattleStruct->eventState.endTurnBlock) { case SECOND_EVENT_BLOCK_REFLECT: - if (gSideStatuses[side] & SIDE_STATUS_REFLECT && gSideTimers[side].reflectTimer == gBattleTurnCounter) + if (gSideTimers[side].reflectTimer > 0 && --gSideTimers[side].reflectTimer == 0) { gBattlerAttacker = GetBattlerSideForMessage(side); gSideStatuses[side] &= ~SIDE_STATUS_REFLECT; @@ -1120,10 +997,10 @@ static bool32 HandleEndTurnSecondEventBlock(u32 battler) PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_REFLECT); effect = TRUE; } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; case SECOND_EVENT_BLOCK_LIGHT_SCREEN: - if (gSideStatuses[side] & SIDE_STATUS_LIGHTSCREEN && gSideTimers[side].lightscreenTimer == gBattleTurnCounter) + if (gSideTimers[side].lightscreenTimer > 0 && --gSideTimers[side].lightscreenTimer == 0) { gBattlerAttacker = GetBattlerSideForMessage(side); gSideStatuses[side] &= ~SIDE_STATUS_LIGHTSCREEN; @@ -1132,20 +1009,20 @@ static bool32 HandleEndTurnSecondEventBlock(u32 battler) PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_LIGHT_SCREEN); effect = TRUE; } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; case SECOND_EVENT_BLOCK_SAFEGUARD: - if (gSideStatuses[side] & SIDE_STATUS_SAFEGUARD && gSideTimers[side].safeguardTimer == gBattleTurnCounter) + if (gSideTimers[side].safeguardTimer > 0 && --gSideTimers[side].safeguardTimer == 0) { gBattlerAttacker = GetBattlerSideForMessage(side); gSideStatuses[side] &= ~SIDE_STATUS_SAFEGUARD; BattleScriptExecute(BattleScript_SafeguardEnds); effect = TRUE; } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; case SECOND_EVENT_BLOCK_MIST: - if (gSideTimers[side].mistTimer != 0 && gSideTimers[side].mistTimer == gBattleTurnCounter) + if (gSideTimers[side].mistTimer > 0 && --gSideTimers[side].mistTimer == 0) { gBattlerAttacker = GetBattlerSideForMessage(side); gSideStatuses[side] &= ~SIDE_STATUS_MIST; @@ -1154,59 +1031,59 @@ static bool32 HandleEndTurnSecondEventBlock(u32 battler) PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_MIST); effect = TRUE; } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; case SECOND_EVENT_BLOCK_TAILWIND: - if (gSideStatuses[side] & SIDE_STATUS_TAILWIND && gSideTimers[side].tailwindTimer == gBattleTurnCounter) + if (gSideTimers[side].tailwindTimer > 0 && --gSideTimers[side].tailwindTimer == 0) { gBattlerAttacker = GetBattlerSideForMessage(side); gSideStatuses[side] &= ~SIDE_STATUS_TAILWIND; BattleScriptExecute(BattleScript_TailwindEnds); effect = TRUE; } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; case SECOND_EVENT_BLOCK_LUCKY_CHANT: - if (gSideStatuses[side] & SIDE_STATUS_LUCKY_CHANT && gSideTimers[side].luckyChantTimer == gBattleTurnCounter) + if (gSideTimers[side].luckyChantTimer > 0 && --gSideTimers[side].luckyChantTimer == 0) { gBattlerAttacker = GetBattlerSideForMessage(side); gSideStatuses[side] &= ~SIDE_STATUS_LUCKY_CHANT; BattleScriptExecute(BattleScript_LuckyChantEnds); effect = TRUE; } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; case SECOND_EVENT_BLOCK_RAINBOW: gBattlerAttacker = GetBattlerSideForMessage(side); - if (gSideStatuses[side] & SIDE_STATUS_RAINBOW && gSideTimers[side].rainbowTimer == gBattleTurnCounter) + if (gSideTimers[side].rainbowTimer > 0 && --gSideTimers[side].rainbowTimer == 0) { gSideStatuses[side] &= ~SIDE_STATUS_RAINBOW; BattleScriptExecute(BattleScript_TheRainbowDisappeared); effect = TRUE; } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; case SECOND_EVENT_BLOCK_SEA_OF_FIRE: - if (gSideStatuses[side] & SIDE_STATUS_SEA_OF_FIRE && gSideTimers[side].seaOfFireTimer == gBattleTurnCounter) + if (gSideTimers[side].seaOfFireTimer > 0 && --gSideTimers[side].seaOfFireTimer == 0) { gSideStatuses[side] &= ~SIDE_STATUS_SEA_OF_FIRE; BattleScriptExecute(BattleScript_TheSeaOfFireDisappeared); effect = TRUE; } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; case SECOND_EVENT_BLOCK_SWAMP: gBattlerAttacker = GetBattlerSideForMessage(side); - if (gSideStatuses[side] & SIDE_STATUS_SWAMP && gSideTimers[side].swampTimer == gBattleTurnCounter) + if (gSideTimers[side].swampTimer > 0 && --gSideTimers[side].swampTimer == 0) { gSideStatuses[side] &= ~SIDE_STATUS_SWAMP; BattleScriptExecute(BattleScript_TheSwampDisappeared); effect = TRUE; } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; case SECOND_EVENT_BLOCK_AURORA_VEIL: - if (gSideStatuses[side] & SIDE_STATUS_AURORA_VEIL && gSideTimers[side].auroraVeilTimer == gBattleTurnCounter) + if (gSideTimers[side].auroraVeilTimer > 0 && --gSideTimers[side].auroraVeilTimer == 0) { gBattlerAttacker = GetBattlerSideForMessage(side); gSideStatuses[side] &= ~SIDE_STATUS_AURORA_VEIL; @@ -1215,8 +1092,8 @@ static bool32 HandleEndTurnSecondEventBlock(u32 battler) PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_AURORA_VEIL); effect = TRUE; } - gBattleStruct->turnSideTracker++; - gBattleStruct->eventBlockCounter = 0; + gBattleStruct->eventState.battlerSide++; + gBattleStruct->eventState.endTurnBlock = 0; break; } @@ -1227,9 +1104,9 @@ static bool32 HandleEndTurnTrickRoom(u32 battler) { bool32 effect = FALSE; - gBattleStruct->endTurnEventsCounter++; + gBattleStruct->eventState.endTurn++; - if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer == gBattleTurnCounter) + if (gFieldTimers.trickRoomTimer > 0 && --gFieldTimers.trickRoomTimer == 0) { gFieldStatuses &= ~STATUS_FIELD_TRICK_ROOM; BattleScriptExecute(BattleScript_TrickRoomEnds); @@ -1243,9 +1120,9 @@ static bool32 HandleEndTurnGravity(u32 battler) { bool32 effect = FALSE; - gBattleStruct->endTurnEventsCounter++; + gBattleStruct->eventState.endTurn++; - if (gFieldStatuses & STATUS_FIELD_GRAVITY && gFieldTimers.gravityTimer == gBattleTurnCounter) + if (gFieldTimers.gravityTimer > 0 && --gFieldTimers.gravityTimer == 0) { gFieldStatuses &= ~STATUS_FIELD_GRAVITY; BattleScriptExecute(BattleScript_GravityEnds); @@ -1259,9 +1136,9 @@ static bool32 HandleEndTurnWaterSport(u32 battler) { bool32 effect = FALSE; - gBattleStruct->endTurnEventsCounter++; + gBattleStruct->eventState.endTurn++; - if (gFieldStatuses & STATUS_FIELD_WATERSPORT && gFieldTimers.waterSportTimer == gBattleTurnCounter) + if (gFieldTimers.waterSportTimer > 0 && --gFieldTimers.waterSportTimer == 0) { gFieldStatuses &= ~STATUS_FIELD_WATERSPORT; BattleScriptExecute(BattleScript_WaterSportEnds); @@ -1275,9 +1152,9 @@ static bool32 HandleEndTurnMudSport(u32 battler) { bool32 effect = FALSE; - gBattleStruct->endTurnEventsCounter++; + gBattleStruct->eventState.endTurn++; - if (gFieldStatuses & STATUS_FIELD_MUDSPORT && gFieldTimers.mudSportTimer == gBattleTurnCounter) + if (gFieldTimers.mudSportTimer > 0 && --gFieldTimers.mudSportTimer == 0) { gFieldStatuses &= ~STATUS_FIELD_MUDSPORT; BattleScriptExecute(BattleScript_MudSportEnds); @@ -1291,9 +1168,9 @@ static bool32 HandleEndTurnWonderRoom(u32 battler) { bool32 effect = FALSE; - gBattleStruct->endTurnEventsCounter++; + gBattleStruct->eventState.endTurn++; - if (gFieldStatuses & STATUS_FIELD_WONDER_ROOM && gFieldTimers.wonderRoomTimer == gBattleTurnCounter) + if (gFieldTimers.wonderRoomTimer > 0 && --gFieldTimers.wonderRoomTimer == 0) { gFieldStatuses &= ~STATUS_FIELD_WONDER_ROOM; BattleScriptExecute(BattleScript_WonderRoomEnds); @@ -1307,9 +1184,9 @@ static bool32 HandleEndTurnMagicRoom(u32 battler) { bool32 effect = FALSE; - gBattleStruct->endTurnEventsCounter++; + gBattleStruct->eventState.endTurn++; - if (gFieldStatuses & STATUS_FIELD_MAGIC_ROOM && gFieldTimers.magicRoomTimer == gBattleTurnCounter) + if (gFieldTimers.magicRoomTimer > 0 && --gFieldTimers.magicRoomTimer == 0) { gFieldStatuses &= ~STATUS_FIELD_MAGIC_ROOM; BattleScriptExecute(BattleScript_MagicRoomEnds); @@ -1321,7 +1198,7 @@ static bool32 HandleEndTurnMagicRoom(u32 battler) static bool32 EndTurnTerrain(u32 terrainFlag, u32 stringTableId) { - if (gFieldStatuses & terrainFlag && gFieldTimers.terrainTimer == gBattleTurnCounter) + if (gFieldTimers.terrainTimer > 0 && --gFieldTimers.terrainTimer == 0) { gFieldStatuses &= ~terrainFlag; TryToRevertMimicryAndFlags(); @@ -1337,7 +1214,7 @@ static bool32 HandleEndTurnTerrain(u32 battler) { bool32 effect = FALSE; - gBattleStruct->endTurnEventsCounter++; + gBattleStruct->eventState.endTurn++; if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) effect = EndTurnTerrain(STATUS_FIELD_ELECTRIC_TERRAIN, B_MSG_TERRAIN_END_ELECTRIC); @@ -1357,11 +1234,11 @@ static bool32 HandleEndTurnThirdEventBlock(u32 battler) if (!IsBattlerAlive(battler)) { - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; return effect; } - switch (gBattleStruct->eventBlockCounter) + switch (gBattleStruct->eventState.endTurnBlock) { case THIRD_EVENT_BLOCK_UPROAR: if (gBattleMons[battler].volatiles.uproarTurns) @@ -1404,7 +1281,7 @@ static bool32 HandleEndTurnThirdEventBlock(u32 battler) effect = TRUE; } } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; case THIRD_EVENT_BLOCK_ABILITIES: { @@ -1426,29 +1303,30 @@ static bool32 HandleEndTurnThirdEventBlock(u32 battler) default: break; } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; } case THIRD_EVENT_BLOCK_ITEMS: { - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler); + // TODO: simplify + enum HoldEffect holdEffect = GetBattlerHoldEffect(battler); switch (holdEffect) { case HOLD_EFFECT_FLAME_ORB: case HOLD_EFFECT_STICKY_BARB: case HOLD_EFFECT_TOXIC_ORB: - if (ItemBattleEffects(ITEMEFFECT_ORBS, battler)) + if (ItemBattleEffects(battler, 0, holdEffect, IsOrbsActivation)) effect = TRUE; break; case HOLD_EFFECT_WHITE_HERB: - if (ItemBattleEffects(ITEMEFFECT_WHITE_HERB_ENDTURN, battler)) + if (ItemBattleEffects(battler, 0, holdEffect, IsWhiteHerbEndTurnActivation)) effect = TRUE; break; default: break; } - gBattleStruct->eventBlockCounter = 0; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBlock = 0; + gBattleStruct->eventState.endTurnBattler++; break; } } @@ -1456,13 +1334,13 @@ static bool32 HandleEndTurnThirdEventBlock(u32 battler) return effect; } -static bool32 HandleEndTurnAbilities(u32 battler) +static bool32 HandleEndTurnFormChangeAbilities(u32 battler) { bool32 effect = FALSE; enum Ability ability = GetBattlerAbility(battler); - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; switch (ability) { @@ -1470,6 +1348,7 @@ static bool32 HandleEndTurnAbilities(u32 battler) case ABILITY_SCHOOLING: case ABILITY_SHIELDS_DOWN: case ABILITY_ZEN_MODE: + case ABILITY_HUNGER_SWITCH: if (AbilityBattleEffects(ABILITYEFFECT_ENDTURN, battler, ability, 0, MOVE_NONE)) effect = TRUE; default: @@ -1479,47 +1358,19 @@ static bool32 HandleEndTurnAbilities(u32 battler) return effect; } -static bool32 HandleEndTurnFourthEventBlock(u32 battler) +static bool32 HandleEndTurnEjectPack(u32 battler) { - bool32 effect = FALSE; - - switch (gBattleStruct->eventBlockCounter) - { - case FOURTH_EVENT_BLOCK_HUNGER_SWITCH: - { - enum Ability ability = GetBattlerAbility(battler); - if (ability == ABILITY_HUNGER_SWITCH) - { - if (AbilityBattleEffects(ABILITYEFFECT_ENDTURN, battler, ability, 0, MOVE_NONE)) - effect = TRUE; - } - gBattleStruct->eventBlockCounter++; - break; - } - case FOURTH_EVENT_BLOCK_EJECT_PACK: - { - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler); - if (holdEffect == HOLD_EFFECT_EJECT_PACK) - { - if (ItemBattleEffects(ITEMEFFECT_NORMAL, battler)) - effect = TRUE; - } - gBattleStruct->eventBlockCounter = 0; - gBattleStruct->turnEffectsBattlerId++; - break; - } - } - - return effect; + gBattleStruct->eventState.endTurn++; + return TrySwitchInEjectPack(END_TURN); } static bool32 HandleEndTurnDynamax(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; - if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX && gBattleStruct->dynamax.dynamaxTurns[battler] == gBattleTurnCounter) + if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX && gBattleStruct->dynamax.dynamaxTurns[battler] > 0 && --gBattleStruct->dynamax.dynamaxTurns[battler] == 0) { gBattleScripting.battler = battler; UndoDynamax(battler); @@ -1549,7 +1400,6 @@ static bool32 (*const sEndTurnEffectHandlers[])(u32 battler) = [ENDTURN_VARIOUS] = HandleEndTurnVarious, [ENDTURN_WEATHER] = HandleEndTurnWeather, [ENDTURN_WEATHER_DAMAGE] = HandleEndTurnWeatherDamage, - [ENDTURN_GEN_3_BERRY_ACTIVATION] = HandleEndTurnGenThreeBerryActivation, [ENDTURN_EMERGENCY_EXIT_1] = HandleEndTurnEmergencyExit, [ENDTURN_AFFECTION] = HandleEndTurnAffection, [ENDTURN_FUTURE_SIGHT] = HandleEndTurnFutureSight, @@ -1590,37 +1440,33 @@ static bool32 (*const sEndTurnEffectHandlers[])(u32 battler) = [ENDTURN_TERRAIN] = HandleEndTurnTerrain, [ENDTURN_THIRD_EVENT_BLOCK] = HandleEndTurnThirdEventBlock, [ENDTURN_EMERGENCY_EXIT_4] = HandleEndTurnEmergencyExit, - [ENDTURN_ABILITIES] = HandleEndTurnAbilities, - [ENDTURN_FOURTH_EVENT_BLOCK] = HandleEndTurnFourthEventBlock, + [ENDTURN_FORM_CHANGE_ABILITIES] = HandleEndTurnFormChangeAbilities, + [ENDTURN_EJECT_PACK] = HandleEndTurnEjectPack, [ENDTURN_DYNAMAX] = HandleEndTurnDynamax, }; u32 DoEndTurnEffects(void) { u32 battler = MAX_BATTLERS_COUNT; - gHitMarker |= (HITMARKER_GRUDGE | HITMARKER_IGNORE_BIDE); for (;;) { // If either turnEffectsBattlerId or turnSideTracker are at max count, reest values and go to the next state - if (gBattleStruct->turnEffectsBattlerId == gBattlersCount || gBattleStruct->turnSideTracker == NUM_BATTLE_SIDES) + if (gBattleStruct->eventState.endTurnBattler == gBattlersCount || gBattleStruct->eventState.battlerSide == NUM_BATTLE_SIDES) { - gBattleStruct->turnEffectsBattlerId = 0; - gBattleStruct->turnSideTracker = 0; - gBattleStruct->eventBlockCounter = 0; - gBattleStruct->endTurnEventsCounter++; + gBattleStruct->eventState.endTurnBattler = 0; + gBattleStruct->eventState.battlerSide = 0; + gBattleStruct->eventState.endTurnBlock = 0; + gBattleStruct->eventState.endTurn++; } // Jump out if possible after endTurnEventsCounter was increased in the above code block - if (gBattleStruct->endTurnEventsCounter == ENDTURN_COUNT) - { - gHitMarker &= ~(HITMARKER_GRUDGE | HITMARKER_IGNORE_BIDE); + if (gBattleStruct->eventState.endTurn == ENDTURN_COUNT) return FALSE; - } - battler = gBattlerAttacker = gBattlerByTurnOrder[gBattleStruct->turnEffectsBattlerId]; + battler = gBattlerAttacker = gBattlerByTurnOrder[gBattleStruct->eventState.endTurnBattler]; - if (sEndTurnEffectHandlers[gBattleStruct->endTurnEventsCounter](battler)) + if (sEndTurnEffectHandlers[gBattleStruct->eventState.endTurn](battler)) return TRUE; } } diff --git a/src/battle_hold_effects.c b/src/battle_hold_effects.c new file mode 100644 index 000000000..d262e024a --- /dev/null +++ b/src/battle_hold_effects.c @@ -0,0 +1,1271 @@ +#include "global.h" +#include "battle.h" +#include "battle_anim.h" +#include "battle_ai_util.h" // maybe move some stuff over to battle.h +#include "battle_controllers.h" +#include "battle_util.h" +#include "battle_hold_effects.h" +#include "battle_scripts.h" +#include "item.h" +#include "string_util.h" +#include "data/hold_effects.h" +#include "constants/berry.h" + +bool32 IsOnSwitchInActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].onSwitchIn; } +bool32 IsOnSwitchInFirstTurnActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].onSwitchInFirstTurn; } +bool32 IsMirrorHerbActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].mirrorHerb; } +bool32 IsMirrorHerbFirstTurnActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].mirrorHerbFirstTurn; } +bool32 IsWhiteHerbActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].whiteHerb; } +bool32 IsWhiteHerbFirstTurnActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].whiteHerbFirstTurn; } +bool32 IsWhiteHerbEndTurnActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].whiteHerbEndTurn; } +bool32 IsOnStatusChangeActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].onStatusChange; } +bool32 IsOnHpThresholdActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].onHpThreshold; } +bool32 IsKeeMarangaBerryActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].keeMarangaBerry; } +bool32 IsOnTargetHitActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].onTargetAfterHit; } +bool32 IsOnAttackerAfterHitActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].onAttackerAfterHit; } +bool32 IsLifeOrbShellBellActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].lifeOrbShellBell; } +bool32 IsLeftoversActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].leftovers; } +bool32 IsOrbsActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].orbs; } +bool32 IsOnEffectActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].onEffect; } +bool32 IsOnBerryActivation(enum HoldEffect holdEffect) { return GetItemPocket(gLastUsedItem) == POCKET_BERRIES; } +bool32 IsOnFlingActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].onFling; } + +bool32 IsForceTriggerItemActivation(enum HoldEffect holdEffect) +{ + return gHoldEffectsInfo[holdEffect].onSwitchIn + || gHoldEffectsInfo[holdEffect].whiteHerb + || gHoldEffectsInfo[holdEffect].onStatusChange + || gHoldEffectsInfo[holdEffect].onHpThreshold; +} + +static enum ItemEffect TryDoublePrize(u32 battler) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (IsOnPlayerSide(battler) && !gBattleStruct->moneyMultiplierItem) + { + gBattleStruct->moneyMultiplier *= 2; + gBattleStruct->moneyMultiplierItem = TRUE; + } + + return effect; +} + +enum ItemEffect TryBoosterEnergy(u32 battler, enum Ability ability, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (gDisableStructs[battler].boosterEnergyActivated || gBattleMons[battler].volatiles.transformed) + return ITEM_NO_EFFECT; + + if (((ability == ABILITY_PROTOSYNTHESIS) && !((gBattleWeather & B_WEATHER_SUN) && HasWeatherEffect())) + || ((ability == ABILITY_QUARK_DRIVE) && !(gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN))) + { + PREPARE_STAT_BUFFER(gBattleTextBuff1, GetHighestStatId(battler)); + gBattlerAbility = gBattleScripting.battler = battler; + gDisableStructs[battler].boosterEnergyActivated = TRUE; + RecordAbilityBattle(battler, ability); + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_BoosterEnergyEnd2); + else + BattleScriptCall(BattleScript_BoosterEnergyRet); + effect = ITEM_EFFECT_OTHER; + } + + return effect; +} + +static enum ItemEffect TryRoomService(u32 battler, ActivationTiming timing) +{ + if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && CompareStat(battler, STAT_SPEED, MIN_STAT_STAGE, CMP_GREATER_THAN, GetBattlerAbility(battler))) + { + gEffectBattler = gBattleScripting.battler = battler; + SET_STATCHANGER(STAT_SPEED, 1, TRUE); + gBattleScripting.animArg1 = STAT_ANIM_PLUS1 + STAT_SPEED; + gBattleScripting.animArg2 = 0; + + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_ConsumableStatRaiseEnd2); + else + BattleScriptCall(BattleScript_ConsumableStatRaiseRet); + + return ITEM_STATS_CHANGE; + } + + return ITEM_NO_EFFECT; +} + +enum ItemEffect TryHandleSeed(u32 battler, u32 terrainFlag, enum Stat statId, ActivationTiming timing) +{ + if (gFieldStatuses & terrainFlag && CompareStat(battler, statId, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(battler))) + { + gEffectBattler = gBattleScripting.battler = battler; + SET_STATCHANGER(statId, 1, FALSE); + gBattleScripting.animArg1 = STAT_ANIM_PLUS1 + statId; + gBattleScripting.animArg2 = 0; + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_ConsumableStatRaiseEnd2); + else + BattleScriptCall(BattleScript_ConsumableStatRaiseRet); + return ITEM_STATS_CHANGE; + } + return ITEM_NO_EFFECT; +} + +static enum ItemEffect TryTerrainSeeds(u32 battler, u32 item, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + switch (GetItemHoldEffectParam(item)) + { + case HOLD_EFFECT_PARAM_ELECTRIC_TERRAIN: + effect = TryHandleSeed(battler, STATUS_FIELD_ELECTRIC_TERRAIN, STAT_DEF, timing); + break; + case HOLD_EFFECT_PARAM_GRASSY_TERRAIN: + effect = TryHandleSeed(battler, STATUS_FIELD_GRASSY_TERRAIN, STAT_DEF, timing); + break; + case HOLD_EFFECT_PARAM_MISTY_TERRAIN: + effect = TryHandleSeed(battler, STATUS_FIELD_MISTY_TERRAIN, STAT_SPDEF, timing); + break; + case HOLD_EFFECT_PARAM_PSYCHIC_TERRAIN: + effect = TryHandleSeed(battler, STATUS_FIELD_PSYCHIC_TERRAIN, STAT_SPDEF, timing); + break; + } + + return effect; +} + +static bool32 CanBeInfinitelyConfused(u32 battler) +{ + enum Ability ability = GetBattlerAbility(battler); + if (ability == ABILITY_OWN_TEMPO + || IsBattlerTerrainAffected(battler, ability, GetBattlerHoldEffect(battler), STATUS_FIELD_MISTY_TERRAIN) + || gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD) + return FALSE; + return TRUE; +} + +static enum ItemEffect TryBerserkGene(u32 battler, ActivationTiming timing) +{ + if (CanBeInfinitelyConfused(battler)) + gBattleMons[battler].volatiles.infiniteConfusion = TRUE; + + SET_STATCHANGER(STAT_ATK, 2, FALSE); + gBattleScripting.animArg1 = STAT_ANIM_PLUS1 + STAT_ATK; + gBattleScripting.animArg2 = 0; + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_BerserkGeneRetEnd2); + else + BattleScriptCall(BattleScript_BerserkGeneRet); + + return ITEM_STATS_CHANGE; +} + +static enum ItemEffect RestoreWhiteHerbStats(u32 battler, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + for (u32 i = 0; i < NUM_BATTLE_STATS; i++) + { + if (gBattleMons[battler].statStages[i] < DEFAULT_STAT_STAGE) + { + gBattleMons[battler].statStages[i] = DEFAULT_STAT_STAGE; + effect = ITEM_STATS_CHANGE; + } + } + if (effect != ITEM_NO_EFFECT) + { + if (timing == IsWhiteHerbActivation || timing == IsOnFlingActivation) + BattleScriptCall(BattleScript_WhiteHerbRet); + else + BattleScriptExecute(BattleScript_WhiteHerbEnd2); + } + + return effect; +} + +static enum ItemEffect TryConsumeMirrorHerb(u32 battler, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (gProtectStructs[battler].eatMirrorHerb) + { + gProtectStructs[battler].eatMirrorHerb = 0; + ChooseStatBoostAnimation(battler); + if (timing == IsMirrorHerbFirstTurnActivation) + BattleScriptExecute(BattleScript_MirrorHerbCopyStatChangeEnd2); + else + BattleScriptCall(BattleScript_MirrorHerbCopyStatChange); + effect = ITEM_STATS_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryKingsRock(u32 battlerAtk, u32 battlerDef, u32 item) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + enum Ability ability = GetBattlerAbility(battlerAtk); + u32 holdEffectParam = GetItemHoldEffectParam(item); + + if (B_SERENE_GRACE_BOOST >= GEN_5 && ability == ABILITY_SERENE_GRACE) + holdEffectParam *= 2; + if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_RAINBOW && gCurrentMove != MOVE_SECRET_POWER) + holdEffectParam *= 2; + if (IsBattlerTurnDamaged(battlerDef) + && !MoveIgnoresKingsRock(gCurrentMove) + && IsBattlerAlive(battlerDef) + && RandomPercentage(RNG_HOLD_EFFECT_FLINCH, holdEffectParam) + && ability != ABILITY_STENCH) + { + SetMoveEffect(battlerAtk, battlerDef, MOVE_EFFECT_FLINCH, gBattlescriptCurrInstr, NO_FLAGS); + effect = ITEM_EFFECT_OTHER; + } + + return effect; +} + +static enum ItemEffect TryAirBalloon(u32 battler, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (timing == IsOnTargetHitActivation) + { + if (IsBattlerTurnDamaged(battler)) + { + BattleScriptCall(BattleScript_AirBalloonMsgPop); + effect = ITEM_EFFECT_OTHER; + } + } + else if (!gSpecialStatuses[battler].switchInItemDone) + { + gSpecialStatuses[battler].switchInItemDone = TRUE; + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptPushCursorAndCallback(BattleScript_AirBalloonMsgIn); + else + BattleScriptCall(BattleScript_AirBalloonMsgInRet); + RecordItemEffectBattle(battler, HOLD_EFFECT_AIR_BALLOON); + effect = ITEM_EFFECT_OTHER; + } + + return effect; +} + +static enum ItemEffect TryRockyHelmet(u32 battlerDef, u32 battlerAtk, u32 item) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + enum Ability ability = GetBattlerAbility(battlerAtk); + + if (IsBattlerTurnDamaged(battlerDef) + && IsBattlerAlive(battlerAtk) + && !CanBattlerAvoidContactEffects(battlerAtk, battlerDef, ability, GetBattlerHoldEffect(battlerAtk), gCurrentMove) + && !IsAbilityAndRecord(battlerAtk, ability, ABILITY_MAGIC_GUARD)) + { + SetPassiveDamageAmount(battlerAtk, GetNonDynamaxMaxHP(battlerAtk) / 6); + PREPARE_ITEM_BUFFER(gBattleTextBuff1, item); + BattleScriptCall(BattleScript_RockyHelmetActivates); + effect = ITEM_HP_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryWeaknessPolicy(u32 battlerDef) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (IsBattlerAlive(battlerDef) + && IsBattlerTurnDamaged(battlerDef) + && gBattleStruct->moveResultFlags[battlerDef] & MOVE_RESULT_SUPER_EFFECTIVE) + { + BattleScriptCall(BattleScript_WeaknessPolicy); + effect = ITEM_STATS_CHANGE; + } + + return effect; +} + +static enum ItemEffect TrySnowball(u32 battlerDef) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (IsBattlerAlive(battlerDef) + && IsBattlerTurnDamaged(battlerDef) + && GetBattleMoveType(gCurrentMove) == TYPE_ICE) + { + BattleScriptCall(BattleScript_TargetItemStatRaise); + SET_STATCHANGER(STAT_ATK, 1, FALSE); + effect = ITEM_STATS_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryLuminousMoss(u32 battlerDef) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (IsBattlerAlive(battlerDef) + && IsBattlerTurnDamaged(battlerDef) + && GetBattleMoveType(gCurrentMove) == TYPE_WATER) + { + BattleScriptCall(BattleScript_TargetItemStatRaise); + SET_STATCHANGER(STAT_SPDEF, 1, FALSE); + effect = ITEM_STATS_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryCellBattery(u32 battlerDef) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (IsBattlerAlive(battlerDef) + && IsBattlerTurnDamaged(battlerDef) + && GetBattleMoveType(gCurrentMove) == TYPE_ELECTRIC) + { + BattleScriptCall(BattleScript_TargetItemStatRaise); + SET_STATCHANGER(STAT_ATK, 1, FALSE); + effect = ITEM_STATS_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryAbsorbBulb(u32 battlerDef) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (IsBattlerAlive(battlerDef) + && IsBattlerTurnDamaged(battlerDef) + && GetBattleMoveType(gCurrentMove) == TYPE_WATER) + { + effect = ITEM_STATS_CHANGE; + BattleScriptCall(BattleScript_TargetItemStatRaise); + SET_STATCHANGER(STAT_SPATK, 1, FALSE); + } + + return effect; +} + +static enum ItemEffect TryJabocaBerry(u32 battlerDef, u32 battlerAtk, u32 item) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (IsBattlerAlive(battlerAtk) + && IsBattlerTurnDamaged(battlerDef) + && !DoesSubstituteBlockMove(battlerAtk, battlerDef, gCurrentMove) + && IsBattleMovePhysical(gCurrentMove) + && !IsAbilityAndRecord(battlerAtk, GetBattlerAbility(battlerAtk), ABILITY_MAGIC_GUARD)) + { + s32 jabocaDamage = GetNonDynamaxMaxHP(battlerAtk) / 8; + if (GetBattlerAbility(battlerDef) == ABILITY_RIPEN) + jabocaDamage *= 2; + SetPassiveDamageAmount(battlerAtk, jabocaDamage); + BattleScriptCall(BattleScript_JabocaRowapBerryActivates); + PREPARE_ITEM_BUFFER(gBattleTextBuff1, item); + effect = ITEM_HP_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryRowapBerry(u32 battlerDef, u32 battlerAtk, u32 item) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (IsBattlerAlive(battlerAtk) + && IsBattlerTurnDamaged(battlerDef) + && !DoesSubstituteBlockMove(battlerAtk, battlerDef, gCurrentMove) + && IsBattleMoveSpecial(gCurrentMove) + && !IsAbilityAndRecord(battlerAtk, GetBattlerAbility(battlerAtk), ABILITY_MAGIC_GUARD)) + { + s32 rowapDamage = GetNonDynamaxMaxHP(battlerAtk) / 8; + if (GetBattlerAbility(battlerDef) == ABILITY_RIPEN) + rowapDamage *= 2; + SetPassiveDamageAmount(battlerAtk, rowapDamage); + BattleScriptCall(BattleScript_JabocaRowapBerryActivates); + PREPARE_ITEM_BUFFER(gBattleTextBuff1, item); + effect = ITEM_HP_CHANGE; + } + + return effect; +} + +static enum ItemEffect TrySetEnigmaBerry(u32 battlerDef, u32 battlerAtk) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (IsBattlerAlive(battlerDef) + && !DoesSubstituteBlockMove(battlerAtk, battlerDef, gCurrentMove) + && ((IsBattlerTurnDamaged(battlerDef) && gBattleStruct->moveResultFlags[battlerDef] & MOVE_RESULT_SUPER_EFFECTIVE) || gBattleScripting.overrideBerryRequirements) + && !(gBattleScripting.overrideBerryRequirements && gBattleMons[battlerDef].hp == gBattleMons[battlerDef].maxHP) + && !(B_HEAL_BLOCKING >= GEN_5 && gBattleMons[battlerDef].volatiles.healBlock)) + { + s32 healAmount = gBattleMons[battlerDef].maxHP * 25 / 100; + if (GetBattlerAbility(battlerDef) == ABILITY_RIPEN) + healAmount *= 2; + SetHealAmount(battlerDef, healAmount); + BattleScriptCall(BattleScript_ItemHealHP_RemoveItemRet); + effect = ITEM_HP_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryBlunderPolicy(u32 battlerAtk) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (gBattleStruct->blunderPolicy + && IsBattlerAlive(battlerAtk) + && CompareStat(battlerAtk, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(battlerAtk))) + { + gBattleStruct->blunderPolicy = FALSE; + SET_STATCHANGER(STAT_SPEED, 2, FALSE); + BattleScriptCall(BattleScript_AttackerItemStatRaise); + effect = ITEM_STATS_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryMentalHerb(u32 battler) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + // Check infatuation + if (gBattleMons[battler].volatiles.infatuation) + { + gBattleMons[battler].volatiles.infatuation = 0; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_INFATUATION; + StringCopy(gBattleTextBuff1, gStatusConditionString_LoveJpn); + effect = ITEM_EFFECT_OTHER; + } + if (B_MENTAL_HERB >= GEN_5) + { + // Check taunt + if (gDisableStructs[battler].tauntTimer != 0) + { + gDisableStructs[battler].tauntTimer = 0; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_TAUNT; + PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_TAUNT); + effect = ITEM_EFFECT_OTHER; + } + // Check encore + if (gDisableStructs[battler].encoreTimer != 0) + { + gDisableStructs[battler].encoredMove = 0; + gDisableStructs[battler].encoreTimer = 0; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_ENCORE; + effect = ITEM_EFFECT_OTHER; + } + // Check torment + if (gBattleMons[battler].volatiles.torment == TRUE) + { + gBattleMons[battler].volatiles.torment = FALSE; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_TORMENT; + effect = ITEM_EFFECT_OTHER; + } + // Check heal block + if (gBattleMons[battler].volatiles.healBlock) + { + gBattleMons[battler].volatiles.healBlock = FALSE; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_HEALBLOCK; + effect = ITEM_EFFECT_OTHER; + } + // Check disable + if (gDisableStructs[battler].disableTimer != 0) + { + gDisableStructs[battler].disableTimer = 0; + gDisableStructs[battler].disabledMove = 0; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_DISABLE; + effect = ITEM_EFFECT_OTHER; + } + } + + if (effect) + BattleScriptCall(BattleScript_MentalHerbCureRet); + + return effect; +} + +static enum ItemEffect TryThroatSpray(u32 battlerAtk) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (IsSoundMove(gCurrentMove) + && gMultiHitCounter == 0 + && IsBattlerAlive(battlerAtk) + && IsAnyTargetTurnDamaged(battlerAtk) + && CompareStat(battlerAtk, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(battlerAtk)) + && !NoAliveMonsForEitherParty()) // Don't activate if battle will end + { + SET_STATCHANGER(STAT_SPATK, 1, FALSE); + BattleScriptCall(BattleScript_AttackerItemStatRaise); + effect = ITEM_STATS_CHANGE; + } + + return effect; +} + +static enum ItemEffect DamagedStatBoostBerryEffect(u32 battlerDef, u32 battlerAtk, enum Stat statId, enum DamageCategory category) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (!IsBattlerAlive(battlerDef) || !CompareStat(battlerDef, statId, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(battlerDef))) + return effect; + + if (gBattleScripting.overrideBerryRequirements + || (!DoesSubstituteBlockMove(battlerAtk, battlerDef, gCurrentMove) + && GetBattleMoveCategory(gCurrentMove) == category + && IsBattlerTurnDamaged(battlerDef))) + { + if (GetBattlerAbility(battlerDef) == ABILITY_RIPEN) + SET_STATCHANGER(statId, 2, FALSE); + else + SET_STATCHANGER(statId, 1, FALSE); + + gBattleScripting.animArg1 = STAT_ANIM_PLUS1 + statId; + gBattleScripting.animArg2 = 0; + BattleScriptCall(BattleScript_ConsumableStatRaiseRet); + effect = ITEM_STATS_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryShellBell(u32 battlerAtk) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (gBattleScripting.savedDmg > 0 + && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) + && (IsAnyTargetTurnDamaged(battlerAtk) || gBattleScripting.savedDmg > 0) + && !IsBattlerAtMaxHp(battlerAtk) + && IsBattlerAlive(battlerAtk) + && GetMoveEffect(gCurrentMove) != EFFECT_PAIN_SPLIT + && !IsFutureSightAttackerInParty(battlerAtk, gBattlerTarget, gCurrentMove) + && !(B_HEAL_BLOCKING >= GEN_5 && gBattleMons[battlerAtk].volatiles.healBlock)) + { + SetHealAmount(battlerAtk, gBattleScripting.savedDmg / GetBattlerHoldEffectParam(battlerAtk)); + BattleScriptCall(BattleScript_ItemHealHP_Ret); + effect = ITEM_HP_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryLifeOrb(u32 battlerAtk) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (IsBattlerAlive(battlerAtk) + && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) + && (IsAnyTargetTurnDamaged(battlerAtk) || gBattleScripting.savedDmg > 0) + && !IsAbilityAndRecord(battlerAtk, GetBattlerAbility(battlerAtk), ABILITY_MAGIC_GUARD) + && GetMoveEffect(gCurrentMove) != EFFECT_PAIN_SPLIT + && !IsFutureSightAttackerInParty(battlerAtk, gBattlerTarget, gCurrentMove)) + { + SetPassiveDamageAmount(battlerAtk, GetNonDynamaxMaxHP(battlerAtk) / 10); + BattleScriptCall(BattleScript_ItemHurtRet); + effect = ITEM_HP_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryStickyBarbOnTargetHit(u32 battlerDef, u32 battlerAtk, u32 item) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (IsBattlerTurnDamaged(battlerDef) + && !CanBattlerAvoidContactEffects(battlerAtk, battlerDef, GetBattlerAbility(battlerAtk), GetBattlerHoldEffect(battlerAtk), gCurrentMove) + && !DoesSubstituteBlockMove(battlerAtk, battlerDef, gCurrentMove) + && IsBattlerAlive(battlerAtk) + && CanStealItem(battlerAtk, battlerDef, item) + && gBattleMons[battlerAtk].item == ITEM_NONE) + { + // No sticky hold checks. + gEffectBattler = battlerDef; + StealTargetItem(battlerAtk, battlerDef); // Attacker takes target's barb + BattleScriptCall(BattleScript_StickyBarbTransfer); + effect = ITEM_EFFECT_OTHER; + } + + return effect; +} + +static enum ItemEffect TryStickyBarbOnEndTurn(u32 battler, u32 item) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (!IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD)) + { + SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / 8); + PREPARE_ITEM_BUFFER(gBattleTextBuff1, item); + BattleScriptExecute(BattleScript_ItemHurtEnd2); + effect = ITEM_HP_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryToxicOrb(u32 battler) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + enum Ability ability = GetBattlerAbility(battler); + + if (CanBePoisoned(battler, battler, ability, ability)) // Can corrosion trigger toxic orb on itself? + { + gBattleMons[battler].status1 = STATUS1_TOXIC_POISON; + BattleScriptExecute(BattleScript_ToxicOrb); + effect = ITEM_STATUS_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryFlameOrb(u32 battler) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + enum Ability ability = GetBattlerAbility(battler); + + if (CanBeBurned(battler, battler, ability)) + { + gBattleMons[battler].status1 = STATUS1_BURN; + BattleScriptExecute(BattleScript_FlameOrb); + effect = ITEM_STATUS_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryLeftovers(u32 battler, enum HoldEffect holdEffect) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (gBattleMons[battler].hp < gBattleMons[battler].maxHP + && !(B_HEAL_BLOCKING >= GEN_5 && gBattleMons[battler].volatiles.healBlock)) + { + SetHealAmount(battler, GetNonDynamaxMaxHP(battler) / 16); + RecordItemEffectBattle(battler, holdEffect); + BattleScriptExecute(BattleScript_ItemHealHP_End2); + effect = ITEM_HP_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryBlackSludgeDamage(u32 battler, enum HoldEffect holdEffect) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (!IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD)) + { + SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / 8); + RecordItemEffectBattle(battler, holdEffect); + BattleScriptExecute(BattleScript_ItemHurtEnd2); + effect = ITEM_HP_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryCureParalysis(u32 battler, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (gBattleMons[battler].status1 & STATUS1_PARALYSIS) + { + gBattleMons[battler].status1 &= ~STATUS1_PARALYSIS; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_CURED_PARALYSIS; + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_BerryCureStatusEnd2); + else + BattleScriptCall(BattleScript_BerryCureStatusRet); + effect = ITEM_STATUS_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryCurePoison(u32 battler, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (gBattleMons[battler].status1 & STATUS1_PSN_ANY) + { + gBattleMons[battler].status1 &= ~(STATUS1_PSN_ANY | STATUS1_TOXIC_COUNTER); + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_CURED_POISON; + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_BerryCureStatusEnd2); + else + BattleScriptCall(BattleScript_BerryCureStatusRet); + effect = ITEM_STATUS_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryCureBurn(u32 battler, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (gBattleMons[battler].status1 & STATUS1_BURN) + { + gBattleMons[battler].status1 &= ~STATUS1_BURN; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_CURED_BURN; + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_BerryCureStatusEnd2); + else + BattleScriptCall(BattleScript_BerryCureStatusRet); + effect = ITEM_STATUS_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryCureFreezeOrFrostbite(u32 battler, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (gBattleMons[battler].status1 & STATUS1_FREEZE) + { + gBattleMons[battler].status1 &= ~STATUS1_FREEZE; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_CURED_FREEEZE; + effect = ITEM_STATUS_CHANGE; + } + else if (gBattleMons[battler].status1 & STATUS1_FROSTBITE) + { + gBattleMons[battler].status1 &= ~STATUS1_FROSTBITE; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_CURED_FROSTBITE; + effect = ITEM_STATUS_CHANGE; + } + + if (effect == ITEM_STATUS_CHANGE) + { + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_BerryCureStatusEnd2); + else + BattleScriptCall(BattleScript_BerryCureStatusRet); + } + + return effect; +} + +static enum ItemEffect TryCureSleep(u32 battler, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (gBattleMons[battler].status1 & STATUS1_SLEEP) + { + gBattleMons[battler].status1 &= ~STATUS1_SLEEP; + gBattleMons[battler].volatiles.nightmare = FALSE; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_CURED_SLEEP; + TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]); + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_BerryCureStatusEnd2); + else + BattleScriptCall(BattleScript_BerryCureStatusRet); + effect = ITEM_STATUS_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryCureConfusion(u32 battler, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (gBattleMons[battler].volatiles.confusionTurns > 0) + { + RemoveConfusionStatus(battler); + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_BerryCureConfusionEnd2); + else + BattleScriptCall(BattleScript_BerryCureConfusionRet); + effect = ITEM_EFFECT_OTHER; + } + + return effect; +} + +static enum ItemEffect TryCureAnyStatus(u32 battler, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + u32 string = 0; + + if ((gBattleMons[battler].status1 & STATUS1_ANY || gBattleMons[battler].volatiles.confusionTurns > 0)) + { + if (gBattleMons[battler].status1 & STATUS1_PSN_ANY) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn); + string++; + } + if (gBattleMons[battler].status1 & STATUS1_SLEEP) + { + gBattleMons[battler].volatiles.nightmare = FALSE; + StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn); + TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]); + string++; + } + if (gBattleMons[battler].status1 & STATUS1_PARALYSIS) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn); + string++; + } + if (gBattleMons[battler].status1 & STATUS1_BURN) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn); + string++; + } + if (gBattleMons[battler].status1 & STATUS1_FREEZE || gBattleMons[battler].status1 & STATUS1_FROSTBITE) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn); + string++; + } + if (gBattleMons[battler].volatiles.confusionTurns > 0) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_ConfusionJpn); + string++; + } + if (string <= 1) + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_CURED_PROBLEM; + else + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_NORMALIZED_STATUS; + gBattleMons[battler].status1 = 0; + RemoveConfusionStatus(battler); + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_BerryCureStatusEnd2); + else + BattleScriptCall(BattleScript_BerryCureStatusRet); + effect = ITEM_STATUS_CHANGE; + } + + return effect; +} + +enum HealAmount +{ + FIXED_HEAL_AMOUNT, + PERCENT_HEAL_AMOUNT, +}; + +static u32 ItemHealHp(u32 battler, u32 itemId, enum HealAmount percentHeal, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + enum Ability ability = GetBattlerAbility(battler); + + if (!(gBattleScripting.overrideBerryRequirements && gBattleMons[battler].hp == gBattleMons[battler].maxHP) + && !(B_HEAL_BLOCKING >= GEN_5 && gBattleMons[battler].volatiles.healBlock) + && HasEnoughHpToEatBerry(battler, ability, 2, itemId)) + { + s32 healAmount = 0; + if (percentHeal == PERCENT_HEAL_AMOUNT) + healAmount = (GetNonDynamaxMaxHP(battler) * GetItemHoldEffectParam(itemId) / 100); + else + healAmount = GetItemHoldEffectParam(itemId); + + if (ability == ABILITY_RIPEN && GetItemPocket(itemId) == POCKET_BERRIES) + healAmount *= 2; + + SetHealAmount(battler, healAmount); + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_ItemHealHP_RemoveItemEnd2); + else + BattleScriptCall(BattleScript_ItemHealHP_RemoveItemRet); + + effect = ITEM_HP_CHANGE; + } + + return effect; +} + +static u32 ItemRestorePp(u32 battler, u32 itemId, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + struct Pokemon *mon = GetBattlerMon(battler); + u32 i, changedPP = 0; + enum Ability ability = GetBattlerAbility(battler); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + u32 move = GetMonData(mon, MON_DATA_MOVE1 + i); + u32 currentPP = GetMonData(mon, MON_DATA_PP1 + i); + u32 ppBonuses = GetMonData(mon, MON_DATA_PP_BONUSES); + u32 maxPP = CalculatePPWithBonus(move, ppBonuses, i); + if (move && (currentPP == 0 || (gBattleScripting.overrideBerryRequirements && currentPP != maxPP))) + { + u32 ppRestored = GetItemHoldEffectParam(itemId); + + if (ability == ABILITY_RIPEN) + { + ppRestored *= 2; + gBattlerAbility = battler; + } + if (currentPP + ppRestored > maxPP) + changedPP = maxPP; + else + changedPP = currentPP + ppRestored; + + PREPARE_MOVE_BUFFER(gBattleTextBuff1, move); + + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_BerryPPHealEnd2); + else + BattleScriptCall(BattleScript_BerryPPHealRet); + + gBattleScripting.battler = battler; + BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, i + REQUEST_PPMOVE1_BATTLE, 0, 1, &changedPP); + MarkBattlerForControllerExec(battler); + if (MOVE_IS_PERMANENT(battler, i)) + gBattleMons[battler].pp[i] = changedPP; + effect = ITEM_PP_CHANGE; + } + } + return effect; +} + +static enum ItemEffect HealConfuseBerry(u32 battler, u32 itemId, u32 flavorId, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + u32 hpFraction = B_CONFUSE_BERRIES_HEAL >= GEN_7 ? 4 : 2; + u32 ability = GetBattlerAbility(battler); + + if (HasEnoughHpToEatBerry(battler, ability, hpFraction, itemId) + && !(B_HEAL_BLOCKING >= GEN_5 && gBattleMons[battler].volatiles.healBlock)) + { + s32 healAmount = GetNonDynamaxMaxHP(battler) / GetItemHoldEffectParam(itemId); + if (ability == ABILITY_RIPEN) + healAmount *= 2; + SetHealAmount(battler, healAmount); + if (timing == IsOnSwitchInFirstTurnActivation) + { + if (GetFlavorRelationByPersonality(gBattleMons[battler].personality, flavorId) < 0) + BattleScriptExecute(BattleScript_BerryConfuseHealEnd2); + else + BattleScriptExecute(BattleScript_ItemHealHP_RemoveItemEnd2); + } + else + { + if (GetFlavorRelationByPersonality(gBattleMons[battler].personality, flavorId) < 0) + BattleScriptCall(BattleScript_BerryConfuseHealRet); + else + BattleScriptCall(BattleScript_ItemHealHP_RemoveItemRet); + } + PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, flavorId); + effect = ITEM_HP_CHANGE; + } + + return effect; +} + +static enum ItemEffect StatRaiseBerry(u32 battler, u32 itemId, enum Stat statId, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + enum Ability ability = GetBattlerAbility(battler); + + if (CompareStat(battler, statId, MAX_STAT_STAGE, CMP_LESS_THAN, ability) + && HasEnoughHpToEatBerry(battler, ability, GetItemHoldEffectParam(itemId), itemId)) + { + gEffectBattler = gBattleScripting.battler = battler; + SET_STATCHANGER(statId, ability == ABILITY_RIPEN ? 2 : 1, FALSE); + gBattleScripting.animArg1 = STAT_ANIM_PLUS1 + statId; + gBattleScripting.animArg2 = 0; + + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_ConsumableStatRaiseEnd2); + else + BattleScriptCall(BattleScript_ConsumableStatRaiseRet); + effect = ITEM_STATS_CHANGE; + } + + return effect; +} + +static enum ItemEffect CriticalHitRatioUp(u32 battler, u32 itemId, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (!gBattleMons[battler].volatiles.focusEnergy + && !gBattleMons[battler].volatiles.dragonCheer + && HasEnoughHpToEatBerry(battler, GetBattlerAbility(battler), GetItemHoldEffectParam(itemId), itemId)) + { + gBattleMons[battler].volatiles.focusEnergy = TRUE; + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_BerryFocusEnergyEnd2); + else + BattleScriptCall(BattleScript_BerryFocusEnergyRet); + effect = ITEM_EFFECT_OTHER; + } + + return effect; +} + +static enum ItemEffect RandomStatRaiseBerry(u32 battler, u32 itemId, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + enum Stat stat; + enum Ability ability = GetBattlerAbility(battler); + + for (stat = STAT_ATK; stat < NUM_STATS; stat++) + { + if (CompareStat(battler, stat, MAX_STAT_STAGE, CMP_LESS_THAN, ability)) + break; + } + + if (stat == NUM_STATS) + return effect; + + if (HasEnoughHpToEatBerry(battler, ability, GetItemHoldEffectParam(itemId), itemId)) + { + u32 savedAttacker = gBattlerAttacker; + // MoodyCantRaiseStat requires that the battler is set to gBattlerAttacker + gBattlerAttacker = gBattleScripting.battler = battler; + gBattleScripting.statChanger = 0; + if (ability != ABILITY_CONTRARY) + stat = RandomUniformExcept(RNG_RANDOM_STAT_UP, STAT_ATK, NUM_STATS - 1, MoodyCantRaiseStat); + else + stat = RandomUniformExcept(RNG_RANDOM_STAT_UP, STAT_ATK, NUM_STATS - 1, MoodyCantLowerStat); + gBattlerAttacker = savedAttacker; + + PREPARE_STAT_BUFFER(gBattleTextBuff1, stat); + SET_STATCHANGER(stat, ability == ABILITY_RIPEN ? 4 : 2, FALSE); + gBattleScripting.animArg1 = STAT_ANIM_PLUS2 + stat; + gBattleScripting.animArg2 = 0; + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_ConsumableStatRaiseEnd2); + else + BattleScriptCall(BattleScript_ConsumableStatRaiseRet); + effect = ITEM_STATS_CHANGE; + } + + return effect; +} + +static enum ItemEffect TrySetMicleBerry(u32 battler, u32 itemId, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (HasEnoughHpToEatBerry(battler, GetBattlerAbility(battler), 4, itemId)) + { + gBattleStruct->battlerState[battler].usedMicleBerry = TRUE; + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_MicleBerryActivateEnd2); + else + BattleScriptCall(BattleScript_MicleBerryActivateRet); + effect = ITEM_EFFECT_OTHER; + } + return effect; +} + +enum ItemEffect ItemBattleEffects(u32 itemBattler, u32 battler, enum HoldEffect holdEffect, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + u32 item; + + if (timing == IsOnBerryActivation || timing == IsOnFlingActivation) + item = gLastUsedItem; + else + item = gBattleMons[itemBattler].item; + + if (holdEffect == HOLD_EFFECT_NONE + || !timing(holdEffect) + || IsUnnerveBlocked(itemBattler, item)) + return effect; + + if (!IsBattlerAlive(itemBattler) + && holdEffect != HOLD_EFFECT_ROWAP_BERRY // Hacky workaround for them right now + && holdEffect != HOLD_EFFECT_JABOCA_BERRY + && holdEffect != HOLD_EFFECT_ROCKY_HELMET) + return effect; + + switch (holdEffect) + { + case HOLD_EFFECT_DOUBLE_PRIZE: + effect = TryDoublePrize(itemBattler); + break; + case HOLD_EFFECT_ROOM_SERVICE: + effect = TryRoomService(itemBattler, timing); + break; + case HOLD_EFFECT_TERRAIN_SEED: + effect = TryTerrainSeeds(itemBattler, item, timing); + break; + case HOLD_EFFECT_BERSERK_GENE: + effect = TryBerserkGene(itemBattler, timing); + break; + case HOLD_EFFECT_BOOSTER_ENERGY: + effect = TryBoosterEnergy(itemBattler, GetBattlerAbility(itemBattler), timing); + break; + case HOLD_EFFECT_WHITE_HERB: + effect = RestoreWhiteHerbStats(itemBattler, timing); + break; + case HOLD_EFFECT_MIRROR_HERB: + effect = TryConsumeMirrorHerb(itemBattler, timing); + break; + case HOLD_EFFECT_FLINCH: // Kings Rock + effect = TryKingsRock(itemBattler, battler, item); + break; + case HOLD_EFFECT_AIR_BALLOON: + effect = TryAirBalloon(itemBattler, timing); + break; + case HOLD_EFFECT_ROCKY_HELMET: + effect = TryRockyHelmet(itemBattler, battler, item); + break; + case HOLD_EFFECT_WEAKNESS_POLICY: + effect = TryWeaknessPolicy(itemBattler); + break; + case HOLD_EFFECT_SNOWBALL: + effect = TrySnowball(itemBattler); + break; + case HOLD_EFFECT_LUMINOUS_MOSS: + effect = TryLuminousMoss(itemBattler); + break; + case HOLD_EFFECT_CELL_BATTERY: + effect = TryCellBattery(itemBattler); + break; + case HOLD_EFFECT_ABSORB_BULB: + effect = TryAbsorbBulb(itemBattler); + break; + case HOLD_EFFECT_JABOCA_BERRY: + effect = TryJabocaBerry(itemBattler, battler, item); + break; + case HOLD_EFFECT_ROWAP_BERRY: + effect = TryRowapBerry(itemBattler, battler, item); + break; + case HOLD_EFFECT_ENIGMA_BERRY: // consume and heal if hit by super effective move + effect = TrySetEnigmaBerry(itemBattler, battler); + break; + case HOLD_EFFECT_BLUNDER_POLICY: + effect = TryBlunderPolicy(itemBattler); + break; + case HOLD_EFFECT_MENTAL_HERB: + effect = TryMentalHerb(itemBattler); + break; + case HOLD_EFFECT_THROAT_SPRAY: + effect = TryThroatSpray(itemBattler); + break; + case HOLD_EFFECT_KEE_BERRY: // consume and boost defense if used physical move + effect = DamagedStatBoostBerryEffect(itemBattler, battler, STAT_DEF, DAMAGE_CATEGORY_PHYSICAL); + break; + case HOLD_EFFECT_MARANGA_BERRY: // consume and boost sp. defense if used special move + effect = DamagedStatBoostBerryEffect(itemBattler, battler, STAT_SPDEF, DAMAGE_CATEGORY_SPECIAL); + break; + case HOLD_EFFECT_SHELL_BELL: + effect = TryShellBell(itemBattler); + break; + case HOLD_EFFECT_LIFE_ORB: + effect = TryLifeOrb(itemBattler); + break; + case HOLD_EFFECT_STICKY_BARB: + if (timing == IsOnTargetHitActivation) + effect = TryStickyBarbOnTargetHit(itemBattler, battler, item); + else + effect = TryStickyBarbOnEndTurn(itemBattler, item); + break; + case HOLD_EFFECT_TOXIC_ORB: + effect = TryToxicOrb(itemBattler); + break; + case HOLD_EFFECT_FLAME_ORB: + effect = TryFlameOrb(itemBattler); + break; + case HOLD_EFFECT_LEFTOVERS: + effect = TryLeftovers(itemBattler, holdEffect); + break; + case HOLD_EFFECT_BLACK_SLUDGE: + if (IS_BATTLER_OF_TYPE(itemBattler, TYPE_POISON)) + effect = TryLeftovers(itemBattler, holdEffect); + else + effect = TryBlackSludgeDamage(itemBattler, holdEffect); + break; + case HOLD_EFFECT_CURE_PAR: // Cheri Berry + effect = TryCureParalysis(itemBattler, timing); + break; + case HOLD_EFFECT_CURE_PSN: // Pecha Berry + effect = TryCurePoison(itemBattler, timing); + break; + case HOLD_EFFECT_CURE_BRN: // Rawst Berry + effect = TryCureBurn(itemBattler, timing); + break; + case HOLD_EFFECT_CURE_FRZ: // Aspear Berry + effect = TryCureFreezeOrFrostbite(itemBattler, timing); + break; + case HOLD_EFFECT_CURE_SLP: // Chesto Berry + effect = TryCureSleep(itemBattler, timing); + break; + case HOLD_EFFECT_CURE_CONFUSION: // Persim Berry + effect = TryCureConfusion(itemBattler, timing); + break; + case HOLD_EFFECT_CURE_STATUS: // Lum Berry + effect = TryCureAnyStatus(itemBattler, timing); + break; + case HOLD_EFFECT_RESTORE_HP: // Oran / Sitrus Berry / Berry Juice + effect = ItemHealHp(itemBattler, item, FIXED_HEAL_AMOUNT, timing); + break; + case HOLD_EFFECT_RESTORE_PCT_HP: // Sitrus Berry + effect = ItemHealHp(itemBattler, item, PERCENT_HEAL_AMOUNT, timing); + break; + case HOLD_EFFECT_RESTORE_PP: // Leppa Berry + effect = ItemRestorePp(itemBattler, item, timing); + break; + case HOLD_EFFECT_CONFUSE_SPICY: // Figy Berry + effect = HealConfuseBerry(itemBattler, item, FLAVOR_SPICY, timing); + break; + case HOLD_EFFECT_CONFUSE_DRY: // Wiki Berry + effect = HealConfuseBerry(itemBattler, item, FLAVOR_DRY, timing); + break; + case HOLD_EFFECT_CONFUSE_SWEET: // Mago Berry + effect = HealConfuseBerry(itemBattler, item, FLAVOR_SWEET, timing); + break; + case HOLD_EFFECT_CONFUSE_BITTER: // Aguav Berry + effect = HealConfuseBerry(itemBattler, item, FLAVOR_BITTER, timing); + break; + case HOLD_EFFECT_CONFUSE_SOUR: // Iapapa Berry + effect = HealConfuseBerry(itemBattler, item, FLAVOR_SOUR, timing); + break; + case HOLD_EFFECT_ATTACK_UP: // Liechi Berry + effect = StatRaiseBerry(itemBattler, item, STAT_ATK, timing); + break; + case HOLD_EFFECT_DEFENSE_UP: // Ganlon Berry + effect = StatRaiseBerry(itemBattler, item, STAT_DEF, timing); + break; + case HOLD_EFFECT_SPEED_UP: // Salac Berry + effect = StatRaiseBerry(itemBattler, item, STAT_SPEED, timing); + break; + case HOLD_EFFECT_SP_ATTACK_UP: // Petaya Berry + effect = StatRaiseBerry(itemBattler, item, STAT_SPATK, timing); + break; + case HOLD_EFFECT_SP_DEFENSE_UP: // Apicot Berry + effect = StatRaiseBerry(itemBattler, item, STAT_SPDEF, timing); + break; + case HOLD_EFFECT_CRITICAL_UP: // Lansat Berry + effect = CriticalHitRatioUp(itemBattler, item, timing); + break; + case HOLD_EFFECT_RANDOM_STAT_UP: // Starf Berry + effect = RandomStatRaiseBerry(itemBattler, item, timing); + break; + case HOLD_EFFECT_MICLE_BERRY: + effect = TrySetMicleBerry(itemBattler, item, timing); + break; + default: + break; + } + + if (effect == ITEM_STATUS_CHANGE) + { + BtlController_EmitSetMonData(itemBattler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[itemBattler].status1); + MarkBattlerForControllerExec(itemBattler); + } + + if (effect) + { + gLastUsedItem = item; + gBattleScripting.battler = gPotentialItemEffectBattler = itemBattler; + if ((item >= FIRST_BERRY_INDEX && item <= LAST_BERRY_INDEX)) + GetBattlerPartyState(itemBattler)->ateBerry = TRUE; + } + + return effect; +} diff --git a/src/battle_main.c b/src/battle_main.c index e03ad5503..296504851 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -6,6 +6,7 @@ // #include "battle_arena.h" #include "battle_controllers.h" #include "battle_end_turn.h" +#include "battle_hold_effects.h" #include "battle_interface.h" #include "battle_main.h" #include "battle_message.h" @@ -13,7 +14,6 @@ #include "battle_scripts.h" #include "battle_setup.h" #include "battle_tower.h" -#include "battle_util.h" #include "battle_z_move.h" #include "battle_gimmick.h" #include "berry.h" @@ -55,6 +55,7 @@ #include "string_util.h" #include "strings.h" #include "task.h" +#include "test/battle.h" #include "test_runner.h" #include "text.h" #include "trainer_pools.h" @@ -70,7 +71,6 @@ #include "constants/battle_string_ids.h" #include "constants/battle_partner.h" #include "constants/battle_setup.h" -#include "constants/hold_effects.h" #include "constants/items.h" #include "constants/moves.h" #include "constants/party_menu.h" @@ -80,6 +80,7 @@ #include "constants/trainers.h" #include "constants/weather.h" #include "cable_club.h" +#include "test/test_runner_battle.h" extern const struct BgTemplate gBattleBgTemplates[]; @@ -116,7 +117,7 @@ static void SetActionsAndBattlersTurnOrder(void); static void UpdateBattlerPartyOrdersOnSwitch(u32 battler); static bool8 AllAtActionConfirmed(void); static void TryChangeTurnOrder(void); -static void TryChangingTurnOrderEffects(u32 battler1, u32 battler2, u32 *quickClawRandom, u32 *quickDrawRandom); +static void TryChangingTurnOrderEffects(struct BattleContext *ctx, u32 *quickClawRandom, u32 *quickDrawRandom); static void CheckChangingTurnOrderEffects(void); static void FreeResetData_ReturnToOvOrDoEvolutions(void); static void ReturnFromBattleToOverworld(void); @@ -248,7 +249,7 @@ EWRAM_DATA u8 gPartyCriticalHits[PARTY_SIZE] = {0}; EWRAM_DATA static u8 sTriedEvolving = 0; EWRAM_DATA u8 gCategoryIconSpriteId = 0; -COMMON_DATA void (*gPreBattleCallback1)(void) = NULL; +COMMON_DATA MainCallback gPreBattleCallback1 = NULL; COMMON_DATA void (*gBattleMainFunc)(void) = NULL; COMMON_DATA struct BattleResults gBattleResults = {0}; COMMON_DATA u8 gLeveledUpInBattle = 0; @@ -577,6 +578,8 @@ static void CB2_InitBattleInternal(void) } if (gBattleTypeFlags & BATTLE_TYPE_RECORDED) gBattleEnvironment = BATTLE_ENVIRONMENT_BUILDING; + if (TestRunner_Battle_GetForcedEnvironment()) + gBattleEnvironment = TestRunner_Battle_GetForcedEnvironment() - 1; if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && !(gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_EREADER_TRAINER @@ -604,9 +607,9 @@ static void CB2_InitBattleInternal(void) SetVBlankCallback(VBlankCB_Battle); SetUpBattleVars(); - if (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER) - SetMainCallback2(CB2_HandleStartMultiPartnerBattle); - else if (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + if ((IsMultibattleTest() && gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + || (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER) + || (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)) SetMainCallback2(CB2_HandleStartMultiPartnerBattle); else if (gBattleTypeFlags & BATTLE_TYPE_MULTI) SetMainCallback2(CB2_HandleStartMultiBattle); @@ -2067,7 +2070,7 @@ u8 CreateNPCTrainerPartyFromTrainer(struct Pokemon *party, const struct Trainer } if (partyData[monIndex].isShiny) { - u32 data = TRUE; + bool32 data = TRUE; SetMonData(&party[i], MON_DATA_IS_SHINY, &data); } if (partyData[monIndex].dynamaxLevel > 0) @@ -2085,7 +2088,7 @@ u8 CreateNPCTrainerPartyFromTrainer(struct Pokemon *party, const struct Trainer if (partyData[monIndex].teraType > 0) { gBattleStruct->opponentMonCanTera |= 1 << i; - u32 data = partyData[monIndex].teraType; + enum Type data = partyData[monIndex].teraType; SetMonData(&party[i], MON_DATA_TERA_TYPE, &data); } CalculateMonStats(&party[i]); @@ -2741,7 +2744,7 @@ void BeginBattleIntro(void) { BattleStartClearSetData(); gBattleCommunication[1] = 0; - gBattleStruct->introState = 0; + gBattleStruct->eventState.battleIntro = 0; gBattleMainFunc = DoBattleIntro; } @@ -2762,7 +2765,10 @@ static void ClearSetBScriptingStruct(void) memset(&gBattleScripting, 0, sizeof(gBattleScripting)); gBattleScripting.windowsType = temp; - gBattleScripting.battleStyle = gSaveBlock2Ptr->optionsBattleStyle; + if (TESTING) + gBattleScripting.battleStyle = OPTIONS_BATTLE_STYLE_SET; + else + gBattleScripting.battleStyle = gSaveBlock2Ptr->optionsBattleStyle; gBattleScripting.expOnCatch = (B_EXP_CATCH >= GEN_6); gBattleScripting.specialTrainerBattleType = specialBattleType; } @@ -2772,7 +2778,7 @@ static void BattleStartClearSetData(void) s32 i; TurnValuesCleanUp(FALSE); - SpecialStatusesClear(); + memset(&gSpecialStatuses, 0, sizeof(gSpecialStatuses)); memset(&gDisableStructs, 0, sizeof(gDisableStructs)); memset(&gFieldTimers, 0, sizeof(gFieldTimers)); @@ -2862,13 +2868,12 @@ static void BattleStartClearSetData(void) { gSideTimers[i].stickyWebBattlerId = 0xFF; } - gBattleStruct->appearedInBattle = 0; gBattleStruct->beatUpSlot = 0; for (i = 0; i < PARTY_SIZE; i++) { - gBattleStruct->usedHeldItems[i][B_SIDE_PLAYER] = 0; - gBattleStruct->usedHeldItems[i][B_SIDE_OPPONENT] = 0; + gBattleStruct->partyState[B_SIDE_PLAYER][i].usedHeldItem = ITEM_NONE; + gBattleStruct->partyState[B_SIDE_OPPONENT][i].usedHeldItem = ITEM_NONE; gBattleStruct->itemLost[B_SIDE_PLAYER][i].originalItem = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM); gBattleStruct->itemLost[B_SIDE_OPPONENT][i].originalItem = GetMonData(&gEnemyParty[i], MON_DATA_HELD_ITEM); gPartyCriticalHits[i] = 0; @@ -2944,9 +2949,9 @@ void SwitchInClearSetData(u32 battler, struct Volatiles *volatilesCopy) { if (gBattleMons[i].volatiles.infatuation == INFATUATED_WITH(battler)) gBattleMons[i].volatiles.infatuation = 0; - if (gBattleMons[i].volatiles.wrapped && gBattleStruct->wrappedBy[i] == battler) + if (gBattleMons[i].volatiles.wrapped && gBattleMons[i].volatiles.wrappedBy == battler) gBattleMons[i].volatiles.wrapped = FALSE; - if (gBattleMons[i].volatiles.syrupBomb && gBattleStruct->stickySyrupdBy[i] == battler) + if (gBattleMons[i].volatiles.syrupBomb && gBattleMons[i].volatiles.stickySyrupedBy == battler) gBattleMons[i].volatiles.syrupBomb = FALSE; if (gDisableStructs[i].octolock && gDisableStructs[i].octolockedBy == battler) gDisableStructs[i].octolock = FALSE; @@ -2987,7 +2992,7 @@ void SwitchInClearSetData(u32 battler, struct Volatiles *volatilesCopy) gLastHitBy[battler] = 0xFF; gBattleStruct->lastTakenMove[battler] = 0; - gBattleStruct->sameMoveTurns[battler] = 0; + gBattleStruct->metronomeItemCounter[battler] = 0; gBattleStruct->lastTakenMoveFrom[battler][0] = 0; gBattleStruct->lastTakenMoveFrom[battler][1] = 0; gBattleStruct->lastTakenMoveFrom[battler][2] = 0; @@ -2995,6 +3000,10 @@ void SwitchInClearSetData(u32 battler, struct Volatiles *volatilesCopy) gBattleStruct->battlerState[battler].stompingTantrumTimer = 0; gBattleStruct->palaceFlags &= ~(1u << battler); gBattleStruct->battlerState[battler].canPickupItem = FALSE; + gBattleStruct->battlerState[battler].wasAboveHalfHp = gBattleMons[battler].hp > gBattleMons[battler].maxHP / 2; + gBattleStruct->hazardsCounter = 0; + gDisableStructs[battler].hazardsDone = FALSE; + gSpecialStatuses[battler].switchInItemDone = FALSE; ClearPursuitValuesIfSet(battler); @@ -3015,7 +3024,7 @@ void SwitchInClearSetData(u32 battler, struct Volatiles *volatilesCopy) gBattleStruct->choicedMove[battler] = MOVE_NONE; gCurrentMove = MOVE_NONE; - gBattleStruct->arenaTurnCounter = 0xFF; + gBattleStruct->eventState.arenaTurn = 0xFF; // Restore struct member so replacement does not miss timing gSpecialStatuses[battler].switchInAbilityDone = FALSE; @@ -3067,9 +3076,9 @@ const u8* FaintClearSetData(u32 battler) gBattleMons[i].volatiles.escapePrevention = FALSE; if (gBattleMons[i].volatiles.infatuation == INFATUATED_WITH(battler)) gBattleMons[i].volatiles.infatuation = 0; - if (gBattleMons[i].volatiles.wrapped && gBattleStruct->wrappedBy[i] == battler) + if (gBattleMons[i].volatiles.wrapped && gBattleMons[i].volatiles.wrappedBy == battler) gBattleMons[i].volatiles.wrapped = FALSE; - if (gBattleMons[i].volatiles.syrupBomb && gBattleStruct->stickySyrupdBy[i] == battler) + if (gBattleMons[i].volatiles.syrupBomb && gBattleMons[i].volatiles.stickySyrupedBy == battler) gBattleMons[i].volatiles.syrupBomb = FALSE; if (gDisableStructs[i].octolock && gDisableStructs[i].octolockedBy == battler) gDisableStructs[i].octolock = FALSE; @@ -3107,7 +3116,7 @@ const u8* FaintClearSetData(u32 battler) gLastHitBy[battler] = 0xFF; gBattleStruct->choicedMove[battler] = MOVE_NONE; - gBattleStruct->sameMoveTurns[battler] = 0; + gBattleStruct->metronomeItemCounter[battler] = 0; gBattleStruct->lastTakenMove[battler] = MOVE_NONE; gBattleStruct->lastTakenMoveFrom[battler][0] = 0; gBattleStruct->lastTakenMoveFrom[battler][1] = 0; @@ -3197,21 +3206,21 @@ static void DoBattleIntro(void) s32 i; u32 battler; - switch ((enum BattleIntroStates)gBattleStruct->introState) + switch ((enum BattleIntroStates)gBattleStruct->eventState.battleIntro) { case BATTLE_INTRO_STATE_GET_MON_DATA: battler = gBattleCommunication[1]; BtlController_EmitGetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_ALL_BATTLE, 0); MarkBattlerForControllerExec(battler); - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; break; case BATTLE_INTRO_STATE_LOOP_BATTLER_DATA: if (!gBattleControllerExecFlags) { if (++gBattleCommunication[1] == gBattlersCount) - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; else - gBattleStruct->introState = BATTLE_INTRO_STATE_GET_MON_DATA; + gBattleStruct->eventState.battleIntro = BATTLE_INTRO_STATE_GET_MON_DATA; } break; case BATTLE_INTRO_STATE_PREPARE_BG_SLIDE: @@ -3222,12 +3231,12 @@ static void DoBattleIntro(void) MarkBattlerForControllerExec(battler); gBattleCommunication[0] = 0; gBattleCommunication[1] = 0; - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; } break; case BATTLE_INTRO_STATE_WAIT_FOR_BG_SLIDE: if (!gBattleControllerExecFlags) - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; break; case BATTLE_INTRO_STATE_DRAW_SPRITES: for (battler = 0; battler < gBattlersCount; battler++) @@ -3308,9 +3317,9 @@ static void DoBattleIntro(void) } if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; else // Skip party summary since it is a wild battle. - gBattleStruct->introState = BATTLE_INTRO_STATE_INTRO_TEXT; + gBattleStruct->eventState.battleIntro = BATTLE_INTRO_STATE_INTRO_TEXT; break; case BATTLE_INTRO_STATE_DRAW_PARTY_SUMMARY: if (!gBattleControllerExecFlags) @@ -3355,18 +3364,18 @@ static void DoBattleIntro(void) BtlController_EmitDrawPartyStatusSummary(battler, B_COMM_TO_CONTROLLER, hpStatus, PARTY_SUMM_SKIP_DRAW_DELAY); MarkBattlerForControllerExec(battler); - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; } break; case BATTLE_INTRO_STATE_WAIT_FOR_PARTY_SUMMARY: if (!gBattleControllerExecFlags) - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; break; case BATTLE_INTRO_STATE_INTRO_TEXT: if (!IsBattlerMarkedForControllerExec(GetBattlerAtPosition(B_POSITION_PLAYER_LEFT))) { PrepareStringBattle(STRINGID_INTROMSG, GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)); - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; } break; case BATTLE_INTRO_STATE_WAIT_FOR_INTRO_TEXT: @@ -3374,14 +3383,14 @@ static void DoBattleIntro(void) { if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) { - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; } else { if (B_FAST_INTRO_PKMN_TEXT == TRUE) - gBattleStruct->introState = BATTLE_INTRO_STATE_WAIT_FOR_WILD_BATTLE_TEXT; + gBattleStruct->eventState.battleIntro = BATTLE_INTRO_STATE_WAIT_FOR_WILD_BATTLE_TEXT; else - gBattleStruct->introState = BATTLE_INTRO_STATE_WAIT_FOR_TRAINER_2_SEND_OUT_ANIM; + gBattleStruct->eventState.battleIntro = BATTLE_INTRO_STATE_WAIT_FOR_TRAINER_2_SEND_OUT_ANIM; } } break; @@ -3390,11 +3399,11 @@ static void DoBattleIntro(void) PrepareStringBattle(STRINGID_INTROSENDOUT, GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)); else PrepareStringBattle(STRINGID_INTROSENDOUT, GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT)); - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; break; case BATTLE_INTRO_STATE_WAIT_FOR_TRAINER_SEND_OUT_TEXT: if (!gBattleControllerExecFlags) - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; break; case BATTLE_INTRO_STATE_TRAINER_1_SEND_OUT_ANIM: if (gBattleTypeFlags & BATTLE_TYPE_RECORDED_LINK && !(gBattleTypeFlags & BATTLE_TYPE_RECORDED_IS_MASTER)) @@ -3404,7 +3413,7 @@ static void DoBattleIntro(void) BtlController_EmitIntroTrainerBallThrow(battler, B_COMM_TO_CONTROLLER); MarkBattlerForControllerExec(battler); - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; break; case BATTLE_INTRO_STATE_TRAINER_2_SEND_OUT_ANIM: if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS) && !BATTLE_TWO_VS_ONE_OPPONENT) @@ -3419,13 +3428,13 @@ static void DoBattleIntro(void) } if (B_FAST_INTRO_PKMN_TEXT == TRUE && !(gBattleTypeFlags & (BATTLE_TYPE_RECORDED | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_RECORDED_IS_MASTER | BATTLE_TYPE_LINK))) - gBattleStruct->introState = BATTLE_INTRO_STATE_WAIT_FOR_WILD_BATTLE_TEXT; // Print at the same time as trainer sends out second mon. + gBattleStruct->eventState.battleIntro = BATTLE_INTRO_STATE_WAIT_FOR_WILD_BATTLE_TEXT; // Print at the same time as trainer sends out second mon. else - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; break; case BATTLE_INTRO_STATE_WAIT_FOR_TRAINER_2_SEND_OUT_ANIM: if (!gBattleControllerExecFlags) - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; break; case BATTLE_INTRO_STATE_WAIT_FOR_WILD_BATTLE_TEXT: if (!IsBattlerMarkedForControllerExec(GetBattlerAtPosition(B_POSITION_PLAYER_LEFT))) @@ -3435,7 +3444,7 @@ static void DoBattleIntro(void) gBattleScripting.battler = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); BattleScriptExecute(BattleScript_SilphScopeUnveiled); } - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; } break; case BATTLE_INTRO_STATE_PRINT_PLAYER_SEND_OUT_TEXT: @@ -3457,7 +3466,7 @@ static void DoBattleIntro(void) PrepareStringBattle(STRINGID_INTROSENDOUT, battler); } - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; break; case BATTLE_INTRO_STATE_WAIT_FOR_PLAYER_SEND_OUT_TEXT: if (!(gBattleTypeFlags & BATTLE_TYPE_LINK && gBattleControllerExecFlags)) @@ -3468,7 +3477,7 @@ static void DoBattleIntro(void) battler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); if (!IsBattlerMarkedForControllerExec(battler)) - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; } break; case BATTLE_INTRO_STATE_PRINT_PLAYER_1_SEND_OUT_TEXT: @@ -3479,7 +3488,7 @@ static void DoBattleIntro(void) BtlController_EmitIntroTrainerBallThrow(battler, B_COMM_TO_CONTROLLER); MarkBattlerForControllerExec(battler); - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; break; case BATTLE_INTRO_STATE_PRINT_PLAYER_2_SEND_OUT_TEXT: if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_INGAME_PARTNER)) @@ -3492,7 +3501,7 @@ static void DoBattleIntro(void) BtlController_EmitIntroTrainerBallThrow(battler, B_COMM_TO_CONTROLLER); MarkBattlerForControllerExec(battler); } - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; break; case BATTLE_INTRO_STATE_SET_DEX_AND_BATTLE_VARS: if (!gBattleControllerExecFlags) @@ -3512,12 +3521,14 @@ static void DoBattleIntro(void) HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[battler].species), FLAG_SET_SEEN, gBattleMons[battler].personality); } } - - gBattleStruct->eventsBeforeFirstTurnState = 0; + gBattleStruct->eventState.beforeFristTurn = 0; gBattleStruct->switchInBattlerCounter = 0; - gBattleStruct->overworldWeatherDone = FALSE; Ai_InitPartyStruct(); // Save mons party counts, and first 2/4 mons on the battlefield. + // mark all battlers as sent out + for (battler = 0; battler < gBattlersCount; battler++) + GetBattlerPartyState(battler)->sentOut = TRUE; + // Try to set a status to start the battle with gBattleStruct->startingStatus = 0; if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS && GetTrainerStartingStatusFromId(TRAINER_BATTLE_PARAM.opponentB)) @@ -3548,7 +3559,7 @@ static void TryDoEventsBeforeFirstTurn(void) if (gBattleControllerExecFlags) return; - switch ((enum FirstTurnEventsStates)gBattleStruct->eventsBeforeFirstTurnState) + switch (gBattleStruct->eventState.beforeFristTurn) { case FIRST_TURN_EVENTS_START: // Set invalid mons as absent(for example when starting a double battle with only one pokemon). @@ -3580,45 +3591,40 @@ static void TryDoEventsBeforeFirstTurn(void) gBattleStruct->speedTieBreaks = RandomUniform(RNG_SPEED_TIE, 0, Factorial(MAX_BATTLERS_COUNT) - 1); gBattleTurnCounter = 0; + struct BattleContext ctx = {0}; for (i = 0; i < gBattlersCount; i++) + { gBattlerByTurnOrder[i] = i; + ctx.abilities[i] = GetBattlerAbility(i); + ctx.holdEffects[i] = GetBattlerHoldEffect(i); + } for (i = 0; i < gBattlersCount - 1; i++) { for (j = i + 1; j < gBattlersCount; j++) { - if (GetWhichBattlerFaster(gBattlerByTurnOrder[i], gBattlerByTurnOrder[j], TRUE) == -1) + ctx.battlerAtk = gBattlerByTurnOrder[i]; + ctx.battlerDef = gBattlerByTurnOrder[j]; + + if (GetWhichBattlerFaster(&ctx, TRUE) == -1) SwapTurnOrder(i, j); } } - gBattleStruct->eventsBeforeFirstTurnState++; + gBattleStruct->eventState.beforeFristTurn++; break; case FIRST_TURN_EVENTS_OVERWORLD_WEATHER: - if (!gBattleStruct->overworldWeatherDone - && AbilityBattleEffects(ABILITYEFFECT_SWITCH_IN_WEATHER, 0, 0, ABILITYEFFECT_SWITCH_IN_WEATHER, 0) != 0) - { - gBattleStruct->overworldWeatherDone = TRUE; + gBattleStruct->eventState.beforeFristTurn++; + if (TryFieldEffects(FIELD_EFFECT_OVERWORLD_WEATHER)) return; - } - gBattleStruct->eventsBeforeFirstTurnState++; break; case FIRST_TURN_EVENTS_TERRAIN: - if (!gBattleStruct->terrainDone - && AbilityBattleEffects(ABILITYEFFECT_SWITCH_IN_TERRAIN, 0, 0, ABILITYEFFECT_SWITCH_IN_TERRAIN, 0) != 0) - { - gBattleStruct->terrainDone = TRUE; + gBattleStruct->eventState.beforeFristTurn++; + if (TryFieldEffects(FIELD_EFFECT_OVERWORLD_TERRAIN)) return; - } - gBattleStruct->eventsBeforeFirstTurnState++; break; case FIRST_TURN_EVENTS_STARTING_STATUS: - if (!gBattleStruct->startingStatusDone - && gBattleStruct->startingStatus - && AbilityBattleEffects(ABILITYEFFECT_SWITCH_IN_STATUSES, 0, 0, ABILITYEFFECT_SWITCH_IN_STATUSES, 0) != 0) - { - gBattleStruct->startingStatusDone = TRUE; + gBattleStruct->eventState.beforeFristTurn++; + if (TryFieldEffects(FIELD_EFFECT_TRAINER_STATUSES)) return; - } - gBattleStruct->eventsBeforeFirstTurnState++; break; case FIRST_TURN_EVENTS_TOTEM_BOOST: for (i = 0; i < gBattlersCount; i++) @@ -3631,7 +3637,7 @@ static void TryDoEventsBeforeFirstTurn(void) } } memset(gQueuedStatBoosts, 0, sizeof(gQueuedStatBoosts)); // erase all totem boosts for Mirror Herb and Opportunist - gBattleStruct->eventsBeforeFirstTurnState++; + gBattleStruct->eventState.beforeFristTurn++; break; case FIRST_TURN_EVENTS_NEUTRALIZING_GAS: while (gBattleStruct->switchInBattlerCounter < gBattlersCount) // From fastest to slowest @@ -3639,9 +3645,11 @@ static void TryDoEventsBeforeFirstTurn(void) i = gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++]; if (AbilityBattleEffects(ABILITYEFFECT_NEUTRALIZINGGAS_FIRST_TURN, i, gBattleMons[i].ability, 0, 0) != 0) return; + if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN_IMMUNITIES, i, 0, 0, 0) != 0) + return; } gBattleStruct->switchInBattlerCounter = 0; - gBattleStruct->eventsBeforeFirstTurnState++; + gBattleStruct->eventState.beforeFristTurn++; break; case FIRST_TURN_EVENTS_SWITCH_IN_ABILITIES: while (gBattleStruct->switchInBattlerCounter < gBattlersCount) // From fastest to slowest @@ -3656,25 +3664,27 @@ static void TryDoEventsBeforeFirstTurn(void) return; } gBattleStruct->switchInBattlerCounter = 0; - gBattleStruct->eventsBeforeFirstTurnState++; + gBattleStruct->eventState.beforeFristTurn++; break; case FIRST_TURN_EVENTS_ITEM_EFFECTS: while (gBattleStruct->switchInBattlerCounter < gBattlersCount) // From fastest to slowest { - if (ItemBattleEffects(ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN, gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++])) + u32 battler = gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++]; + if (ItemBattleEffects(battler, 0, GetBattlerHoldEffect(battler), IsOnSwitchInFirstTurnActivation)) return; } gBattleStruct->switchInBattlerCounter = 0; - gBattleStruct->eventsBeforeFirstTurnState++; + gBattleStruct->eventState.beforeFristTurn++; break; case FIRST_TURN_EVENTS_WHITE_HERB: while (gBattleStruct->switchInBattlerCounter < gBattlersCount) // From fastest to slowest { - if (ItemBattleEffects(ITEMEFFECT_WHITE_HERB_FIRST_TURN, gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++])) + u32 battler = gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++]; + if (ItemBattleEffects(battler, 0, GetBattlerHoldEffect(battler), IsWhiteHerbFirstTurnActivation)) return; } gBattleStruct->switchInBattlerCounter = 0; - gBattleStruct->eventsBeforeFirstTurnState++; + gBattleStruct->eventState.beforeFristTurn++; break; case FIRST_TURN_EVENTS_OPPORTUNIST: while (gBattleStruct->switchInBattlerCounter < gBattlersCount) // From fastest to slowest @@ -3684,20 +3694,21 @@ static void TryDoEventsBeforeFirstTurn(void) return; } gBattleStruct->switchInBattlerCounter = 0; - gBattleStruct->eventsBeforeFirstTurnState++; + gBattleStruct->eventState.beforeFristTurn++; break; case FIRST_TURN_EVENTS_MIRROR_HERB: while (gBattleStruct->switchInBattlerCounter < gBattlersCount) // From fastest to slowest { - if (ItemBattleEffects(ITEMEFFECT_MIRROR_HERB_FIRST_TURN, gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++])) + u32 battler = gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++]; + if (ItemBattleEffects(battler, 0, GetBattlerHoldEffect(battler), IsMirrorHerbFirstTurnActivation)) return; } gBattleStruct->switchInBattlerCounter = 0; - gBattleStruct->eventsBeforeFirstTurnState++; + gBattleStruct->eventState.beforeFristTurn++; break; case FIRST_TURN_EVENTS_EJECT_PACK: - gBattleStruct->eventsBeforeFirstTurnState++; - if (TrySwitchInEjectPack(ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN)) + gBattleStruct->eventState.beforeFristTurn++; + if (TrySwitchInEjectPack(FIRST_TURN)) return; break; case FIRST_TURN_EVENTS_END: @@ -3708,7 +3719,7 @@ static void TryDoEventsBeforeFirstTurn(void) gChosenMoveByBattler[i] = MOVE_NONE; } TurnValuesCleanUp(FALSE); - SpecialStatusesClear(); + memset(&gSpecialStatuses, 0, sizeof(gSpecialStatuses)); BattlePutTextOnWindow(gText_EmptyString3, B_WIN_MSG); AssignUsableGimmicks(); gBattleMainFunc = HandleTurnActionSelectionState; @@ -3717,19 +3728,11 @@ static void TryDoEventsBeforeFirstTurn(void) for (i = 0; i < BATTLE_COMMUNICATION_ENTRIES_COUNT; i++) gBattleCommunication[i] = 0; - for (i = 0; i < gBattlersCount; i++) - { - gBattleMons[i].volatiles.flinched = FALSE; - // Record party slots of player's mons that appeared in battle - if (!BattlerHasAi(i)) - gBattleStruct->appearedInBattle |= 1u << gBattlerPartyIndexes[i]; - } - - gBattleStruct->eventBlockCounter = 0; - gBattleStruct->turnEffectsBattlerId = 0; + gBattleStruct->eventState.endTurnBlock = 0; + gBattleStruct->eventState.endTurnBattler = 0; gBattleScripting.moveendState = 0; - gBattleStruct->faintedActionsState = 0; - gBattleStruct->endTurnEventsCounter = 0; + gBattleStruct->eventState.faintedAction = 0; + gBattleStruct->eventState.endTurn = 0; memset(gQueuedStatBoosts, 0, sizeof(gQueuedStatBoosts)); SetShellSideArmCategory(); @@ -3743,7 +3746,7 @@ static void TryDoEventsBeforeFirstTurn(void) if ((i = ShouldDoTrainerSlide(GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT), TRAINER_SLIDE_BEFORE_FIRST_TURN))) BattleScriptExecute(i == 1 ? BattleScript_TrainerASlideMsgEnd2 : BattleScript_TrainerBSlideMsgEnd2); - gBattleStruct->eventsBeforeFirstTurnState = 0; + gBattleStruct->eventState.beforeFristTurn = 0; break; } } @@ -3763,9 +3766,9 @@ static void HandleEndTurn_ContinueBattle(void) if ((gBattleMons[i].status1 & STATUS1_SLEEP) && (gBattleMons[i].volatiles.multipleTurns)) CancelMultiTurnMoves(i, SKY_DROP_IGNORE); } - gBattleStruct->eventBlockCounter = 0; - gBattleStruct->turnEffectsBattlerId = 0; - gBattleStruct->endTurnEventsCounter = 0; + gBattleStruct->eventState.endTurnBlock = 0; + gBattleStruct->eventState.endTurnBattler = 0; + gBattleStruct->eventState.endTurn = 0; } } @@ -3784,13 +3787,11 @@ void BattleTurnPassed(void) if (HandleFaintedMonActions()) return; - gBattleStruct->faintedActionsState = 0; + gBattleStruct->eventState.faintedAction = 0; TurnValuesCleanUp(FALSE); gHitMarker &= ~HITMARKER_UNABLE_TO_USE_MOVE; - gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED; gHitMarker &= ~HITMARKER_PLAYER_FAINTED; - gHitMarker &= ~HITMARKER_PASSIVE_HP_UPDATE; gBattleScripting.animTurn = 0; gBattleScripting.animTargetsHit = 0; gBattleScripting.moveendState = 0; @@ -3808,7 +3809,7 @@ void BattleTurnPassed(void) if (gBattleResults.battleTurnCounter < 0xFF) { gBattleResults.battleTurnCounter++; - gBattleStruct->arenaTurnCounter++; + gBattleStruct->eventState.arenaTurn++; } for (i = 0; i < gBattlersCount; i++) @@ -3856,7 +3857,7 @@ void BattleTurnPassed(void) u8 IsRunningFromBattleImpossible(u32 battler) { - enum ItemHoldEffect holdEffect; + enum HoldEffect holdEffect; u32 i; if (FlagGet(B_FLAG_NO_RUNNING)) @@ -4003,7 +4004,7 @@ static void HandleTurnActionSelectionState(void) else { if (gBattleMons[battler].volatiles.multipleTurns - || gBattleMons[battler].volatiles.recharge) + || gDisableStructs[battler].rechargeTimer > 0) { gChosenActionByBattler[battler] = B_ACTION_USE_MOVE; gBattleCommunication[battler] = STATE_WAIT_ACTION_CONFIRMED_STANDBY; @@ -4048,7 +4049,7 @@ static void HandleTurnActionSelectionState(void) if (AreAllMovesUnusable(battler)) { gBattleCommunication[battler] = STATE_SELECTION_SCRIPT; - gBattleStruct->selectionScriptFinished[battler] = FALSE; + gBattleStruct->battlerState[battler].selectionScriptFinished = FALSE; gBattleStruct->stateIdAfterSelScript[battler] = STATE_WAIT_ACTION_CONFIRMED_STANDBY; gBattleStruct->moveTarget[battler] = gBattleResources->bufferB[battler][3]; return; @@ -4090,7 +4091,7 @@ static void HandleTurnActionSelectionState(void) RecordedBattle_ClearBattlerAction(battler, 1); gSelectionBattleScripts[battler] = BattleScript_ActionSelectionItemsCantBeUsed; gBattleCommunication[battler] = STATE_SELECTION_SCRIPT; - gBattleStruct->selectionScriptFinished[battler] = FALSE; + gBattleStruct->battlerState[battler].selectionScriptFinished = FALSE; gBattleStruct->stateIdAfterSelScript[battler] = STATE_BEFORE_ACTION_CHOSEN; return; } @@ -4106,7 +4107,7 @@ static void HandleTurnActionSelectionState(void) RecordedBattle_ClearBattlerAction(battler, 1); gSelectionBattleScripts[battler] = BattleScript_ActionSelectionItemsCantBeUsed; gBattleCommunication[battler] = STATE_SELECTION_SCRIPT; - gBattleStruct->selectionScriptFinished[battler] = FALSE; + gBattleStruct->battlerState[battler].selectionScriptFinished = FALSE; gBattleStruct->stateIdAfterSelScript[battler] = STATE_BEFORE_ACTION_CHOSEN; return; } @@ -4144,7 +4145,7 @@ static void HandleTurnActionSelectionState(void) { gSelectionBattleScripts[battler] = BattleScript_PrintFullBox; gBattleCommunication[battler] = STATE_SELECTION_SCRIPT; - gBattleStruct->selectionScriptFinished[battler] = FALSE; + gBattleStruct->battlerState[battler].selectionScriptFinished = FALSE; gBattleStruct->stateIdAfterSelScript[battler] = STATE_BEFORE_ACTION_CHOSEN; return; } @@ -4154,7 +4155,7 @@ static void HandleTurnActionSelectionState(void) gBattleCommunication[GetPartnerBattler(battler)] = STATE_BEFORE_ACTION_CHOSEN; RecordedBattle_ClearBattlerAction(battler, 1); if (gBattleMons[GetPartnerBattler(battler)].volatiles.multipleTurns - || gBattleMons[GetPartnerBattler(battler)].volatiles.recharge) + || gDisableStructs[GetPartnerBattler(battler)].rechargeTimer > 0) { BtlController_EmitEndBounceEffect(battler, B_COMM_TO_CONTROLLER); MarkBattlerForControllerExec(battler); @@ -4201,7 +4202,7 @@ static void HandleTurnActionSelectionState(void) { gSelectionBattleScripts[battler] = BattleScript_AskIfWantsToForfeitMatch; gBattleCommunication[battler] = STATE_SELECTION_SCRIPT_MAY_RUN; - gBattleStruct->selectionScriptFinished[battler] = FALSE; + gBattleStruct->battlerState[battler].selectionScriptFinished = FALSE; gBattleStruct->stateIdAfterSelScript[battler] = STATE_BEFORE_ACTION_CHOSEN; return; } @@ -4209,7 +4210,7 @@ static void HandleTurnActionSelectionState(void) // { // gSelectionBattleScripts[battler] = BattleScript_QuestionForfeitBattle; // gBattleCommunication[battler] = STATE_SELECTION_SCRIPT_MAY_RUN; - // gBattleStruct->selectionScriptFinished[battler] = FALSE; + // gBattleStruct->battlerState[battler].selectionScriptFinished = FALSE; // gBattleStruct->stateIdAfterSelScript[battler] = STATE_BEFORE_ACTION_CHOSEN; // return; // } @@ -4226,7 +4227,7 @@ static void HandleTurnActionSelectionState(void) { gSelectionBattleScripts[battler] = BattleScript_PrintCantEscapeFromBattle; gBattleCommunication[battler] = STATE_SELECTION_SCRIPT; - gBattleStruct->selectionScriptFinished[battler] = FALSE; + gBattleStruct->battlerState[battler].selectionScriptFinished = FALSE; gBattleStruct->stateIdAfterSelScript[battler] = STATE_BEFORE_ACTION_CHOSEN; return; } @@ -4268,7 +4269,7 @@ static void HandleTurnActionSelectionState(void) { RecordedBattle_ClearBattlerAction(battler, 1); gBattleCommunication[battler] = STATE_SELECTION_SCRIPT; - gBattleStruct->selectionScriptFinished[battler] = FALSE; + gBattleStruct->battlerState[battler].selectionScriptFinished = FALSE; gBattleResources->bufferB[battler][1] = B_ACTION_USE_MOVE; gBattleStruct->stateIdAfterSelScript[battler] = STATE_WAIT_ACTION_CHOSEN; return; @@ -4397,7 +4398,7 @@ static void HandleTurnActionSelectionState(void) } break; case STATE_SELECTION_SCRIPT: - if (gBattleStruct->selectionScriptFinished[battler]) + if (gBattleStruct->battlerState[battler].selectionScriptFinished) { gBattleCommunication[battler] = gBattleStruct->stateIdAfterSelScript[battler]; } @@ -4419,7 +4420,7 @@ static void HandleTurnActionSelectionState(void) } break; case STATE_SELECTION_SCRIPT_MAY_RUN: - if (gBattleStruct->selectionScriptFinished[battler]) + if (gBattleStruct->battlerState[battler].selectionScriptFinished) { if (gBattleResources->bufferB[battler][1] == B_ACTION_NOTHING_FAINTED) { @@ -4520,7 +4521,7 @@ void SwapTurnOrder(u8 id1, u8 id2) } // For AI, so it doesn't 'cheat' by knowing player's ability -u32 GetBattlerTotalSpeedStatArgs(u32 battler, enum Ability ability, enum ItemHoldEffect holdEffect) +u32 GetBattlerTotalSpeedStat(u32 battler, enum Ability ability, enum HoldEffect holdEffect) { u32 speed = gBattleMons[battler].speed; @@ -4560,7 +4561,7 @@ u32 GetBattlerTotalSpeedStatArgs(u32 battler, enum Ability ability, enum ItemHol && ShouldGetStatBadgeBoost(B_FLAG_BADGE_BOOST_SPEED, battler) && IsOnPlayerSide(battler)) { - speed = (speed * 110) / 100; + speed = uq4_12_multiply_by_int_half_down(GetBadgeBoostModifier(), speed); } // item effects @@ -4587,13 +4588,6 @@ u32 GetBattlerTotalSpeedStatArgs(u32 battler, enum Ability ability, enum ItemHol return speed; } -u32 GetBattlerTotalSpeedStat(u32 battler) -{ - enum Ability ability = GetBattlerAbility(battler); - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler); - return GetBattlerTotalSpeedStatArgs(battler, ability, holdEffect); -} - s32 GetChosenMovePriority(u32 battler, enum Ability ability) { u16 move; @@ -4647,8 +4641,7 @@ s32 GetBattleMovePriority(u32 battler, enum Ability ability, u32 move) return priority; } -s32 GetWhichBattlerFasterArgs(u32 battler1, u32 battler2, bool32 ignoreChosenMoves, enum Ability ability1, enum Ability ability2, - enum ItemHoldEffect holdEffectBattler1, enum ItemHoldEffect holdEffectBattler2, u32 speedBattler1, u32 speedBattler2, s32 priority1, s32 priority2) +s32 GetWhichBattlerFasterArgs(struct BattleContext *ctx, bool32 ignoreChosenMoves, u32 speedBattler1, u32 speedBattler2, s32 priority1, s32 priority2) { u32 strikesFirst = 0; @@ -4657,18 +4650,18 @@ s32 GetWhichBattlerFasterArgs(u32 battler1, u32 battler2, bool32 ignoreChosenMov // Quick Claw / Quick Draw / Custap Berry - always first // Stall / Mycelium Might - last but before Lagging Tail // Lagging Tail - always last - bool32 battler1HasQuickEffect = gProtectStructs[battler1].quickDraw || gProtectStructs[battler1].usedCustapBerry; - bool32 battler2HasQuickEffect = gProtectStructs[battler2].quickDraw || gProtectStructs[battler2].usedCustapBerry; - bool32 battler1HasStallingAbility = ability1 == ABILITY_STALL || gProtectStructs[battler1].myceliumMight; - bool32 battler2HasStallingAbility = ability2 == ABILITY_STALL || gProtectStructs[battler2].myceliumMight; + bool32 battler1HasQuickEffect = gProtectStructs[ctx->battlerAtk].quickDraw || gProtectStructs[ctx->battlerAtk].usedCustapBerry; + bool32 battler2HasQuickEffect = gProtectStructs[ctx->battlerDef].quickDraw || gProtectStructs[ctx->battlerDef].usedCustapBerry; + bool32 battler1HasStallingAbility = ctx->abilities[ctx->battlerAtk] == ABILITY_STALL || gProtectStructs[ctx->battlerAtk].myceliumMight; + bool32 battler2HasStallingAbility = ctx->abilities[ctx->battlerDef] == ABILITY_STALL || gProtectStructs[ctx->battlerDef].myceliumMight; if (battler1HasQuickEffect && !battler2HasQuickEffect) strikesFirst = 1; else if (battler2HasQuickEffect && !battler1HasQuickEffect) strikesFirst = -1; - else if (gProtectStructs[battler1].laggingTail && !gProtectStructs[battler2].laggingTail) + else if (gProtectStructs[ctx->battlerAtk].laggingTail && !gProtectStructs[ctx->battlerDef].laggingTail) strikesFirst = -1; - else if (gProtectStructs[battler2].laggingTail && !gProtectStructs[battler1].laggingTail) + else if (gProtectStructs[ctx->battlerDef].laggingTail && !gProtectStructs[ctx->battlerAtk].laggingTail) strikesFirst = 1; else if (battler1HasStallingAbility && !battler2HasStallingAbility) strikesFirst = -1; @@ -4710,32 +4703,27 @@ s32 GetWhichBattlerFasterArgs(u32 battler1, u32 battler2, bool32 ignoreChosenMov return strikesFirst; } -s32 GetWhichBattlerFasterOrTies(u32 battler1, u32 battler2, bool32 ignoreChosenMoves) +s32 GetWhichBattlerFasterOrTies(struct BattleContext *ctx, bool32 ignoreChosenMoves) { s32 priority1 = 0, priority2 = 0; - enum Ability ability1 = GetBattlerAbility(battler1); - u32 speedBattler1 = GetBattlerTotalSpeedStat(battler1); - enum ItemHoldEffect holdEffectBattler1 = GetBattlerHoldEffect(battler1); - u32 speedBattler2 = GetBattlerTotalSpeedStat(battler2); - enum ItemHoldEffect holdEffectBattler2 = GetBattlerHoldEffect(battler2); - enum Ability ability2 = GetBattlerAbility(battler2); + u32 speedBattler1 = GetBattlerTotalSpeedStat(ctx->battlerAtk, ctx->abilities[ctx->battlerAtk], ctx->holdEffects[ctx->battlerAtk]); + u32 speedBattler2 = GetBattlerTotalSpeedStat(ctx->battlerDef, ctx->abilities[ctx->battlerDef], ctx->holdEffects[ctx->battlerDef]); if (!ignoreChosenMoves) { - if (gChosenActionByBattler[battler1] == B_ACTION_USE_MOVE) - priority1 = GetChosenMovePriority(battler1, ability1); - if (gChosenActionByBattler[battler2] == B_ACTION_USE_MOVE) - priority2 = GetChosenMovePriority(battler2, ability2); + if (gChosenActionByBattler[ctx->battlerAtk] == B_ACTION_USE_MOVE) + priority1 = GetChosenMovePriority(ctx->battlerAtk, ctx->abilities[ctx->battlerAtk]); + if (gChosenActionByBattler[ctx->battlerDef] == B_ACTION_USE_MOVE) + priority2 = GetChosenMovePriority(ctx->battlerDef, ctx->abilities[ctx->battlerDef]); } return GetWhichBattlerFasterArgs( - battler1, battler2, + ctx, ignoreChosenMoves, - ability1, ability2, - holdEffectBattler1, holdEffectBattler2, - speedBattler1, speedBattler2, - priority1, priority2 - ); + speedBattler1, + speedBattler2, + priority1, + priority2); } // 24 == MAX_BATTLERS_COUNT!. @@ -4769,13 +4757,13 @@ static const u8 sBattlerOrders[24][4] = { 3, 2, 1, 0 }, }; -s32 GetWhichBattlerFaster(u32 battler1, u32 battler2, bool32 ignoreChosenMoves) +s32 GetWhichBattlerFaster(struct BattleContext *ctx, bool32 ignoreChosenMoves) { - s32 strikesFirst = GetWhichBattlerFasterOrTies(battler1, battler2, ignoreChosenMoves); + s32 strikesFirst = GetWhichBattlerFasterOrTies(ctx, ignoreChosenMoves); if (strikesFirst == 0) { - s32 order1 = sBattlerOrders[gBattleStruct->speedTieBreaks][battler1]; - s32 order2 = sBattlerOrders[gBattleStruct->speedTieBreaks][battler2]; + s32 order1 = sBattlerOrders[gBattleStruct->speedTieBreaks][ctx->battlerAtk]; + s32 order2 = sBattlerOrders[gBattleStruct->speedTieBreaks][ctx->battlerDef]; if (order1 < order2) strikesFirst = 1; else @@ -4869,13 +4857,19 @@ static void SetActionsAndBattlersTurnOrder(void) turnOrderId++; } } + struct BattleContext ctx = {0}; + for (i = 0; i < gBattlersCount; i++) + { + ctx.abilities[i] = GetBattlerAbility(i); + ctx.holdEffects[i] = GetBattlerHoldEffect(i); + } for (i = 0; i < gBattlersCount - 1; i++) { for (j = i + 1; j < gBattlersCount; j++) { - u8 battler1 = gBattlerByTurnOrder[i]; - u8 battler2 = gBattlerByTurnOrder[j]; - TryChangingTurnOrderEffects(battler1, battler2, quickClawRandom, quickDrawRandom); + ctx.battlerAtk = gBattlerByTurnOrder[i]; + ctx.battlerDef = gBattlerByTurnOrder[j]; + TryChangingTurnOrderEffects(&ctx, quickClawRandom, quickDrawRandom); if (gActionsByTurnOrder[i] != B_ACTION_USE_ITEM && gActionsByTurnOrder[j] != B_ACTION_USE_ITEM && gActionsByTurnOrder[i] != B_ACTION_SWITCH @@ -4883,7 +4877,7 @@ static void SetActionsAndBattlersTurnOrder(void) && gActionsByTurnOrder[i] != B_ACTION_THROW_BALL && gActionsByTurnOrder[j] != B_ACTION_THROW_BALL) { - if (GetWhichBattlerFaster(battler1, battler2, FALSE) == -1) + if (GetWhichBattlerFaster(&ctx, FALSE) == -1) SwapTurnOrder(i, j); } } @@ -4916,12 +4910,10 @@ static void TurnValuesCleanUp(bool8 var0) gDisableStructs[i].isFirstTurn--; if (gDisableStructs[i].rechargeTimer) - { gDisableStructs[i].rechargeTimer--; - if (gDisableStructs[i].rechargeTimer == 0) - gBattleMons[i].volatiles.recharge = FALSE; - } + gBattleStruct->battlerState[i].canPickupItem = FALSE; + gBattleStruct->battlerState[i].wasAboveHalfHp = FALSE; } if (gDisableStructs[i].substituteHP == 0) @@ -4933,21 +4925,19 @@ static void TurnValuesCleanUp(bool8 var0) gSpecialStatuses[i].parentalBondState = PARENTAL_BOND_OFF; gBattleStruct->battlerState[i].usedEjectItem = FALSE; gProtectStructs[i].lashOutAffected = FALSE; + gDisableStructs[i].endured = FALSE; } gSideTimers[B_SIDE_PLAYER].followmeTimer = 0; gSideTimers[B_SIDE_OPPONENT].followmeTimer = 0; gBattleStruct->pledgeMove = FALSE; // combined pledge move may not have been used due to a canceller + gBattleStruct->tryDestinyBond = FALSE; + gBattleStruct->tryGrudge = FALSE; ClearPursuitValues(); ClearDamageCalcResults(); } -void SpecialStatusesClear(void) -{ - memset(&gSpecialStatuses, 0, sizeof(gSpecialStatuses)); -} - static void PopulateArrayWithBattlers(u8 *battlers) { u32 i; @@ -5035,29 +5025,38 @@ static bool32 TryDoMoveEffectsBeforeMoves(void) static void TryChangeTurnOrder(void) { u32 i, j; + + struct BattleContext ctx = {0}; + for (i = 0; i < gBattlersCount; i++) + { + ctx.abilities[i] = GetBattlerAbility(i); + ctx.holdEffects[i] = GetBattlerHoldEffect(i); + } for (i = gCurrentTurnActionNumber; i < gBattlersCount - 1; i++) { for (j = i + 1; j < gBattlersCount; j++) { - u32 battler1 = gBattlerByTurnOrder[i]; - u32 battler2 = gBattlerByTurnOrder[j]; + ctx.battlerAtk = gBattlerByTurnOrder[i]; + ctx.battlerDef = gBattlerByTurnOrder[j]; if (gActionsByTurnOrder[i] == B_ACTION_USE_MOVE && gActionsByTurnOrder[j] == B_ACTION_USE_MOVE) { - if (GetWhichBattlerFaster(battler1, battler2, FALSE) == -1) + if (GetWhichBattlerFaster(&ctx, FALSE) == -1) SwapTurnOrder(i, j); } } } } -static void TryChangingTurnOrderEffects(u32 battler1, u32 battler2, u32 *quickClawRandom, u32 *quickDrawRandom) +static void TryChangingTurnOrderEffects(struct BattleContext *ctx, u32 *quickClawRandom, u32 *quickDrawRandom) { - enum Ability ability1 = GetBattlerAbility(battler1); - enum ItemHoldEffect holdEffectBattler1 = GetBattlerHoldEffect(battler1); - enum ItemHoldEffect holdEffectBattler2 = GetBattlerHoldEffect(battler2); - enum Ability ability2 = GetBattlerAbility(battler2); + u32 battler1 = ctx->battlerAtk; + u32 battler2 = ctx->battlerDef; + enum Ability ability1 = ctx->abilities[ctx->battlerAtk]; + enum Ability ability2 = ctx->abilities[ctx->battlerDef]; + enum HoldEffect holdEffectBattler1 = ctx->holdEffects[ctx->battlerAtk]; + enum HoldEffect holdEffectBattler2 = ctx->holdEffects[ctx->battlerDef]; // Battler 1 // Quick Draw @@ -5066,7 +5065,7 @@ static void TryChangingTurnOrderEffects(u32 battler1, u32 battler2, u32 *quickCl // Quick Claw and Custap Berry if (!gProtectStructs[battler1].quickDraw && ((holdEffectBattler1 == HOLD_EFFECT_QUICK_CLAW && quickClawRandom[battler1]) - || (holdEffectBattler1 == HOLD_EFFECT_CUSTAP_BERRY && HasEnoughHpToEatBerry(battler1, 4, gBattleMons[battler1].item)))) + || (holdEffectBattler1 == HOLD_EFFECT_CUSTAP_BERRY && HasEnoughHpToEatBerry(battler1, ability1, 4, gBattleMons[battler1].item)))) gProtectStructs[battler1].usedCustapBerry = TRUE; // Battler 2 @@ -5076,7 +5075,7 @@ static void TryChangingTurnOrderEffects(u32 battler1, u32 battler2, u32 *quickCl // Quick Claw and Custap Berry if (!gProtectStructs[battler2].quickDraw && ((holdEffectBattler2 == HOLD_EFFECT_QUICK_CLAW && quickClawRandom[battler2]) - || (holdEffectBattler2 == HOLD_EFFECT_CUSTAP_BERRY && HasEnoughHpToEatBerry(battler2, 4, gBattleMons[battler2].item)))) + || (holdEffectBattler2 == HOLD_EFFECT_CUSTAP_BERRY && HasEnoughHpToEatBerry(battler2, ability2, 4, gBattleMons[battler2].item)))) gProtectStructs[battler2].usedCustapBerry = TRUE; } @@ -5172,16 +5171,12 @@ static void RunTurnActionsFunctions(void) if (gCurrentTurnActionNumber >= gBattlersCount) // everyone did their actions, turn finished { - gHitMarker &= ~HITMARKER_PASSIVE_HP_UPDATE; gBattleMainFunc = sEndTurnFuncsTable[gBattleOutcome & 0x7F]; } else { if (gBattleStruct->savedTurnActionNumber != gCurrentTurnActionNumber) // action turn has been done, clear hitmarker bits for another battler - { - gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED; gHitMarker &= ~HITMARKER_UNABLE_TO_USE_MOVE; - } } } @@ -5350,18 +5345,7 @@ static void HandleEndTurn_FinishBattle(void) for (i = 0; i < PARTY_SIZE; i++) { - bool8 changedForm = FALSE; - - // Appeared in battle and didn't faint - if ((gBattleStruct->appearedInBattle & (1u << i)) && GetMonData(&gPlayerParty[i], MON_DATA_HP, NULL) != 0) - changedForm = TryFormChange(i, B_SIDE_PLAYER, FORM_CHANGE_END_BATTLE_ENVIRONMENT); - - if (!changedForm) - changedForm = TryFormChange(i, B_SIDE_PLAYER, FORM_CHANGE_END_BATTLE); - - // Clear original species field - gBattleStruct->partyState[B_SIDE_PLAYER][i].changedSpecies = SPECIES_NONE; - gBattleStruct->partyState[B_SIDE_OPPONENT][i].changedSpecies = SPECIES_NONE; + bool32 changedForm = TryRevertPartyMonFormChange(i); // Recalculate the stats of every party member before the end if (!changedForm && B_RECALCULATE_STATS >= GEN_5) @@ -5449,20 +5433,24 @@ static void TryEvolvePokemon(void) if (!(sTriedEvolving & (1u << i))) { bool32 canStopEvo = TRUE; - u32 species = GetEvolutionTargetSpecies(&gPlayerParty[i], EVO_MODE_BATTLE_SPECIAL, i, NULL, &canStopEvo, CHECK_EVO); + enum EvolutionMode mode = EVO_MODE_BATTLE_SPECIAL; + u32 evolutionItemArg = i; + u32 species = GetEvolutionTargetSpecies(&gPlayerParty[i], mode, evolutionItemArg, NULL, &canStopEvo, CHECK_EVO); sTriedEvolving |= 1u << i; if (species == SPECIES_NONE && (gLeveledUpInBattle & (1u << i))) { gLeveledUpInBattle &= ~(1u << i); - species = GetEvolutionTargetSpecies(&gPlayerParty[i], EVO_MODE_BATTLE_ONLY, gLeveledUpInBattle, NULL, &canStopEvo, CHECK_EVO); + mode = EVO_MODE_BATTLE_ONLY; + evolutionItemArg = gLeveledUpInBattle; + species = GetEvolutionTargetSpecies(&gPlayerParty[i], mode, evolutionItemArg, NULL, &canStopEvo, CHECK_EVO); } if (species != SPECIES_NONE) { FreeAllWindowBuffers(); gBattleMainFunc = WaitForEvoSceneToFinish; - GetEvolutionTargetSpecies(&gPlayerParty[i], EVO_MODE_BATTLE_ONLY, gLeveledUpInBattle, NULL, &canStopEvo, DO_EVO); + GetEvolutionTargetSpecies(&gPlayerParty[i], mode, evolutionItemArg, NULL, &canStopEvo, DO_EVO); EvolutionScene(&gPlayerParty[i], species, canStopEvo, i); return; } @@ -5532,9 +5520,9 @@ void RunBattleScriptCommands(void) gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]](); } -u32 TrySetAteType(u32 move, u32 battlerAtk, enum Ability attackerAbility) +enum Type TrySetAteType(u32 move, u32 battlerAtk, enum Ability attackerAbility) { - u32 ateType = TYPE_NONE; + enum Type ateType = TYPE_NONE; switch (GetMoveEffect(move)) { @@ -5580,20 +5568,21 @@ u32 TrySetAteType(u32 move, u32 battlerAtk, enum Ability attackerAbility) } // Returns TYPE_NONE if type doesn't change. -u32 GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum MonState state) +enum Type GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum MonState state) { - u32 moveType = GetMoveType(move); + enum Type moveType = GetMoveType(move); enum BattleMoveEffects moveEffect = GetMoveEffect(move); - u32 species, heldItem, type1, type2, type3; + u32 species, heldItem; + enum Type type1, type2, type3; enum Ability ability; - enum ItemHoldEffect holdEffect; + enum HoldEffect holdEffect; enum Gimmick gimmick = GetActiveGimmick(battler); - if (move == MOVE_STRUGGLE) - return TYPE_NORMAL; - if (state == MON_IN_BATTLE) { + if (moveEffect == EFFECT_STRUGGLE) + return TYPE_MYSTERY; + species = gBattleMons[battler].species; heldItem = gBattleMons[battler].item; holdEffect = GetBattlerHoldEffect(battler); @@ -5694,7 +5683,7 @@ u32 GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum MonState case EFFECT_REVELATION_DANCE: if (gimmick != GIMMICK_Z_MOVE) { - u32 teraType; + enum Type teraType; if (gimmick == GIMMICK_TERA && ((teraType = GetMonData(mon, MON_DATA_TERA_TYPE)) != TYPE_STELLAR)) return teraType; else if (type1 != TYPE_MYSTERY && !(gDisableStructs[battler].roostActive && type1 == TYPE_FLYING)) @@ -5819,9 +5808,9 @@ u32 GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum MonState void SetTypeBeforeUsingMove(u32 move, u32 battler) { - u32 moveType; + enum Type moveType; u32 heldItem = gBattleMons[battler].item; - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler); + enum HoldEffect holdEffect = GetBattlerHoldEffect(battler); gBattleStruct->dynamicMoveType = 0; gBattleStruct->battlerState[battler].ateBoost = FALSE; @@ -5846,8 +5835,7 @@ void SetTypeBeforeUsingMove(u32 move, u32 battler) && GetBattleMoveType(move) == GetItemSecondaryId(heldItem) && effect != EFFECT_PLEDGE && effect != EFFECT_OHKO - && effect != EFFECT_SHEER_COLD - && effect != EFFECT_STRUGGLE) + && effect != EFFECT_SHEER_COLD) { gSpecialStatuses[battler].gemParam = GetBattlerHoldEffectParam(battler); gSpecialStatuses[battler].gemBoost = TRUE; @@ -5892,27 +5880,27 @@ static s32 Factorial(s32 n) return f; } -// bool32 CanPlayerForfeitNormalTrainerBattle(void) -// { -// if (!B_RUN_TRAINER_BATTLE) -// return FALSE; +bool32 CanPlayerForfeitNormalTrainerBattle(void) +{ + if (!B_RUN_TRAINER_BATTLE) + return FALSE; -// if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER) -// return FALSE; + if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER) + return FALSE; -// if (gBattleTypeFlags & BATTLE_TYPE_RECORDED_INVALID) -// return FALSE; + if (gBattleTypeFlags & BATTLE_TYPE_RECORDED_INVALID) + return FALSE; -// return (gBattleTypeFlags & BATTLE_TYPE_TRAINER); -// } + return (gBattleTypeFlags & BATTLE_TYPE_TRAINER); +} -// bool32 DidPlayerForfeitNormalTrainerBattle(void) -// { -// if (!CanPlayerForfeitNormalTrainerBattle()) -// return FALSE; +bool32 DidPlayerForfeitNormalTrainerBattle(void) +{ + if (!CanPlayerForfeitNormalTrainerBattle()) + return FALSE; -// return (gBattleOutcome == B_OUTCOME_FORFEITED); -// } + return (gBattleOutcome == B_OUTCOME_FORFEITED); +} // Wins the battle instantly. Used in the battle debug with LIST_ITEM_INSTANT_WIN void BattleDebug_WonBattle(void) diff --git a/src/battle_message.c b/src/battle_message.c index 666b63f97..9780a1701 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -294,8 +294,7 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_STATSWONTINCREASE2] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s stats won't go any higher!"), [STRINGID_AVOIDEDDAMAGE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} avoided damage with {B_DEF_ABILITY}!"), //not in gen 5+, ability popup [STRINGID_ITDOESNTAFFECT] = COMPOUND_STRING("It doesn't affect {B_DEF_NAME_WITH_PREFIX2}…"), - [STRINGID_ATTACKERFAINTED] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} fainted!\p"), - [STRINGID_TARGETFAINTED] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} fainted!\p"), + [STRINGID_BATTLERFAINTED] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} fainted!\p"), [STRINGID_PLAYERGOTMONEY] = COMPOUND_STRING("You got ¥{B_BUFF1} for winning!\p"), [STRINGID_PLAYERWHITEOUT] = COMPOUND_STRING("You have no more Pokémon that can fight!\p"), [STRINGID_PLAYERWHITEOUT2_WILD] = COMPOUND_STRING("You panicked and dropped ¥{B_BUFF1}…"), @@ -396,16 +395,16 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_PKMNRAGEBUILDING] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s rage is building!"), [STRINGID_PKMNMOVEWASDISABLED] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_BUFF1} was disabled!"), [STRINGID_PKMNMOVEISDISABLED] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_CURRENT_MOVE} is disabled!\p"), - [STRINGID_PKMNMOVEDISABLEDNOMORE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s move is no longer disabled!"), + [STRINGID_PKMNMOVEDISABLEDNOMORE] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s move is no longer disabled!"), [STRINGID_PKMNGOTENCORE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} must do an encore!"), [STRINGID_PKMNGOTENCOREDMOVE] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} can only use {B_CURRENT_MOVE}!\p"), - [STRINGID_PKMNENCOREENDED] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} ended its encore!"), + [STRINGID_PKMNENCOREENDED] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} ended its encore!"), [STRINGID_PKMNTOOKAIM] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} took aim at {B_DEF_NAME_WITH_PREFIX2}!"), [STRINGID_PKMNSKETCHEDMOVE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} sketched {B_BUFF1}!"), [STRINGID_PKMNTRYINGTOTAKEFOE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is hoping to take its attacker down with it!"), [STRINGID_PKMNTOOKFOE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} took its attacker down with it!"), [STRINGID_PKMNREDUCEDPP] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s PP was reduced!"), - [STRINGID_PKMNSTOLEITEM] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} stole {B_DEF_NAME_WITH_PREFIX2}'s {B_LAST_ITEM}!"), + [STRINGID_PKMNSTOLEITEM] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} stole {B_EFF_NAME_WITH_PREFIX2}'s {B_LAST_ITEM}!"), [STRINGID_TARGETCANTESCAPENOW] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} can no longer escape!"), [STRINGID_PKMNFELLINTONIGHTMARE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} began having a nightmare!"), [STRINGID_PKMNLOCKEDINNIGHTMARE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is locked in a nightmare!"), @@ -461,7 +460,7 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_PKMNRESTOREDHPUSING] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} restored HP using its {B_DEF_ABILITY}!"), //not in gen 5+, ability popup [STRINGID_PKMNCHANGEDTYPEWITH] = COMPOUND_STRING("{B_EFF_NAME_WITH_PREFIX}'s {B_EFF_ABILITY} made it the {B_BUFF1} type!"), //not in gen 5+, ability popup [STRINGID_PKMNPREVENTSROMANCEWITH] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} prevents romance!"), //not in gen 5+, ability popup - [STRINGID_PKMNPREVENTSCONFUSIONWITH] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} prevents confusion!"), //not in gen 5+, ability popup + [STRINGID_PKMNPREVENTSCONFUSIONWITH] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} prevents confusion!"), //not in gen 5+, ability popup [STRINGID_PKMNRAISEDFIREPOWERWITH] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} raised the power of Fire-type moves!"), //not in gen 5+, ability popup [STRINGID_PKMNANCHORSITSELFWITH] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} anchors itself with {B_DEF_ABILITY}!"), //not in gen 5+, ability popup [STRINGID_PKMNCUTSATTACKWITH] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} cuts {B_DEF_NAME_WITH_PREFIX2}'s Attack!"), //not in gen 5+, ability popup @@ -681,7 +680,7 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_TRANSFERHELDITEM] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} received {B_LAST_ITEM} from {B_ATK_NAME_WITH_PREFIX2}"), [STRINGID_EMBARGOENDS] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} can use items again!"), [STRINGID_ELECTROMAGNETISM] = COMPOUND_STRING("electromagnetism"), - [STRINGID_BUFFERENDS] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_BUFF1} wore off!"), + [STRINGID_BUFFERENDS] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_BUFF1} wore off!"), [STRINGID_TELEKINESISENDS] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} was freed from the telekinesis!"), [STRINGID_TAILWINDENDS] = COMPOUND_STRING("{B_ATK_TEAM1} team's Tailwind petered out!"), [STRINGID_LUCKYCHANTENDS] = COMPOUND_STRING("{B_ATK_TEAM1} team's Lucky Chant wore off!"), @@ -791,7 +790,7 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_RECEIVERABILITYTAKEOVER] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} was taken over!"), [STRINGID_PKNMABSORBINGPOWER] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is absorbing power!"), [STRINGID_NOONEWILLBEABLETORUNAWAY] = COMPOUND_STRING("No one will be able to run away during the next turn!"), - [STRINGID_DESTINYKNOTACTIVATES] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} fell in love because of the {B_LAST_ITEM}!"), + [STRINGID_DESTINYKNOTACTIVATES] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} fell in love because of the {B_LAST_ITEM}!"), [STRINGID_CLOAKEDINAFREEZINGLIGHT] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} became cloaked in a freezing light!"), [STRINGID_CLEARAMULETWONTLOWERSTATS] = COMPOUND_STRING("The effects of the {B_LAST_ITEM} held by {B_SCR_NAME_WITH_PREFIX2} prevents its stats from being lowered!"), [STRINGID_FERVENTWISHREACHED] = COMPOUND_STRING("{B_ATK_TRAINER_NAME}'s fervent wish has reached {B_ATK_NAME_WITH_PREFIX2}!"), @@ -817,9 +816,9 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_PKMNBURNHEALED] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s burn was cured!"), [STRINGID_REDCARDACTIVATE] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} held up its Red Card against {B_ATK_NAME_WITH_PREFIX2}!"), [STRINGID_EJECTBUTTONACTIVATE] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} is switched out with the {B_LAST_ITEM}!"), - [STRINGID_ATKGOTOVERINFATUATION] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} got over its infatuation!"), - [STRINGID_TORMENTEDNOMORE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is no longer tormented!"), - [STRINGID_HEALBLOCKEDNOMORE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is cured of its heal block!"), + [STRINGID_ATKGOTOVERINFATUATION] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} got over its infatuation!"), + [STRINGID_TORMENTEDNOMORE] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} is no longer tormented!"), + [STRINGID_HEALBLOCKEDNOMORE] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} is cured of its heal block!"), [STRINGID_ATTACKERBECAMEFULLYCHARGED] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} became fully charged due to its bond with its trainer!\p"), [STRINGID_ATTACKERBECAMEASHSPECIES] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} became Ash-Greninja!\p"), [STRINGID_EXTREMELYHARSHSUNLIGHT] = COMPOUND_STRING("The sunlight turned extremely harsh!"), @@ -980,6 +979,11 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_POWERCONSTRUCTPRESENCEOFMANY] = COMPOUND_STRING("You sense the presence of many!"), [STRINGID_POWERCONSTRUCTTRANSFORM] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} transformed into its Complete Forme!"), [STRINGID_ABILITYSHIELDPROTECTS] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s Ability is protected by the effects of its {B_LAST_ITEM}!"), + [STRINGID_MONTOOSCAREDTOMOVE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is too scared to move!"), + [STRINGID_GHOSTGETOUTGETOUT] = COMPOUND_STRING("GHOST: Get out…… Get out……"), + [STRINGID_SILPHSCOPEUNVEILED] = COMPOUND_STRING("SILPH SCOPE unveiled the GHOST's\nidentity!"), + [STRINGID_GHOSTWASMAROWAK] = COMPOUND_STRING("The GHOST was MAROWAK!\p\n"), + [STRINGID_TRAINER1MON1COMEBACK] = COMPOUND_STRING("{B_TRAINER1_NAME}: {B_OPPONENT_MON1_NAME}, come back!"), // pokefirered strings [STRINGID_PKMNTRANSFERREDBILLSPC] = gText_PkmnTransferredBillsPC, @@ -991,11 +995,6 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_PKMNANGRY] = COMPOUND_STRING("{B_OPPONENT_MON1_NAME} is angry!"), [STRINGID_PKMNEATING] = COMPOUND_STRING("{B_OPPONENT_MON1_NAME} is eating!"), [STRINGID_POKEDUDEUSED] = COMPOUND_STRING("The POKé DUDE used\n{B_LAST_ITEM}!"), - [STRINGID_MONTOOSCAREDTOMOVE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is too scared to move!"), - [STRINGID_GHOSTGETOUTGETOUT] = COMPOUND_STRING("GHOST: Get out…… Get out……"), - [STRINGID_SILPHSCOPEUNVEILED] = COMPOUND_STRING("SILPH SCOPE unveiled the GHOST's\nidentity!"), - [STRINGID_GHOSTWASMAROWAK] = COMPOUND_STRING("The GHOST was MAROWAK!\p\n"), - [STRINGID_TRAINER1MON1COMEBACK] = COMPOUND_STRING("{B_TRAINER1_NAME}: {B_OPPONENT_MON1_NAME}, come back!"), [STRINGID_TRAINER1MON2COMEBACK] = COMPOUND_STRING("{B_TRAINER1_NAME}: {B_OPPONENT_MON2_NAME}, come back!"), [STRINGID_TRAINER1MON1AND2COMEBACK] = COMPOUND_STRING("{B_TRAINER1_NAME}: {B_OPPONENT_MON1_NAME} and\n{B_OPPONENT_MON2_NAME}, come back!"), }; @@ -1411,18 +1410,14 @@ const u16 gSafariReactionStringIds[NUM_SAFARI_REACTIONS] = [B_MSG_MON_EATING] = STRINGID_PKMNEATING }; -// const u16 gTrainerItemCuredStatusStringIds[] = -// { -// [AI_HEAL_CONFUSION] = STRINGID_PKMNSITEMSNAPPEDOUT, -// [AI_HEAL_PARALYSIS] = STRINGID_PKMNSITEMCUREDPARALYSIS, -// [AI_HEAL_FREEZE] = STRINGID_PKMNSITEMDEFROSTEDIT, -// [AI_HEAL_BURN] = STRINGID_PKMNSITEMHEALEDBURN, -// [AI_HEAL_POISON] = STRINGID_PKMNSITEMCUREDPOISON, -// [AI_HEAL_SLEEP] = STRINGID_PKMNSITEMWOKEIT -// }; - -const u16 gBerryEffectStringIds[] = +const u16 CureStatusBerryEffectStringID[] = { + [B_MSG_CURED_PARALYSIS] = STRINGID_PKMNSITEMCUREDPARALYSIS, + [B_MSG_CURED_POISON] = STRINGID_PKMNSITEMCUREDPOISON, + [B_MSG_CURED_BURN] = STRINGID_PKMNSITEMHEALEDBURN, + [B_MSG_CURED_FREEEZE] = STRINGID_PKMNSITEMDEFROSTEDIT, + [B_MSG_CURED_FROSTBITE] = STRINGID_PKMNSITEMHEALEDFROSTBITE, + [B_MSG_CURED_SLEEP] = STRINGID_PKMNSITEMWOKEIT, [B_MSG_CURED_PROBLEM] = STRINGID_PKMNSITEMCUREDPROBLEM, [B_MSG_NORMALIZED_STATUS] = STRINGID_PKMNSITEMNORMALIZEDSTATUS }; diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 4b8397e2b..1831a8413 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1,5 +1,6 @@ #include "global.h" #include "battle.h" +#include "battle_hold_effects.h" #include "battle_message.h" #include "battle_anim.h" #include "battle_ai_main.h" @@ -41,8 +42,8 @@ #include "party_menu.h" #include "trainer_pokemon_sprites.h" // #include "battle_arena.h" -// // #include "battle_pike.h" -// // #include "battle_pyramid.h" +// #include "battle_pike.h" +// #include "battle_pyramid.h" #include "field_specials.h" #include "pokemon_summary_screen.h" // #include "pokenav.h" @@ -55,7 +56,6 @@ #include "constants/battle_move_effects.h" #include "constants/battle_string_ids.h" #include "constants/battle_partner.h" -#include "constants/hold_effects.h" #include "constants/items.h" #include "constants/item_effects.h" #include "constants/moves.h" @@ -69,8 +69,10 @@ #include "constants/pokemon.h" #include "config/battle.h" #include "data/battle_move_effects.h" +#include "test/battle.h" // #include "follower_npc.h" #include "load_save.h" +#include "test/test_runner_battle.h" // table to avoid ugly powing on gba (courtesy of doesnt) // this returns (i^2.5)/4 @@ -310,8 +312,7 @@ enum GiveCaughtMonStates #define TAG_LVLUP_BANNER_MON_ICON 55130 -static void TrySetDestinyBondToHappen(void); -static u32 ChangeStatBuffs(u32 battler, s8 statValue, u32 statId, union StatChangeFlags flags, u32 stats, const u8 *BS_ptr); +static u32 ChangeStatBuffs(u32 battler, s8 statValue, enum Stat statId, union StatChangeFlags flags, u32 stats, const u8 *BS_ptr); static void InitLevelUpBanner(void); static bool8 SlideInLevelUpBanner(void); static bool8 SlideOutLevelUpBanner(void); @@ -322,7 +323,7 @@ static void DrawLevelUpBannerText(void); static void SpriteCB_MonIconOnLvlUpBanner(struct Sprite *sprite); static bool32 CriticalCapture(u32 odds); static void BestowItem(u32 battlerAtk, u32 battlerDef); -static bool8 IsFinalStrikeEffect(enum BattleMoveEffects moveEffect); +static bool32 IsFinalStrikeEffect(enum MoveEffect moveEffect); static void TryUpdateRoundTurnOrder(void); static bool32 ChangeOrderTargetAfterAttacker(void); static bool32 SetTargetToNextPursuiter(u32 battlerDef); @@ -334,14 +335,13 @@ static u32 GetNextTarget(u32 moveTarget, bool32 excludeCurrent); static void TryUpdateEvolutionTracker(u32 evolutionCondition, u32 upAmount, u16 usedMove); static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u8 *failInstr, u16 move); static void ResetValuesForCalledMove(void); -static void TryRestoreDamageAfterCheekPouch(u32 battler); static bool32 TrySymbiosis(u32 battler, u32 itemId, bool32 moveEnd); static bool32 CanAbilityShieldActivateForBattler(u32 battler); static void Cmd_attackcanceler(void); static void Cmd_accuracycheck(void); static void Cmd_printattackstring(void); -static void Cmd_unused0x3(void); +static void Cmd_unused_0x3(void); static void Cmd_critcalc(void); static void Cmd_damagecalc(void); static void Cmd_typecalc(void); @@ -371,7 +371,7 @@ static void Cmd_jumpifvolatile(void); static void Cmd_jumpifability(void); static void Cmd_jumpifsideaffecting(void); static void Cmd_jumpifstat(void); -static void Cmd_unused_0x21(void); +static void Cmd_jumpifstatignorecontrary(void); static void Cmd_jumpbasedontype(void); static void Cmd_getexp(void); static void Cmd_checkteamslost(void); @@ -397,7 +397,7 @@ static void Cmd_bichalfword(void); static void Cmd_bicword(void); static void Cmd_pause(void); static void Cmd_waitstate(void); -static void Cmd_absorb(void); +static void Cmd_isdmgblockedbydisguise(void); static void Cmd_return(void); static void Cmd_end(void); static void Cmd_end2(void); @@ -456,7 +456,7 @@ static void Cmd_jumpifplayerran(void); static void Cmd_hpthresholds(void); static void Cmd_hpthresholds2(void); static void Cmd_useitemonopponent(void); -static void Cmd_various(void); +static void Cmd_unused_0x78(void); static void Cmd_setprotectlike(void); static void Cmd_tryexplosion(void); static void Cmd_setatkhptozero(void); @@ -474,7 +474,7 @@ static void Cmd_jumpifuproarwakes(void); static void Cmd_stockpile(void); static void Cmd_stockpiletobasedamage(void); static void Cmd_stockpiletohpheal(void); -static void Cmd_setdrainedhp(void); +static void Cmd_unused_0x88(void); static void Cmd_statbuffchange(void); static void Cmd_normalisebuffs(void); static void Cmd_setbide(void); @@ -509,7 +509,7 @@ static void Cmd_setalwayshitflag(void); static void Cmd_copymovepermanently(void); static void Cmd_unused_0xA9(void); static void Cmd_unused_AA(void); -static void Cmd_trysetdestinybondtohappen(void); +static void Cmd_unused_0xab(void); static void Cmd_settailwind(void); static void Cmd_tryspiteppreduce(void); static void Cmd_healpartystatus(void); @@ -525,7 +525,7 @@ static void Cmd_presentdamagecalculation(void); static void Cmd_setsafeguard(void); static void Cmd_magnitudedamagecalculation(void); static void Cmd_jumpifnopursuitswitchdmg(void); -static void Cmd_tryrestorehpberry(void); +static void Cmd_tryactivateitem(void); static void Cmd_halvehp(void); static void Cmd_copyfoestats(void); static void Cmd_rapidspinfree(void); @@ -582,7 +582,7 @@ static void Cmd_givecaughtmon(void); static void Cmd_trysetcaughtmondexflags(void); static void Cmd_displaydexinfo(void); static void Cmd_trygivecaughtmonnick(void); -static void Cmd_subattackerhpbydmg(void); +static void Cmd_unused_0xf4(void); static void Cmd_removeattackerstatus1(void); static void Cmd_finishaction(void); static void Cmd_finishturn(void); @@ -592,7 +592,7 @@ static void Cmd_swapstatstages(void); static void Cmd_averagestats(void); static void Cmd_jumpifcaptivateaffected(void); static void Cmd_setnonvolatilestatus(void); -static void Cmd_tryworryseed(void); +static void Cmd_tryoverwriteability(void); static void Cmd_callnative(void); void (*const gBattleScriptingCommandsTable[])(void) = @@ -600,7 +600,7 @@ void (*const gBattleScriptingCommandsTable[])(void) = Cmd_attackcanceler, //0x0 Cmd_accuracycheck, //0x1 Cmd_printattackstring, //0x2 - Cmd_unused0x3, //0x3 + Cmd_unused_0x3, //0x3 Cmd_critcalc, //0x4 Cmd_damagecalc, //0x5 Cmd_typecalc, //0x6 @@ -630,7 +630,7 @@ void (*const gBattleScriptingCommandsTable[])(void) = Cmd_jumpifability, //0x1E Cmd_jumpifsideaffecting, //0x1F Cmd_jumpifstat, //0x20 - Cmd_unused_0x21, //0x21 + Cmd_jumpifstatignorecontrary, //0x21 Cmd_jumpbasedontype, //0x22 Cmd_getexp, //0x23 Cmd_checkteamslost, //0x24 @@ -656,7 +656,7 @@ void (*const gBattleScriptingCommandsTable[])(void) = Cmd_bicword, //0x38 Cmd_pause, //0x39 Cmd_waitstate, //0x3A - Cmd_absorb, //0x3B + Cmd_isdmgblockedbydisguise, //0x3B Cmd_return, //0x3C Cmd_end, //0x3D Cmd_end2, //0x3E @@ -715,7 +715,7 @@ void (*const gBattleScriptingCommandsTable[])(void) = Cmd_hpthresholds, //0x73 Cmd_hpthresholds2, //0x74 Cmd_useitemonopponent, //0x75 - Cmd_various, //0x76 + Cmd_unused_0x78, //0x76 Cmd_setprotectlike, //0x77 Cmd_tryexplosion, //0x78 Cmd_setatkhptozero, //0x79 @@ -733,7 +733,7 @@ void (*const gBattleScriptingCommandsTable[])(void) = Cmd_stockpile, //0x85 Cmd_stockpiletobasedamage, //0x86 Cmd_stockpiletohpheal, //0x87 - Cmd_setdrainedhp, //0x88 + Cmd_unused_0x88, //0x88 Cmd_statbuffchange, //0x89 Cmd_normalisebuffs, //0x8A Cmd_setbide, //0x8B @@ -768,7 +768,7 @@ void (*const gBattleScriptingCommandsTable[])(void) = Cmd_copymovepermanently, //0xA8 Cmd_unused_0xA9, //0xA9 Cmd_unused_AA, //0xAA - Cmd_trysetdestinybondtohappen, //0xAB + Cmd_unused_0xab, //0xAB Cmd_settailwind, //0xAC Cmd_tryspiteppreduce, //0xAD Cmd_healpartystatus, //0xAE @@ -784,7 +784,7 @@ void (*const gBattleScriptingCommandsTable[])(void) = Cmd_setsafeguard, //0xB8 Cmd_magnitudedamagecalculation, //0xB9 Cmd_jumpifnopursuitswitchdmg, //0xBA - Cmd_tryrestorehpberry, //0xBB + Cmd_tryactivateitem, //0xBB Cmd_halvehp, //0xBC Cmd_copyfoestats, //0xBD Cmd_rapidspinfree, //0xBE @@ -841,7 +841,7 @@ void (*const gBattleScriptingCommandsTable[])(void) = Cmd_trysetcaughtmondexflags, //0xF1 Cmd_displaydexinfo, //0xF2 Cmd_trygivecaughtmonnick, //0xF3 - Cmd_subattackerhpbydmg, //0xF4 + Cmd_unused_0xf4, //0xF4 Cmd_removeattackerstatus1, //0xF5 Cmd_finishaction, //0xF6 Cmd_finishturn, //0xF7 @@ -851,7 +851,7 @@ void (*const gBattleScriptingCommandsTable[])(void) = Cmd_averagestats, //0xFB Cmd_jumpifcaptivateaffected, //0xFC Cmd_setnonvolatilestatus, //0xFD - Cmd_tryworryseed, //0xFE + Cmd_tryoverwriteability, //0xFE Cmd_callnative, //0xFF }; @@ -916,15 +916,6 @@ static const struct SpriteTemplate sSpriteTemplate_MonIconOnLvlUpBanner = static const u16 sProtectSuccessRates[] = {USHRT_MAX, USHRT_MAX / 2, USHRT_MAX / 4, USHRT_MAX / 8}; -static const u16 sFinalStrikeOnlyEffects[] = -{ - MOVE_EFFECT_REMOVE_ARG_TYPE, - MOVE_EFFECT_REMOVE_STATUS, - MOVE_EFFECT_RECOIL_HP_25, - MOVE_EFFECT_PREVENT_ESCAPE, - MOVE_EFFECT_WRAP, -}; - #define _ 0 static const struct PickupItem sPickupTable[] = @@ -967,19 +958,17 @@ static void ValidateSavedBattlerCounts(void) { if (gBattleStruct->savedAttackerCount > 0) { - // #if TESTING - // Test_ExitWithResult(TEST_RESULT_ERROR, "savedAttackerCount is greater than 0! More calls to SaveBattlerAttacker than RestoreBattlerAttacker!"); - // #else - DebugPrintfLevel(MGBA_LOG_WARN, "savedAttackerCount is greater than 0! More calls to SaveBattlerAttacker than RestoreBattlerAttacker!"); - // #endif + if (TESTING) + Test_ExitWithResult(TEST_RESULT_ERROR, 0, "savedAttackerCount is greater than 0! More calls to SaveBattlerAttacker than RestoreBattlerAttacker!", __FILE__, __LINE__); + else + DebugPrintfLevel(MGBA_LOG_WARN, "savedAttackerCount is greater than 0! More calls to SaveBattlerAttacker than RestoreBattlerAttacker!"); } if (gBattleStruct->savedTargetCount > 0) { - // #if TESTING - // Test_ExitWithResult(TEST_RESULT_ERROR, "savedTargetCount is greater than 0! More calls to SaveBattlerTarget than RestoreBattlerTarget!"); - // #else - DebugPrintfLevel(MGBA_LOG_WARN, "savedTargetCount is greater than 0! More calls to SaveBattlerTarget than RestoreBattlerTarget!"); - // #endif + if (TESTING) + Test_ExitWithResult(TEST_RESULT_ERROR, 0, "savedTargetCount is greater than 0! More calls to SaveBattlerTarget than RestoreBattlerTarget!", __FILE__, __LINE__); + else + DebugPrintfLevel(MGBA_LOG_WARN, "savedTargetCount is greater than 0! More calls to SaveBattlerTarget than RestoreBattlerTarget!"); } } @@ -1009,7 +998,7 @@ static bool32 NoTargetPresent(u8 battler, u32 move) return FALSE; } -bool32 ProteanTryChangeType(u32 battler, enum Ability ability, u32 move, u32 moveType) +bool32 ProteanTryChangeType(u32 battler, enum Ability ability, u32 move, enum Type moveType) { if ((ability == ABILITY_PROTEAN || ability == ABILITY_LIBERO) && !gDisableStructs[gBattlerAttacker].usedProteanLibero @@ -1061,31 +1050,15 @@ u32 NumFaintedBattlersByAttacker(u32 battlerAtk) return numMonsFainted; } -bool32 IsMovePowderBlocked(struct BattleContext *ctx) +bool32 IsPowderMoveBlocked(struct BattleContext *ctx) { - bool32 effect = FALSE; + if (!IsPowderMove(ctx->currentMove) + || ctx->battlerAtk == ctx->battlerDef + || IsAffectedByPowderMove(ctx->battlerDef, ctx->abilities[ctx->battlerDef], GetBattlerHoldEffect(ctx->battlerDef))) + return FALSE; - if (IsPowderMove(ctx->currentMove) && (ctx->battlerAtk != ctx->battlerDef)) - { - if (B_POWDER_GRASS >= GEN_6 - && (IS_BATTLER_OF_TYPE(ctx->battlerDef, TYPE_GRASS) || ctx->ability[ctx->battlerDef] == ABILITY_OVERCOAT)) - { - gBattlerAbility = ctx->battlerDef; - RecordAbilityBattle(ctx->battlerDef, ABILITY_OVERCOAT); - effect = TRUE; - } - else if (GetBattlerHoldEffect(ctx->battlerDef) == HOLD_EFFECT_SAFETY_GOGGLES) - { - RecordItemEffectBattle(ctx->battlerDef, HOLD_EFFECT_SAFETY_GOGGLES); - gLastUsedItem = gBattleMons[ctx->battlerDef].item; - effect = TRUE; - } - - if (effect) - gBattlescriptCurrInstr = BattleScript_PowderMoveNoEffect; - } - - return effect; + gBattlescriptCurrInstr = BattleScript_PowderMoveNoEffect; + return TRUE; } bool32 EmergencyExitCanBeTriggered(u32 battler) @@ -1095,12 +1068,10 @@ bool32 EmergencyExitCanBeTriggered(u32 battler) if (ability != ABILITY_EMERGENCY_EXIT && ability != ABILITY_WIMP_OUT) return FALSE; - if (IsBattlerTurnDamaged(battler) - && IsBattlerAlive(battler) + if (IsBattlerAlive(battler) && HadMoreThanHalfHpNowDoesnt(battler) && (CanBattlerSwitch(battler) || !(gBattleTypeFlags & BATTLE_TYPE_TRAINER)) && !(gBattleTypeFlags & BATTLE_TYPE_ARENA) - && CountUsablePartyMons(battler) > 0 && gBattleMons[battler].volatiles.semiInvulnerable != STATE_SKY_DROP) return TRUE; @@ -1128,11 +1099,12 @@ static void Cmd_attackcanceler(void) ctx.battlerAtk = gBattlerAttacker; ctx.battlerDef = gBattlerTarget; ctx.currentMove = gCurrentMove; - ctx.moveEffect = GetMoveEffect(ctx.currentMove); + + enum BattleMoveEffects moveEffect = GetMoveEffect(ctx.currentMove); if (!IsBattlerAlive(gBattlerAttacker) - && ctx.moveEffect != EFFECT_EXPLOSION - && ctx.moveEffect != EFFECT_MISTY_EXPLOSION) + && moveEffect != EFFECT_EXPLOSION + && moveEffect != EFFECT_MISTY_EXPLOSION) { gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; gBattlescriptCurrInstr = BattleScript_MoveEnd; @@ -1140,14 +1112,14 @@ static void Cmd_attackcanceler(void) } // With how attackcanceller works right now we only need attacker and target abilities. Might change in the future - ctx.ability[ctx.battlerAtk] = GetBattlerAbility(ctx.battlerAtk); - ctx.ability[ctx.battlerDef] = GetBattlerAbility(ctx.battlerDef); + ctx.abilities[ctx.battlerAtk] = GetBattlerAbility(ctx.battlerAtk); + ctx.abilities[ctx.battlerDef] = GetBattlerAbility(ctx.battlerDef); if (AtkCanceller_MoveSuccessOrder(&ctx) != MOVE_STEP_SUCCESS) return; if (gSpecialStatuses[gBattlerAttacker].parentalBondState == PARENTAL_BOND_OFF - && ctx.ability[ctx.battlerAtk] == ABILITY_PARENTAL_BOND + && ctx.abilities[ctx.battlerAtk] == ABILITY_PARENTAL_BOND && IsMoveAffectedByParentalBond(gCurrentMove, gBattlerAttacker) && !(gAbsentBattlerFlags & (1u << gBattlerTarget)) && GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE) @@ -1161,8 +1133,8 @@ static void Cmd_attackcanceler(void) if (CanAbilityBlockMove( ctx.battlerAtk, ctx.battlerDef, - ctx.ability[ctx.battlerAtk], - ctx.ability[ctx.battlerDef], + ctx.abilities[ctx.battlerAtk], + ctx.abilities[ctx.battlerDef], ctx.currentMove, RUN_SCRIPT)) return; @@ -1172,29 +1144,29 @@ static void Cmd_attackcanceler(void) if (CanAbilityAbsorbMove( ctx.battlerAtk, ctx.battlerDef, - ctx.ability[ctx.battlerDef], + ctx.abilities[ctx.battlerDef], ctx.currentMove, GetBattleMoveType(ctx.currentMove), RUN_SCRIPT)) return; } - if (IsMovePowderBlocked(&ctx)) + if (IsPowderMoveBlocked(&ctx)) return; // Check if no available target present on the field or if Sky Battles ban the move if ((NoTargetPresent(gBattlerAttacker, gCurrentMove) - && (!gBattleMoveEffects[ctx.moveEffect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns))) + && (!gBattleMoveEffects[moveEffect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns))) || (IsMoveNotAllowedInSkyBattles(gCurrentMove))) { gBattleStruct->noTargetPresent = TRUE; - if (ctx.moveEffect == EFFECT_FLING) // Edge case for removing a mon's item when there is no target available after using Fling. + if (moveEffect == EFFECT_FLING) // Edge case for removing a mon's item when there is no target available after using Fling. gBattlescriptCurrInstr = BattleScript_FlingFailConsumeItem; else gBattlescriptCurrInstr = BattleScript_ButItFailed; - if (!gBattleMoveEffects[ctx.moveEffect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns)) + if (!gBattleMoveEffects[moveEffect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns)) CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK); return; } @@ -1225,7 +1197,7 @@ static void Cmd_attackcanceler(void) { u32 battler = gBattlerTarget; - if (ctx.ability[ctx.battlerDef] == ABILITY_MAGIC_BOUNCE) + if (ctx.abilities[ctx.battlerDef] == ABILITY_MAGIC_BOUNCE) { battler = gBattlerTarget; gBattleStruct->bouncedMoveIsUsed = TRUE; @@ -1276,11 +1248,11 @@ static void Cmd_attackcanceler(void) BattleScriptCall(BattleScript_TookAttack); } else if (IsBattlerProtected(gBattlerAttacker, gBattlerTarget, gCurrentMove) - && (ctx.moveEffect != EFFECT_CURSE || IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GHOST)) - && (!gBattleMoveEffects[ctx.moveEffect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns)) - && ctx.moveEffect != EFFECT_SUCKER_PUNCH - && ctx.moveEffect != EFFECT_COUNTER - && ctx.moveEffect != EFFECT_UPPER_HAND) + && (moveEffect != EFFECT_CURSE || IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GHOST)) + && (!gBattleMoveEffects[moveEffect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns)) + && moveEffect != EFFECT_SUCKER_PUNCH + && moveEffect != EFFECT_COUNTER + && moveEffect != EFFECT_UPPER_HAND) { if (!CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), gCurrentMove)) gProtectStructs[gBattlerAttacker].touchedProtectLike = TRUE; @@ -1320,8 +1292,6 @@ static void JumpIfMoveFailed(u32 adder, u32 move, u32 moveType, const u8 *failIn } else { - TrySetDestinyBondToHappen(); - if (CanAbilityAbsorbMove(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerTarget), @@ -1374,10 +1344,6 @@ static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u if (move == ACC_CURR_MOVE) move = gCurrentMove; - enum BattleMoveEffects effect = GetMoveEffect(move); - enum Ability abilityAtk = GetBattlerAbility(gBattlerAttacker); - enum ItemHoldEffect holdEffectAtk = GetBattlerHoldEffect(gBattlerAttacker); - if (move == NO_ACC_CALC_CHECK_LOCK_ON) { if (gBattleMons[gBattlerTarget].volatiles.lockOn && gDisableStructs[gBattlerTarget].battlerWithSureHit == gBattlerAttacker) @@ -1398,8 +1364,14 @@ static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u GetBattleMoveType(gCurrentMove), RUN_SCRIPT); } + return; } - else if (gSpecialStatuses[gBattlerAttacker].parentalBondState == PARENTAL_BOND_2ND_HIT + + enum Ability abilityAtk = GetBattlerAbility(gBattlerAttacker); + enum HoldEffect holdEffectAtk = GetBattlerHoldEffect(gBattlerAttacker); + enum BattleMoveEffects effect = GetMoveEffect(move); + + if (gSpecialStatuses[gBattlerAttacker].parentalBondState == PARENTAL_BOND_2ND_HIT || (gSpecialStatuses[gBattlerAttacker].multiHitOn && (abilityAtk == ABILITY_SKILL_LINK || holdEffectAtk == HOLD_EFFECT_LOADED_DICE || !(effect == EFFECT_TRIPLE_KICK || effect == EFFECT_POPULATION_BOMB)))) @@ -1469,6 +1441,7 @@ static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u ctx.battlerAtk = gBattlerAttacker; ctx.battlerDef = battlerDef; ctx.move = move; + ctx.chosenMove = gChosenMove; ctx.moveType = moveType; ctx.updateFlags = TRUE; ctx.abilityAtk = abilityAtk; @@ -1516,7 +1489,7 @@ static void Cmd_printattackstring(void) gBattlescriptCurrInstr = cmd->nextInstr; } -static void Cmd_unused0x3(void) +static void Cmd_unused_0x3(void) { } @@ -1538,7 +1511,7 @@ static inline u32 GetCriticalHitOdds(u32 critChance) return sCriticalHitOdds[critChance]; } -static inline u32 IsBattlerLeekAffected(u32 battler, enum ItemHoldEffect holdEffect) +static inline u32 IsBattlerLeekAffected(u32 battler, enum HoldEffect holdEffect) { if (holdEffect == HOLD_EFFECT_LEEK) { @@ -1548,7 +1521,7 @@ static inline u32 IsBattlerLeekAffected(u32 battler, enum ItemHoldEffect holdEff return FALSE; } -static inline u32 GetHoldEffectCritChanceIncrease(u32 battler, enum ItemHoldEffect holdEffect) +static inline u32 GetHoldEffectCritChanceIncrease(u32 battler, enum HoldEffect holdEffect) { u32 critStageIncrease = 0; @@ -1573,7 +1546,7 @@ static inline u32 GetHoldEffectCritChanceIncrease(u32 battler, enum ItemHoldEffe return critStageIncrease; } -s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, enum Ability abilityAtk, enum Ability abilityDef, enum ItemHoldEffect holdEffectAtk) +s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, enum Ability abilityAtk, enum Ability abilityDef, enum HoldEffect holdEffectAtk) { s32 critChance = 0; @@ -1622,7 +1595,7 @@ s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordA // Threshold = Base Speed / 2 // High crit move = 8 * (Base Speed / 2) // Focus Energy = 4 * (Base Speed / 2) -s32 CalcCritChanceStageGen1(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, enum Ability abilityAtk, enum Ability abilityDef, enum ItemHoldEffect holdEffectAtk) +s32 CalcCritChanceStageGen1(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, enum Ability abilityAtk, enum Ability abilityDef, enum HoldEffect holdEffectAtk) { s32 critChance = 0; s32 moveCritStage = GetMoveCriticalHitStage(gCurrentMove); @@ -1690,7 +1663,7 @@ static void Cmd_critcalc(void) moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove), battlerDef; bool32 calcSpreadMoveDamage = IsSpreadMove(moveTarget) && !IsBattleMoveStatus(gCurrentMove); - enum ItemHoldEffect holdEffectAtk = GetBattlerHoldEffect(gBattlerAttacker); + enum HoldEffect holdEffectAtk = GetBattlerHoldEffect(gBattlerAttacker); gPotentialItemEffectBattler = gBattlerAttacker; for (battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) @@ -1767,9 +1740,10 @@ static void Cmd_damagecalc(void) u32 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove); - struct DamageContext ctx; + struct DamageContext ctx = {0}; ctx.battlerAtk = gBattlerAttacker; ctx.move = gCurrentMove; + ctx.chosenMove = gChosenMove; ctx.moveType = GetBattleMoveType(gCurrentMove); ctx.randomFactor = TRUE; ctx.updateFlags = TRUE; @@ -1807,6 +1781,7 @@ static void Cmd_typecalc(void) ctx.battlerAtk = gBattlerAttacker; ctx.battlerDef = gBattlerTarget; ctx.move = gCurrentMove; + ctx.chosenMove = gChosenMove; ctx.moveType = GetBattleMoveType(gCurrentMove); ctx.updateFlags = TRUE; ctx.abilityAtk = GetBattlerAbility(gBattlerAttacker); @@ -1824,7 +1799,7 @@ static void Cmd_adjustdamage(void) { CMD_ARGS(); - enum ItemHoldEffect holdEffect; + enum HoldEffect holdEffect; u8 param; u32 battlerDef; u32 rand = Random() % 100; @@ -1861,13 +1836,13 @@ static void Cmd_adjustdamage(void) gBattleStruct->moveResultFlags[battlerDef] &= ~(MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE); gBattleStruct->moveDamage[battlerDef] = 0; gSpecialStatuses[battlerDef].enduredDamage = TRUE; - RecordAbilityBattle(gBattlerTarget, ABILITY_ICE_FACE); + RecordAbilityBattle(battlerDef, ABILITY_ICE_FACE); gDisableStructs[battlerDef].iceFaceActivationPrevention = TRUE; // Form change will be done after attack animation in Cmd_resultmessage. continue; } - if (gBattleMons[gBattlerTarget].hp > gBattleStruct->moveDamage[battlerDef]) + if (gBattleMons[battlerDef].hp > gBattleStruct->moveDamage[battlerDef]) continue; holdEffect = GetBattlerHoldEffect(battlerDef); @@ -2209,8 +2184,7 @@ static void Cmd_waitanimation(void) static void DoublesHPBarReduction(void) { - if (gBattleStruct->doneDoublesSpreadHit - || gHitMarker & (HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE)) + if (gBattleStruct->doneDoublesSpreadHit) return; for (u32 battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) @@ -2222,12 +2196,10 @@ static void DoublesHPBarReduction(void) || DoesDisguiseBlockMove(battlerDef, gCurrentMove)) continue; - s32 currDmg = gBattleStruct->moveDamage[battlerDef]; - s32 healthValue = min(currDmg, 10000); // Max damage (10000) not present in R/S, ensures that huge damage values don't change sign - BtlController_EmitHealthBarUpdate(battlerDef, B_COMM_TO_CONTROLLER, healthValue); + s32 dmgUpdate = min(gBattleStruct->moveDamage[battlerDef], 10000); + BtlController_EmitHealthBarUpdate(battlerDef, B_COMM_TO_CONTROLLER, dmgUpdate); MarkBattlerForControllerExec(battlerDef); - - if (IsOnPlayerSide(battlerDef) && currDmg > 0) + if (IsOnPlayerSide(battlerDef) && dmgUpdate > 0) gBattleResults.playerMonWasDamaged = TRUE; } @@ -2236,185 +2208,201 @@ static void DoublesHPBarReduction(void) static void Cmd_healthbarupdate(void) { - CMD_ARGS(u8 battler); + CMD_ARGS(u8 battler, u8 updateState); u32 battler = GetBattlerForBattleScript(cmd->battler); if (gBattleControllerExecFlags) return; - if (!(gBattleStruct->moveResultFlags[battler] & MOVE_RESULT_NO_EFFECT) || (gHitMarker & HITMARKER_PASSIVE_HP_UPDATE)) + switch (cmd->updateState) { - if (DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) && gDisableStructs[battler].substituteHP && !(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE)) + case PASSIVE_HP_UPDATE: + BtlController_EmitHealthBarUpdate(battler, B_COMM_TO_CONTROLLER, min(gBattleStruct->passiveHpUpdate[battler], 10000)); + MarkBattlerForControllerExec(battler); + break; + case MOVE_DAMAGE_HP_UPDATE: + if (IsDoubleSpreadMove()) + { + DoublesHPBarReduction(); + if (DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove)) + PrepareStringBattle(STRINGID_SUBSTITUTEDAMAGED, battler); + } + else if (DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove)) { PrepareStringBattle(STRINGID_SUBSTITUTEDAMAGED, battler); - if (IsDoubleSpreadMove()) - DoublesHPBarReduction(); } - else if (!DoesDisguiseBlockMove(battler, gCurrentMove)) + else if (!(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT) + && !DoesDisguiseBlockMove(battler, gCurrentMove)) { - if (IsDoubleSpreadMove()) - { - DoublesHPBarReduction(); - } - else - { - s16 healthValue = min(gBattleStruct->moveDamage[battler], 10000); // Max damage (10000) not present in R/S, ensures that huge damage values don't change sign - - BtlController_EmitHealthBarUpdate(battler, B_COMM_TO_CONTROLLER, healthValue); - MarkBattlerForControllerExec(battler); - - if (IsOnPlayerSide(battler) && gBattleStruct->moveDamage[battler] > 0) - gBattleResults.playerMonWasDamaged = TRUE; - } + s32 damage = min(gBattleStruct->moveDamage[battler], 10000); + BtlController_EmitHealthBarUpdate(battler, B_COMM_TO_CONTROLLER, damage); + MarkBattlerForControllerExec(battler); + if (IsOnPlayerSide(battler) && damage > 0) + gBattleResults.playerMonWasDamaged = TRUE; } - } - else if (IsDoubleSpreadMove()) - { - DoublesHPBarReduction(); + break; } gBattlescriptCurrInstr = cmd->nextInstr; } -// Update the active battler's HP and various HP trackers (Substitute, Bide, etc.) +static void PassiveDataHpUpdate(u32 battler, const u8 *nextInstr) +{ + if (gBattleStruct->passiveHpUpdate[battler] < 0) + { + // Negative damage is HP gain + gBattleMons[battler].hp += -gBattleStruct->passiveHpUpdate[battler]; + if (gBattleMons[battler].hp > gBattleMons[battler].maxHP) + gBattleMons[battler].hp = gBattleMons[battler].maxHP; + } + else + { + if (gBattleMons[battler].hp > gBattleStruct->passiveHpUpdate[battler]) + gBattleMons[battler].hp -= gBattleStruct->passiveHpUpdate[battler]; + else + gBattleMons[battler].hp = 0; + } + + // Send updated HP + BtlController_EmitSetMonData( + battler, + B_COMM_TO_CONTROLLER, + REQUEST_HP_BATTLE, + 0, + sizeof(gBattleMons[battler].hp), &gBattleMons[battler].hp); + MarkBattlerForControllerExec(battler); + + gBattleStruct->passiveHpUpdate[battler] = 0; + gBattlescriptCurrInstr = nextInstr; +} + +static void MoveDamageDataHpUpdate(u32 battler, u32 scriptBattler, const u8 *nextInstr) +{ + if (gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT) + { + gBattlescriptCurrInstr = nextInstr; + } + else if (DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) && gDisableStructs[battler].substituteHP) + { + if (gDisableStructs[battler].substituteHP >= gBattleStruct->moveDamage[battler]) + { + gDisableStructs[battler].substituteHP -= gBattleStruct->moveDamage[battler]; + } + else + { + gBattleStruct->moveDamage[battler] = gDisableStructs[battler].substituteHP; + gDisableStructs[battler].substituteHP = 0; + } + // check substitute fading + if (gDisableStructs[battler].substituteHP == 0) + { + gBattlescriptCurrInstr = nextInstr; + BattleScriptCall(BattleScript_SubstituteFade); + return; + } + else + { + gBattlescriptCurrInstr = nextInstr; + return; + } + } + else if (DoesDisguiseBlockMove(battler, gCurrentMove)) + { + // TODO: Convert this to a proper FORM_CHANGE type. + gBattleScripting.battler = battler; + if (GetBattlerPartyState(battler)->changedSpecies == SPECIES_NONE) + GetBattlerPartyState(battler)->changedSpecies = gBattleMons[battler].species; + if (gBattleMons[battler].species == SPECIES_MIMIKYU_TOTEM_DISGUISED) + gBattleMons[battler].species = SPECIES_MIMIKYU_BUSTED_TOTEM; + else + gBattleMons[battler].species = SPECIES_MIMIKYU_BUSTED; + if (GetGenConfig(GEN_CONFIG_DISGUISE_HP_LOSS) >= GEN_8) + SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / 8); + BattleScriptPush(nextInstr); + gBattlescriptCurrInstr = BattleScript_TargetFormChange; + } + else + { + if (gBattleStruct->moveDamage[battler] < 0) + { + // Negative damage is HP gain + gBattleMons[battler].hp += -gBattleStruct->moveDamage[battler]; + if (gBattleMons[battler].hp > gBattleMons[battler].maxHP) + gBattleMons[battler].hp = gBattleMons[battler].maxHP; + } + else + { + gBideDmg[battler] += gBattleStruct->moveDamage[battler]; + if (scriptBattler == BS_TARGET) + gBideTarget[battler] = gBattlerAttacker; + else + gBideTarget[battler] = gBattlerTarget; + + // Deal damage to the battler + if (gBattleMons[battler].hp > gBattleStruct->moveDamage[battler]) + { + gBattleMons[battler].hp -= gBattleStruct->moveDamage[battler]; + } + else + { + gBattleStruct->moveDamage[battler] = gBattleMons[battler].hp; + gBattleMons[battler].hp = 0; + } + + // Note: While physicalDmg/specialDmg below are only distinguished between for Counter/Mirror Coat, they are + // used in combination as general damage trackers for other purposes. specialDmg is additionally used + // to help determine if a fire move should defrost the target. + if (IsBattleMovePhysical(gCurrentMove)) + { + gProtectStructs[battler].physicalDmg = gBattleStruct->moveDamage[battler]; + gSpecialStatuses[battler].physicalDmg = gBattleStruct->moveDamage[battler]; + if (scriptBattler == BS_TARGET) // What's the point of this??? It will be always target + gProtectStructs[battler].physicalBattlerId = gBattlerAttacker; + else + gProtectStructs[battler].physicalBattlerId = gBattlerTarget; + gProtectStructs[battler].assuranceDoubled = TRUE; + } + else // Physical move + { + gProtectStructs[battler].specialDmg = gBattleStruct->moveDamage[battler]; + gSpecialStatuses[battler].specialDmg = gBattleStruct->moveDamage[battler]; + if (scriptBattler == BS_TARGET) // What's the point of this??? It will be always target + gProtectStructs[battler].specialBattlerId = gBattlerAttacker; + else + gProtectStructs[battler].specialBattlerId = gBattlerTarget; + gProtectStructs[battler].assuranceDoubled = TRUE; + } + } + // Send updated HP + BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_HP_BATTLE, 0, sizeof(gBattleMons[battler].hp), &gBattleMons[battler].hp); + MarkBattlerForControllerExec(battler); + gBattlescriptCurrInstr = nextInstr; + } + + if (IsBattlerTurnDamaged(gBattlerTarget) && GetMoveCategory(gCurrentMove) != DAMAGE_CATEGORY_STATUS) + GetBattlerPartyState(battler)->timesGotHit++; +} + static void Cmd_datahpupdate(void) { - CMD_ARGS(u8 battler); - bool32 isPassiveHpUpdate = gHitMarker & HITMARKER_PASSIVE_HP_UPDATE; - bool32 disguiseActivates = FALSE; + CMD_ARGS(u8 battler, u8 updateState); + u32 battler = GetBattlerForBattleScript(cmd->battler); if (gBattleControllerExecFlags) return; - u32 battler = GetBattlerForBattleScript(cmd->battler); - - if (!(gBattleStruct->moveResultFlags[battler] & MOVE_RESULT_NO_EFFECT) || (gHitMarker & HITMARKER_PASSIVE_HP_UPDATE)) + switch (cmd->updateState) { - if (DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) && gDisableStructs[battler].substituteHP && !(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE)) - { - if (gDisableStructs[battler].substituteHP >= gBattleStruct->moveDamage[battler]) - { - gDisableStructs[battler].substituteHP -= gBattleStruct->moveDamage[battler]; - } - else - { - gBattleStruct->moveDamage[battler] = gDisableStructs[battler].substituteHP; - gDisableStructs[battler].substituteHP = 0; - } - // check substitute fading - if (gDisableStructs[battler].substituteHP == 0) - { - gBattlescriptCurrInstr = cmd->nextInstr; - BattleScriptCall(BattleScript_SubstituteFade); - return; - } - } - else if (DoesDisguiseBlockMove(battler, gCurrentMove)) - { - // TODO: Convert this to a proper FORM_CHANGE type. - gBattleScripting.battler = battler; - if (GetBattlerPartyState(battler)->changedSpecies == SPECIES_NONE) - GetBattlerPartyState(battler)->changedSpecies = gBattleMons[battler].species; - if (gBattleMons[battler].species == SPECIES_MIMIKYU_TOTEM_DISGUISED) - gBattleMons[battler].species = SPECIES_MIMIKYU_BUSTED_TOTEM; - else - gBattleMons[battler].species = SPECIES_MIMIKYU_BUSTED; - if (GetGenConfig(GEN_CONFIG_DISGUISE_HP_LOSS) >= GEN_8) - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 8; - BattleScriptPush(cmd->nextInstr); - gBattlescriptCurrInstr = BattleScript_TargetFormChange; - disguiseActivates = TRUE; - } - else - { - gHitMarker &= ~HITMARKER_IGNORE_SUBSTITUTE; - if (gBattleStruct->moveDamage[battler] < 0) - { - // Negative damage is HP gain - gBattleMons[battler].hp += -gBattleStruct->moveDamage[battler]; - if (gBattleMons[battler].hp > gBattleMons[battler].maxHP) - gBattleMons[battler].hp = gBattleMons[battler].maxHP; - } - else - { - if (gHitMarker & HITMARKER_IGNORE_BIDE) - { - gHitMarker &= ~HITMARKER_IGNORE_BIDE; - } - else - { - gBideDmg[battler] += gBattleStruct->moveDamage[battler]; - if (cmd->battler == BS_TARGET) - gBideTarget[battler] = gBattlerAttacker; - else - gBideTarget[battler] = gBattlerTarget; - } - - // Deal damage to the battler - if (gBattleMons[battler].hp > gBattleStruct->moveDamage[battler]) - { - gBattleMons[battler].hp -= gBattleStruct->moveDamage[battler]; - } - else - { - gBattleStruct->moveDamage[battler] = gBattleMons[battler].hp; - gBattleMons[battler].hp = 0; - } - - enum BattleMoveEffects effect = GetMoveEffect(gCurrentMove); - - // Note: While physicalDmg/specialDmg below are only distinguished between for Counter/Mirror Coat, they are - // used in combination as general damage trackers for other purposes. specialDmg is additionally used - // to help determine if a fire move should defrost the target. - if (IsBattleMovePhysical(gCurrentMove) && !(gHitMarker & HITMARKER_PASSIVE_HP_UPDATE) && effect != EFFECT_PAIN_SPLIT) - { - gProtectStructs[battler].physicalDmg = gBattleStruct->moveDamage[battler]; - gSpecialStatuses[battler].physicalDmg = gBattleStruct->moveDamage[battler]; - if (cmd->battler == BS_TARGET) - gProtectStructs[battler].physicalBattlerId = gBattlerAttacker; - else - gProtectStructs[battler].physicalBattlerId = gBattlerTarget; - gProtectStructs[battler].assuranceDoubled = TRUE; - } - else if (!IsBattleMovePhysical(gCurrentMove) && !(gHitMarker & HITMARKER_PASSIVE_HP_UPDATE) && effect != EFFECT_PAIN_SPLIT) - { - // Record special damage/attacker for Mirror Coat - gProtectStructs[battler].specialDmg = gBattleStruct->moveDamage[battler]; - gSpecialStatuses[battler].specialDmg = gBattleStruct->moveDamage[battler]; - if (cmd->battler == BS_TARGET) - gProtectStructs[battler].specialBattlerId = gBattlerAttacker; - else - gProtectStructs[battler].specialBattlerId = gBattlerTarget; - gProtectStructs[battler].assuranceDoubled = TRUE; - } - } - gHitMarker &= ~HITMARKER_PASSIVE_HP_UPDATE; - // Send updated HP - BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_HP_BATTLE, 0, sizeof(gBattleMons[battler].hp), &gBattleMons[battler].hp); - MarkBattlerForControllerExec(battler); - } - - if (gBattlerAttacker != gBattlerTarget - && !isPassiveHpUpdate - && GetMoveCategory(gCurrentMove) != DAMAGE_CATEGORY_STATUS - && IsBattlerTurnDamaged(gBattlerTarget)) - GetBattlerPartyState(gBattlerTarget)->timesGotHit++; - - if (GetMoveEffect(gCurrentMove) == EFFECT_KNOCK_OFF - && !isPassiveHpUpdate - && IsBattlerTurnDamaged(gBattlerTarget) - && gBattleMons[gBattlerTarget].item != ITEM_NONE - && !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) - && CanBattlerGetOrLoseItem(gBattlerTarget, gBattleMons[gBattlerTarget].item) - && !NoAliveMonsForEitherParty()) - gBattleStruct->battlerState[gBattlerTarget].itemCanBeKnockedOff = TRUE; - - if (disguiseActivates) - return; + case PASSIVE_HP_UPDATE: + PassiveDataHpUpdate(battler, cmd->nextInstr); + break; + case MOVE_DAMAGE_HP_UPDATE: + MoveDamageDataHpUpdate(battler, cmd->battler, cmd->nextInstr); + break; } + if (gBattleMons[battler].hp > gBattleMons[battler].maxHP / 2) + gBattleStruct->battlerState[battler].wasAboveHalfHp = TRUE; - TryRestoreDamageAfterCheekPouch(battler); - gBattlescriptCurrInstr = cmd->nextInstr; } static void Cmd_critmessage(void) @@ -2792,11 +2780,11 @@ static void CheckSetUnburden(u8 battler) gDisableStructs[battler].unburdenActive = TRUE; } -// battlerStealer steals the item of battlerItem -void StealTargetItem(u8 battlerStealer, u8 battlerItem) +// battlerStealer steals the item of itemBattler +void StealTargetItem(u8 battlerStealer, u8 itemBattler) { - gLastUsedItem = gBattleMons[battlerItem].item; - gBattleMons[battlerItem].item = ITEM_NONE; + gLastUsedItem = gBattleMons[itemBattler].item; + gBattleMons[itemBattler].item = ITEM_NONE; if (GetGenConfig(GEN_STEAL_WILD_ITEMS) >= GEN_9 && !(gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_PALACE)) @@ -2815,15 +2803,16 @@ void StealTargetItem(u8 battlerStealer, u8 battlerItem) MarkBattlerForControllerExec(battlerStealer); } - RecordItemEffectBattle(battlerItem, ITEM_NONE); - CheckSetUnburden(battlerItem); + RecordItemEffectBattle(itemBattler, ITEM_NONE); + CheckSetUnburden(itemBattler); - BtlController_EmitSetMonData(battlerItem, B_COMM_TO_CONTROLLER, REQUEST_HELDITEM_BATTLE, 0, sizeof(gBattleMons[gBattlerTarget].item), &gBattleMons[battlerItem].item); // remove target item - MarkBattlerForControllerExec(battlerItem); + BtlController_EmitSetMonData(itemBattler, B_COMM_TO_CONTROLLER, REQUEST_HELDITEM_BATTLE, 0, sizeof(gBattleMons[itemBattler].item), &gBattleMons[itemBattler].item); // remove target item + MarkBattlerForControllerExec(itemBattler); - gBattleStruct->choicedMove[battlerItem] = 0; + if (GetBattlerAbility(itemBattler) != ABILITY_GORILLA_TACTICS) + gBattleStruct->choicedMove[itemBattler] = MOVE_NONE; - TrySaveExchangedItem(battlerItem, gLastUsedItem); + TrySaveExchangedItem(itemBattler, gLastUsedItem); } static inline bool32 TrySetReflect(u32 battler) @@ -2833,9 +2822,9 @@ static inline bool32 TrySetReflect(u32 battler) { gSideStatuses[side] |= SIDE_STATUS_REFLECT; if (GetBattlerHoldEffect(battler) == HOLD_EFFECT_LIGHT_CLAY) - gSideTimers[side].reflectTimer = gBattleTurnCounter + 8; + gSideTimers[side].reflectTimer = 8; else - gSideTimers[side].reflectTimer = gBattleTurnCounter + 5; + gSideTimers[side].reflectTimer = 5; if (IsDoubleBattle() && CountAliveMonsInBattle(BATTLE_ALIVE_SIDE, battler) == 2) gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_REFLECT_DOUBLE; @@ -2854,9 +2843,9 @@ static inline bool32 TrySetLightScreen(u32 battler) { gSideStatuses[side] |= SIDE_STATUS_LIGHTSCREEN; if (GetBattlerHoldEffect(battler) == HOLD_EFFECT_LIGHT_CLAY) - gSideTimers[side].lightscreenTimer = gBattleTurnCounter + 8; + gSideTimers[side].lightscreenTimer = 8; else - gSideTimers[side].lightscreenTimer = gBattleTurnCounter + 5; + gSideTimers[side].lightscreenTimer = 5; if (IsDoubleBattle() && CountAliveMonsInBattle(BATTLE_ALIVE_SIDE, battler) == 2) gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_LIGHTSCREEN_DOUBLE; @@ -2868,7 +2857,7 @@ static inline bool32 TrySetLightScreen(u32 battler) return FALSE; } -static void SetNonVolatileStatus(u32 effectBattler, enum MoveEffect effect, enum StatusTrigger trigger) +static void SetNonVolatileStatus(u32 effectBattler, enum MoveEffect effect, const u8 *battleScript, enum StatusTrigger trigger) { gEffectBattler = effectBattler; @@ -2881,7 +2870,7 @@ static void SetNonVolatileStatus(u32 effectBattler, enum MoveEffect effect, enum gBattlescriptCurrInstr = cancelMultiTurnMovesResult; } - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); switch (effect) { @@ -2943,9 +2932,11 @@ static void SetNonVolatileStatus(u32 effectBattler, enum MoveEffect effect, enum } // To avoid confusion the arguments are naned battler/effectBattler since they can be different from gBattlerAttacker/gBattlerTarget -void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certain) +void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, const u8 *battleScript, enum SetMoveEffectFlags effectFlags) { s32 i; + bool32 primary = effectFlags & EFFECT_PRIMARY; + bool32 certain = effectFlags & EFFECT_CERTAIN; bool32 affectsUser = (battler == effectBattler); bool32 mirrorArmorReflected = (GetBattlerAbility(gBattlerTarget) == ABILITY_MIRROR_ARMOR); union StatChangeFlags flags = {0}; @@ -2953,48 +2944,49 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai bool32 activateAfterFaint = FALSE; // NULL move effect - if (gBattleScripting.moveEffect == MOVE_EFFECT_NONE) + if (moveEffect == MOVE_EFFECT_NONE) return; if (gSpecialStatuses[gBattlerAttacker].parentalBondState == PARENTAL_BOND_1ST_HIT && IsBattlerAlive(gBattlerTarget) - && IsFinalStrikeEffect(gBattleScripting.moveEffect)) + && IsFinalStrikeEffect(moveEffect)) { - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; return; } - switch (gBattleScripting.moveEffect) // Set move effects which happen later on + switch (moveEffect) // Set move effects which happen later on { case MOVE_EFFECT_STEALTH_ROCK: case MOVE_EFFECT_PAYDAY: case MOVE_EFFECT_BUG_BITE: activateAfterFaint = TRUE; break; + default: + break; } gBattleScripting.battler = battler; gEffectBattler = effectBattler; battlerAbility = GetBattlerAbility(gEffectBattler); - if (!primary && !affectsUser - && !(gHitMarker & HITMARKER_STATUS_ABILITY_EFFECT) - && IsMoveEffectBlockedByTarget(battlerAbility)) - gBattleScripting.moveEffect = MOVE_EFFECT_NONE; - else if (!(gHitMarker & HITMARKER_STATUS_ABILITY_EFFECT) + if (!primary && !affectsUser && IsMoveEffectBlockedByTarget(battlerAbility)) + moveEffect = MOVE_EFFECT_NONE; + else if (!primary && TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove) - && !(GetMoveEffect(gCurrentMove) == EFFECT_ORDER_UP && gBattleStruct->battlerState[gBattlerAttacker].commanderSpecies != SPECIES_NONE) - && !primary) - gBattleScripting.moveEffect = MOVE_EFFECT_NONE; + && !(GetMoveEffect(gCurrentMove) == EFFECT_ORDER_UP && gBattleStruct->battlerState[gBattlerAttacker].commanderSpecies != SPECIES_NONE)) + moveEffect = MOVE_EFFECT_NONE; else if (!IsBattlerAlive(gEffectBattler) && !activateAfterFaint) - gBattleScripting.moveEffect = MOVE_EFFECT_NONE; + moveEffect = MOVE_EFFECT_NONE; else if (DoesSubstituteBlockMove(gBattlerAttacker, gEffectBattler, gCurrentMove) && !affectsUser) - gBattleScripting.moveEffect = MOVE_EFFECT_NONE; + moveEffect = MOVE_EFFECT_NONE; - switch (gBattleScripting.moveEffect) + gBattleScripting.moveEffect = moveEffect; // ChangeStatBuffs still needs the global moveEffect + + switch (moveEffect) { case MOVE_EFFECT_NONE: - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; break; case MOVE_EFFECT_SLEEP: case MOVE_EFFECT_POISON: @@ -3003,23 +2995,23 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai case MOVE_EFFECT_PARALYSIS: case MOVE_EFFECT_TOXIC: case MOVE_EFFECT_FROSTBITE: - if (gSideStatuses[GetBattlerSide(gEffectBattler)] & SIDE_STATUS_SAFEGUARD && !(gHitMarker & HITMARKER_STATUS_ABILITY_EFFECT) && !primary) - gBattlescriptCurrInstr++; + if (gSideStatuses[GetBattlerSide(gEffectBattler)] & SIDE_STATUS_SAFEGUARD && !primary) + gBattlescriptCurrInstr = battleScript; else if (CanSetNonVolatileStatus( gBattlerAttacker, gEffectBattler, GetBattlerAbility(gBattlerAttacker), battlerAbility, - gBattleScripting.moveEffect, + moveEffect, CHECK_TRIGGER)) - SetNonVolatileStatus(gEffectBattler, gBattleScripting.moveEffect, TRIGGER_ON_MOVE); + SetNonVolatileStatus(gEffectBattler, moveEffect, battleScript, TRIGGER_ON_MOVE); break; case MOVE_EFFECT_CONFUSION: if (!CanBeConfused(gEffectBattler) || gBattleMons[gEffectBattler].volatiles.confusionTurns - || (gSideStatuses[GetBattlerSide(gEffectBattler)] & SIDE_STATUS_SAFEGUARD && !(gHitMarker & HITMARKER_STATUS_ABILITY_EFFECT) && !primary)) + || (gSideStatuses[GetBattlerSide(gEffectBattler)] & SIDE_STATUS_SAFEGUARD && !primary)) { - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } else { @@ -3035,7 +3027,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai } else { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectConfusion; } } @@ -3050,27 +3042,27 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai gLastUsedAbility = ABILITY_INNER_FOCUS; gBattlerAbility = gEffectBattler; RecordAbilityBattle(gEffectBattler, ABILITY_INNER_FOCUS); - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_FlinchPrevention; } else { - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } } else if (gBattleMons[gEffectBattler].volatiles.flinched) { - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } else if (!HasBattlerActedThisTurn(gEffectBattler) && GetActiveGimmick(gEffectBattler) != GIMMICK_DYNAMAX) { gBattleMons[gEffectBattler].volatiles.flinched = TRUE; - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } else { - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } break; case MOVE_EFFECT_UPROAR: @@ -3080,12 +3072,12 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai gLockedMoves[gEffectBattler] = gCurrentMove; gBattleMons[gEffectBattler].volatiles.uproarTurns = B_UPROAR_TURNS >= GEN_5 ? 3 : (Random() & 3) + 2; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectUproar; } else { - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } break; case MOVE_EFFECT_PAYDAY: @@ -3102,15 +3094,15 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai // we only want to print the message on the final hit if (!(NumAffectedSpreadMoveTargets() > 1 && GetNextTarget(moveTarget, TRUE) != MAX_BATTLERS_COUNT)) { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectPayDay; } else - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } else { - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } break; case MOVE_EFFECT_HAPPY_HOUR: @@ -3119,12 +3111,12 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai gBattleStruct->moneyMultiplier *= 2; gBattleStruct->moneyMultiplierMove = 1; } - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; break; case MOVE_EFFECT_TRI_ATTACK: if (gBattleMons[gEffectBattler].status1) { - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } else { @@ -3134,27 +3126,24 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai MOVE_EFFECT_FREEZE_OR_FROSTBITE, MOVE_EFFECT_PARALYSIS }; - gBattleScripting.moveEffect = RandomElement(RNG_TRI_ATTACK, sTriAttackEffects); - SetMoveEffect(battler, effectBattler, primary, certain); + SetMoveEffect(battler, effectBattler, RandomElement(RNG_TRI_ATTACK, sTriAttackEffects), battleScript, effectFlags); } break; case MOVE_EFFECT_WRAP: if (gBattleMons[gEffectBattler].volatiles.wrapped) { - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } else { - gBattleMons[gEffectBattler].volatiles.wrapped = TRUE; if (GetBattlerHoldEffect(gBattlerAttacker) == HOLD_EFFECT_GRIP_CLAW) gDisableStructs[gEffectBattler].wrapTurns = B_BINDING_TURNS >= GEN_5 ? 7 : 5; else gDisableStructs[gEffectBattler].wrapTurns = B_BINDING_TURNS >= GEN_5 ? RandomUniform(RNG_WRAP, 4, 5) : RandomUniform(RNG_WRAP, 2, 5); - - gBattleStruct->wrappedMove[gEffectBattler] = gCurrentMove; - gBattleStruct->wrappedBy[gEffectBattler] = gBattlerAttacker; - - BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattleMons[gEffectBattler].volatiles.wrapped = TRUE; + gBattleMons[gEffectBattler].volatiles.wrappedMove = gCurrentMove; + gBattleMons[gEffectBattler].volatiles.wrappedBy = gBattlerAttacker; + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectWrap; } break; @@ -3169,17 +3158,17 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai || ChangeStatBuffs( effectBattler, SET_STAT_BUFF_VALUE(1), - gBattleScripting.moveEffect - MOVE_EFFECT_ATK_PLUS_1 + 1, + moveEffect - MOVE_EFFECT_ATK_PLUS_1 + 1, STAT_CHANGE_UPDATE_MOVE_EFFECT, 0, 0) == STAT_CHANGE_DIDNT_WORK) { - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } else { - gBattleScripting.animArg1 = gBattleScripting.moveEffect; + gBattleScripting.animArg1 = moveEffect; gBattleScripting.animArg2 = 0; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_StatUp; } break; @@ -3199,18 +3188,18 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai if (ChangeStatBuffs( effectBattler, SET_STAT_BUFF_VALUE(1) | STAT_BUFF_NEGATIVE, - gBattleScripting.moveEffect - MOVE_EFFECT_ATK_MINUS_1 + 1, + moveEffect - MOVE_EFFECT_ATK_MINUS_1 + 1, flags, - 0, gBattlescriptCurrInstr + 1) == STAT_CHANGE_DIDNT_WORK) + 0, battleScript) == STAT_CHANGE_DIDNT_WORK) { if (!mirrorArmorReflected) - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } else { - gBattleScripting.animArg1 = gBattleScripting.moveEffect; + gBattleScripting.animArg1 = moveEffect; gBattleScripting.animArg2 = 0; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_StatDown; } break; @@ -3225,17 +3214,17 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai || ChangeStatBuffs( effectBattler, SET_STAT_BUFF_VALUE(2), - gBattleScripting.moveEffect - MOVE_EFFECT_ATK_PLUS_2 + 1, + moveEffect - MOVE_EFFECT_ATK_PLUS_2 + 1, STAT_CHANGE_UPDATE_MOVE_EFFECT, 0, 0) == STAT_CHANGE_DIDNT_WORK) { - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } else { - gBattleScripting.animArg1 = gBattleScripting.moveEffect; + gBattleScripting.animArg1 = moveEffect; gBattleScripting.animArg2 = 0; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_StatUp; } break; @@ -3255,18 +3244,18 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai if (ChangeStatBuffs( effectBattler, SET_STAT_BUFF_VALUE(2) | STAT_BUFF_NEGATIVE, - gBattleScripting.moveEffect - MOVE_EFFECT_ATK_MINUS_2 + 1, + moveEffect - MOVE_EFFECT_ATK_MINUS_2 + 1, flags, - 0, gBattlescriptCurrInstr + 1) == STAT_CHANGE_DIDNT_WORK) + 0, battleScript) == STAT_CHANGE_DIDNT_WORK) { if (!mirrorArmorReflected) - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } else { - gBattleScripting.animArg1 = gBattleScripting.moveEffect; + gBattleScripting.animArg1 = moveEffect; gBattleScripting.animArg2 = 0; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_StatDown; } break; @@ -3274,14 +3263,13 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai if (B_SKIP_RECHARGE == GEN_1 && !IsBattlerAlive(gBattlerTarget)) // Skip recharge if gen 1 and foe is KO'd break; - gBattleMons[gEffectBattler].volatiles.recharge = TRUE; gDisableStructs[gEffectBattler].rechargeTimer = 2; gLockedMoves[gEffectBattler] = gCurrentMove; - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; break; case MOVE_EFFECT_RAGE: gBattleMons[gBattlerAttacker].volatiles.rage = TRUE; - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; break; case MOVE_EFFECT_PREVENT_ESCAPE: if (!gBattleMons[gBattlerTarget].volatiles.escapePrevention) // Do we need to check if the status is already set? @@ -3289,48 +3277,51 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai gBattleMons[gBattlerTarget].volatiles.escapePrevention = TRUE; gDisableStructs[gBattlerTarget].battlerPreventingEscape = gBattlerAttacker; } - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; break; case MOVE_EFFECT_NIGHTMARE: gBattleMons[gBattlerTarget].volatiles.nightmare = TRUE; - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; break; case MOVE_EFFECT_ALL_STATS_UP: if (!NoAliveMonsForEitherParty()) { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_AllStatsUp; } break; case MOVE_EFFECT_ATK_DEF_DOWN: // SuperPower if (!NoAliveMonsForEitherParty()) { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_AtkDefDown; } break; case MOVE_EFFECT_DEF_SPDEF_DOWN: // Close Combat if (!NoAliveMonsForEitherParty()) { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_DefSpDefDown; } break; case MOVE_EFFECT_RECOIL_HP_25: // Struggle - gBattleStruct->moveDamage[gEffectBattler] = (gBattleMons[gEffectBattler].maxHP) / 4; - if (gBattleStruct->moveDamage[gEffectBattler] == 0) - gBattleStruct->moveDamage[gEffectBattler] = 1; + { + s32 recoil = (gBattleMons[gEffectBattler].maxHP) / 4; + if (recoil == 0) + recoil = 1; if (GetBattlerAbility(gEffectBattler) == ABILITY_PARENTAL_BOND) - gBattleStruct->moveDamage[gEffectBattler] *= 2; - - BattleScriptPush(gBattlescriptCurrInstr + 1); + recoil *= 2; + SetPassiveDamageAmount(gEffectBattler, recoil); + TryUpdateEvolutionTracker(IF_RECOIL_DAMAGE_GE, gBattleStruct->passiveHpUpdate[gBattlerAttacker], MOVE_NONE); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectRecoil; break; + } case MOVE_EFFECT_THRASH: // Petal Dance doesn't lock mons that copy the move with Dancer if (gSpecialStatuses[gEffectBattler].dancerUsedMove || gBattleMons[gEffectBattler].volatiles.lockConfusionTurns) { - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } else { @@ -3349,7 +3340,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai { for (i = 0; i < NUM_BATTLE_STATS; i++) gBattleMons[gEffectBattler].statStages[i] = DEFAULT_STAT_STAGE; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectClearSmog; } break; @@ -3358,11 +3349,10 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai && !IsSemiInvulnerable(BATTLE_PARTNER(gBattlerTarget), CHECK_ALL) && GetBattlerAbility(BATTLE_PARTNER(gBattlerTarget)) != ABILITY_MAGIC_GUARD) { - gBattleScripting.battler = i = BATTLE_PARTNER(gBattlerTarget); - gBattleStruct->moveDamage[i] = gBattleMons[i].maxHP / 16; - if (gBattleStruct->moveDamage[i] == 0) - gBattleStruct->moveDamage[i] = 1; - BattleScriptPush(gBattlescriptCurrInstr + 1); + u32 partnerTarget = BATTLE_PARTNER(gBattlerTarget); + gBattleScripting.battler = partnerTarget; + SetPassiveDamageAmount(partnerTarget, gBattleMons[partnerTarget].maxHP / 16); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectFlameBurst; } break; @@ -3381,7 +3371,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai } if (i) { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); if (gCurrentMove == MOVE_HYPERSPACE_FURY) gBattlescriptCurrInstr = BattleScript_HyperspaceFuryRemoveProtect; else @@ -3391,7 +3381,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai case MOVE_EFFECT_V_CREATE: if (!NoAliveMonsForEitherParty()) { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_VCreateStatLoss; } break; @@ -3399,13 +3389,13 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai if (HasBattlerActedThisTurn(gBattlerTarget) && !NoAliveMonsForEitherParty()) { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectCoreEnforcer; } break; case MOVE_EFFECT_THROAT_CHOP: - gDisableStructs[gEffectBattler].throatChopTimer = gBattleTurnCounter + 2; - gBattlescriptCurrInstr++; + gDisableStructs[gEffectBattler].throatChopTimer = 2; + gBattlescriptCurrInstr = battleScript; break; case MOVE_EFFECT_INCINERATE: if ((gBattleMons[gEffectBattler].item >= FIRST_BERRY_INDEX && gBattleMons[gEffectBattler].item <= LAST_BERRY_INDEX) @@ -3417,7 +3407,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai BtlController_EmitSetMonData(gEffectBattler, B_COMM_TO_CONTROLLER, REQUEST_HELDITEM_BATTLE, 0, sizeof(gBattleMons[gEffectBattler].item), &gBattleMons[gEffectBattler].item); MarkBattlerForControllerExec(gEffectBattler); - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectIncinerate; } break; @@ -3425,7 +3415,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai if (GetBattlerHoldEffect(gEffectBattler) == HOLD_EFFECT_JABOCA_BERRY) { // jaboca berry triggers instead of being stolen - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } else if (GetItemPocket(gBattleMons[gEffectBattler].item) == POCKET_BERRIES && battlerAbility != ABILITY_STICKY_HOLD) @@ -3437,14 +3427,14 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai BtlController_EmitSetMonData(gEffectBattler, B_COMM_TO_CONTROLLER, REQUEST_HELDITEM_BATTLE, 0, sizeof(gBattleMons[gEffectBattler].item), &gBattleMons[gEffectBattler].item); MarkBattlerForControllerExec(gEffectBattler); - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectBugBite; } break; case MOVE_EFFECT_TRAP_BOTH: if (!(gBattleMons[gBattlerTarget].volatiles.escapePrevention || gBattleMons[gBattlerAttacker].volatiles.escapePrevention)) { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_BothCanNoLongerEscape; } if (!gBattleMons[gBattlerTarget].volatiles.escapePrevention) @@ -3460,7 +3450,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai { u32 type = GetMoveArgType(gCurrentMove); // This seems unnecessary but is done to make it work properly with Parental Bond - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); switch (type) { case TYPE_FIRE: // Burn Up @@ -3478,21 +3468,20 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai } case MOVE_EFFECT_ROUND: TryUpdateRoundTurnOrder(); // If another Pokémon uses Round before the user this turn, the user will use Round directly after it - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; break; case MOVE_EFFECT_DIRE_CLAW: if (!gBattleMons[gEffectBattler].status1) { static const u8 sDireClawEffects[] = { MOVE_EFFECT_POISON, MOVE_EFFECT_PARALYSIS, MOVE_EFFECT_SLEEP }; - gBattleScripting.moveEffect = RandomElement(RNG_DIRE_CLAW, sDireClawEffects); - SetMoveEffect(battler, effectBattler, primary, certain); + SetMoveEffect(battler, effectBattler, RandomElement(RNG_DIRE_CLAW, sDireClawEffects), battleScript, effectFlags); } break; case MOVE_EFFECT_STEALTH_ROCK: if (!IsHazardOnSide(GetBattlerSide(gEffectBattler), HAZARDS_STEALTH_ROCK)) { gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_POINTEDSTONESFLOAT; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_StealthRockActivates; } break; @@ -3502,10 +3491,10 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai struct Pokemon *mon = GetBattlerMon(gBattlerAttacker); gBattleMons[gEffectBattler].volatiles.syrupBomb = TRUE; + gBattleMons[gEffectBattler].volatiles.stickySyrupedBy = gBattlerAttacker; gDisableStructs[gEffectBattler].syrupBombTimer = 3; gDisableStructs[gEffectBattler].syrupBombIsShiny = IsMonShiny(mon); - gBattleStruct->stickySyrupdBy[gEffectBattler] = gBattlerAttacker; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_SyrupBombActivates; } break; @@ -3515,25 +3504,24 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai switch (gFieldStatuses & STATUS_FIELD_TERRAIN_ANY) { case STATUS_FIELD_MISTY_TERRAIN: - gBattleScripting.moveEffect = MOVE_EFFECT_SP_ATK_MINUS_1; + moveEffect = MOVE_EFFECT_SP_ATK_MINUS_1; break; case STATUS_FIELD_GRASSY_TERRAIN: - gBattleScripting.moveEffect = MOVE_EFFECT_SLEEP; + moveEffect = MOVE_EFFECT_SLEEP; break; case STATUS_FIELD_ELECTRIC_TERRAIN: - gBattleScripting.moveEffect = MOVE_EFFECT_PARALYSIS; + moveEffect = MOVE_EFFECT_PARALYSIS; break; case STATUS_FIELD_PSYCHIC_TERRAIN: - gBattleScripting.moveEffect = MOVE_EFFECT_SPD_MINUS_1; + moveEffect = MOVE_EFFECT_SPD_MINUS_1; break; default: - gBattleScripting.moveEffect = MOVE_EFFECT_PARALYSIS; + moveEffect = MOVE_EFFECT_PARALYSIS; break; } } else - gBattleScripting.moveEffect = gBattleEnvironmentInfo[gBattleEnvironment].secretPowerEffect; - SetMoveEffect(battler, effectBattler, primary, certain); + SetMoveEffect(battler, effectBattler, gBattleEnvironmentInfo[gBattleEnvironment].secretPowerEffect, battleScript, effectFlags); break; case MOVE_EFFECT_PSYCHIC_NOISE: battlerAbility = IsAbilityOnSide(gEffectBattler, ABILITY_AROMA_VEIL); @@ -3541,14 +3529,14 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai if (battlerAbility) { gBattlerAbility = battlerAbility - 1; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_AromaVeilProtectsRet; } else if (!gBattleMons[gEffectBattler].volatiles.healBlock) { gBattleMons[gEffectBattler].volatiles.healBlock = TRUE; - gDisableStructs[gEffectBattler].healBlockTimer = gBattleTurnCounter + 2; - BattleScriptPush(gBattlescriptCurrInstr + 1); + gDisableStructs[gEffectBattler].healBlockTimer = 2; + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectPsychicNoise; } break; @@ -3557,13 +3545,13 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai && GetBattlerTeraType(gEffectBattler) == TYPE_STELLAR && !NoAliveMonsForEitherParty()) { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_LowerAtkSpAtk; } break; case MOVE_EFFECT_ORDER_UP: { - u32 stat = 0; + enum Stat stat = 0; bool32 commanderAffected = TRUE; switch (gBattleStruct->battlerState[gEffectBattler].commanderSpecies) { @@ -3590,13 +3578,13 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai 0, 0) == STAT_CHANGE_DIDNT_WORK) { - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } else { - gBattleScripting.animArg1 = gBattleScripting.moveEffect; + gBattleScripting.animArg1 = moveEffect; gBattleScripting.animArg2 = 0; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_StatUp; } } @@ -3605,35 +3593,35 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai if (!(gFieldStatuses & STATUS_FIELD_ION_DELUGE)) { gFieldStatuses |= STATUS_FIELD_ION_DELUGE; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectIonDeluge; } break; case MOVE_EFFECT_HAZE: for (i = 0; i < gBattlersCount; i++) TryResetBattlerStatChanges(i); - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectHaze; break; case MOVE_EFFECT_LEECH_SEED: if (!IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_GRASS) && !gBattleMons[gBattlerTarget].volatiles.leechSeed) { gBattleMons[gBattlerTarget].volatiles.leechSeed = LEECHSEEDED_BY(gBattlerAttacker); - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectLeechSeed; } break; case MOVE_EFFECT_REFLECT: if (TrySetReflect(gBattlerAttacker)) { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectReflect; } break; case MOVE_EFFECT_LIGHT_SCREEN: if (TrySetLightScreen(gBattlerAttacker)) { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectLightScreen; } break; @@ -3641,7 +3629,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai if (!gBattleMons[gBattlerTarget].volatiles.saltCure) { gBattleMons[gBattlerTarget].volatiles.saltCure = TRUE; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectSaltCure; } break; @@ -3677,7 +3665,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai if (gBattleMons[gBattlerTarget].pp[i] == 0 && gBattleStruct->skyDropTargets[gBattlerTarget] == SKY_DROP_NO_TARGET) CancelMultiTurnMoves(gBattlerTarget, SKY_DROP_IGNORE); - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectEerieSpell; } } @@ -3687,7 +3675,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai { // Max Effects are ordered by stat ID. SET_STATCHANGER(STAT_ATK, 1, FALSE); - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectRaiseStatAllies; } break; @@ -3696,7 +3684,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai { // Max Effects are ordered by stat ID. SET_STATCHANGER(STAT_DEF, 1, FALSE); - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectRaiseStatAllies; } break; @@ -3705,7 +3693,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai { // Max Effects are ordered by stat ID. SET_STATCHANGER(STAT_SPEED, 1, FALSE); - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectRaiseStatAllies; } break; @@ -3714,7 +3702,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai { // Max Effects are ordered by stat ID. SET_STATCHANGER(STAT_SPATK, 1, FALSE); - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectRaiseStatAllies; } break; @@ -3723,7 +3711,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai { // Max Effects are ordered by stat ID. SET_STATCHANGER(STAT_SPDEF, 1, FALSE); - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectRaiseStatAllies; } break; @@ -3736,9 +3724,9 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai case MOVE_EFFECT_LOWER_EVASIVENESS_SIDE: if (!NoAliveMonsForEitherParty()) { - u32 statId = 0; + enum Stat statId = 0; u32 stage = 1; - switch (gBattleScripting.moveEffect) + switch (moveEffect) { case MOVE_EFFECT_LOWER_SPEED_2_SIDE: statId = STAT_SPEED; @@ -3749,11 +3737,11 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai break; default: // Max Effects are ordered by stat ID. - statId = gBattleScripting.moveEffect - MOVE_EFFECT_LOWER_ATTACK_SIDE + 1; + statId = moveEffect - MOVE_EFFECT_LOWER_ATTACK_SIDE + 1; break; } SET_STATCHANGER(statId, stage, TRUE); - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectLowerStatFoes; } break; @@ -3763,7 +3751,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai case MOVE_EFFECT_HAIL: { u8 weather = 0, msg = 0; - switch (gBattleScripting.moveEffect) + switch (moveEffect) { case MOVE_EFFECT_SUN: weather = BATTLE_WEATHER_SUN; @@ -3789,11 +3777,13 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai msg = B_MSG_STARTED_HAIL; } break; + default: + break; } - if (TryChangeBattleWeather(gBattlerAttacker, weather, FALSE)) + if (TryChangeBattleWeather(gBattlerAttacker, weather, ABILITY_NONE)) { gBattleCommunication[MULTISTRING_CHOOSER] = msg; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectSetWeather; } break; @@ -3804,7 +3794,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai case MOVE_EFFECT_PSYCHIC_TERRAIN: { u32 statusFlag = 0; - switch (gBattleScripting.moveEffect) + switch (moveEffect) { case MOVE_EFFECT_MISTY_TERRAIN: statusFlag = STATUS_FIELD_MISTY_TERRAIN; @@ -3822,16 +3812,18 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai statusFlag = STATUS_FIELD_PSYCHIC_TERRAIN; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_PSYCHIC; break; + default: + break; } if (!(gFieldStatuses & statusFlag) && statusFlag != 0) { gFieldStatuses &= ~STATUS_FIELD_TERRAIN_ANY; gFieldStatuses |= statusFlag; if (GetBattlerHoldEffect(gBattlerAttacker) == HOLD_EFFECT_TERRAIN_EXTENDER) - gFieldTimers.terrainTimer = gBattleTurnCounter + 8; + gFieldTimers.terrainTimer = 8; else - gFieldTimers.terrainTimer = gBattleTurnCounter + 5; - BattleScriptPush(gBattlescriptCurrInstr + 1); + gFieldTimers.terrainTimer = 5; + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectSetTerrain; } break; @@ -3846,9 +3838,9 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai { u32 moveType = GetMoveType(gCurrentMove); gSideStatuses[side] |= SIDE_STATUS_DAMAGE_NON_TYPES; - gSideTimers[side].damageNonTypesTimer = gBattleTurnCounter + 5; // damage is dealt for 4 turns, ends on 5th + gSideTimers[side].damageNonTypesTimer = 5; gSideTimers[side].damageNonTypesType = moveType; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); ChooseDamageNonTypesString(moveType); gBattlescriptCurrInstr = BattleScript_DamageNonTypesStarts; } @@ -3858,7 +3850,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai if (!IsHazardOnSide(GetBattlerSide(gBattlerTarget), HAZARDS_STEELSURGE)) { gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SHARPSTEELFLOATS; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectSteelsurge; } break; @@ -3868,7 +3860,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai || AreAnyHazardsOnSide(GetBattlerSide(gBattlerAttacker)) || gFieldStatuses & STATUS_FIELD_TERRAIN_ANY) { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectDefog; } break; @@ -3877,11 +3869,11 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai { gSideStatuses[GetBattlerSide(gBattlerAttacker)] |= SIDE_STATUS_AURORA_VEIL; if (GetBattlerHoldEffect(gBattlerAttacker) == HOLD_EFFECT_LIGHT_CLAY) - gSideTimers[GetBattlerSide(gBattlerAttacker)].auroraVeilTimer = gBattleTurnCounter + 8; + gSideTimers[GetBattlerSide(gBattlerAttacker)].auroraVeilTimer = 8; else - gSideTimers[GetBattlerSide(gBattlerAttacker)].auroraVeilTimer = gBattleTurnCounter + 5; + gSideTimers[GetBattlerSide(gBattlerAttacker)].auroraVeilTimer = 5; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_SAFEGUARD; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectAuroraVeil; } break; @@ -3889,8 +3881,8 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai if (!(gFieldStatuses & STATUS_FIELD_GRAVITY)) { gFieldStatuses |= STATUS_FIELD_GRAVITY; - gFieldTimers.gravityTimer = gBattleTurnCounter + 5; - BattleScriptPush(gBattlescriptCurrInstr + 1); + gFieldTimers.gravityTimer = 5; + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectGravitySuccess; } break; @@ -3911,11 +3903,11 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai else gDisableStructs[battler].wrapTurns = (Random() % 2) + 4; // The Wrap effect does not expire when the user switches, so here's some cheese. - gBattleStruct->wrappedBy[battler] = gBattlerTarget; - if (gBattleScripting.moveEffect == MOVE_EFFECT_SANDBLAST_SIDE) - gBattleStruct->wrappedMove[battler] = MOVE_SAND_TOMB; + gBattleMons[battler].volatiles.wrappedBy = gBattlerTarget; + if (moveEffect == MOVE_EFFECT_SANDBLAST_SIDE) + gBattleMons[battler].volatiles.wrappedMove = MOVE_SAND_TOMB; else - gBattleStruct->wrappedMove[battler] = MOVE_FIRE_SPIN; + gBattleMons[battler].volatiles.wrappedMove = MOVE_FIRE_SPIN; } } break; @@ -3927,7 +3919,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai && RandomPercentage(RNG_G_MAX_SNOOZE, 50)) { gBattleMons[gBattlerTarget].volatiles.yawn = 2; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectYawnSide; } break; @@ -3936,24 +3928,24 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai if (gLastMoves[gBattlerTarget] != MOVE_NONE && gLastMoves[gBattlerTarget] != MOVE_UNAVAILABLE) { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectTryReducePP; } break; case MOVE_EFFECT_PARALYZE_SIDE: - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectParalyzeSide; break; case MOVE_EFFECT_POISON_SIDE: - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectPoisonSide; break; case MOVE_EFFECT_POISON_PARALYZE_SIDE: - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectPoisonParalyzeSide; break; case MOVE_EFFECT_EFFECT_SPORE_SIDE: - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectEffectSporeSide; break; case MOVE_EFFECT_CONFUSE_PAY_DAY_SIDE: @@ -3967,39 +3959,39 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai } // fall through case MOVE_EFFECT_CONFUSE_SIDE: - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectConfuseSide; break; case MOVE_EFFECT_INFATUATE_SIDE: - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectInfatuateSide; break; case MOVE_EFFECT_TORMENT_SIDE: - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectTormentSide; break; case MOVE_EFFECT_PREVENT_ESCAPE_SIDE: - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectMeanLookSide; break; case MOVE_EFFECT_CRIT_PLUS_SIDE: gBattleStruct->bonusCritStages[gBattlerAttacker]++; gBattleStruct->bonusCritStages[BATTLE_PARTNER(gBattlerAttacker)]++; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectRaiseCritAlliesAnim; break; case MOVE_EFFECT_HEAL_TEAM: - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectHealOneSixthAllies; break; case MOVE_EFFECT_AROMATHERAPY: - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectAromatherapy; break; case MOVE_EFFECT_RECYCLE_BERRIES: if (RandomPercentage(RNG_G_MAX_REPLENISH, 50)) { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectRecycleBerriesAllies; } break; @@ -4012,7 +4004,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai gBattleMons[gEffectBattler].status1 &= ~(argStatus); BtlController_EmitSetMonData(gEffectBattler, 0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gEffectBattler].status1); MarkBattlerForControllerExec(gEffectBattler); - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); switch (argStatus) { @@ -4041,9 +4033,11 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai } break; } + default: + break; } - gBattleScripting.moveEffect = 0; + gBattleScripting.moveEffect = MOVE_EFFECT_NONE; } static bool32 CanApplyAdditionalEffect(const struct AdditionalEffect *additionalEffect) @@ -4104,14 +4098,18 @@ static void Cmd_setadditionaleffects(void) // Activate effect if it's primary (chance == 0) or if RNGesus says so if ((percentChance == 0) || RandomPercentage(RNG_SECONDARY_EFFECT + gBattleStruct->additionalEffectsCounter, percentChance)) { - gBattleScripting.moveEffect = additionalEffect->moveEffect; gBattleCommunication[MULTISTRING_CHOOSER] = *((u8 *) &additionalEffect->multistring); + enum SetMoveEffectFlags flags = NO_FLAGS; + if (percentChance == 0) flags |= EFFECT_PRIMARY; + if (percentChance >= 100) flags |= EFFECT_CERTAIN; + SetMoveEffect( gBattlerAttacker, additionalEffect->self ? gBattlerAttacker : gBattlerTarget, - percentChance == 0, // a primary effect - percentChance >= 100 // certain to happen + additionalEffect->moveEffect, + cmd->nextInstr, + flags ); } } @@ -4146,8 +4144,7 @@ static void Cmd_seteffectprimary(void) u32 battler = GetBattlerForBattleScript(cmd->battler); u32 effectBattler = GetBattlerForBattleScript(cmd->effectBattler); - gBattlescriptCurrInstr = cmd->nextInstr - 1; - SetMoveEffect(battler, effectBattler, TRUE, FALSE); + SetMoveEffect(battler, effectBattler, gBattleScripting.moveEffect, cmd->nextInstr, EFFECT_PRIMARY); } static void Cmd_seteffectsecondary(void) @@ -4156,8 +4153,7 @@ static void Cmd_seteffectsecondary(void) u32 battler = GetBattlerForBattleScript(cmd->battler); u32 effectBattler = GetBattlerForBattleScript(cmd->effectBattler); - gBattlescriptCurrInstr = cmd->nextInstr - 1; - SetMoveEffect(battler, effectBattler, FALSE, FALSE); + SetMoveEffect(battler, effectBattler, gBattleScripting.moveEffect, cmd->nextInstr, EFFECT_PRIMARY); } static void Cmd_clearvolatile(void) @@ -4176,7 +4172,7 @@ static void Cmd_clearvolatile(void) static void Cmd_tryfaintmon(void) { CMD_ARGS(u8 battler, bool8 isSpikes, const u8 *instr); - u32 battler, destinyBondBattler; + u32 battler; const u8 *faintScript; battler = GetBattlerForBattleScript(cmd->battler); @@ -4203,16 +4199,12 @@ static void Cmd_tryfaintmon(void) gBattlescriptCurrInstr = BattleScript_NeutralizingGasExits; return; } + if (cmd->battler == BS_ATTACKER) - { - destinyBondBattler = gBattlerTarget; - faintScript = BattleScript_FaintAttacker; - } - else - { - destinyBondBattler = gBattlerAttacker; - faintScript = BattleScript_FaintTarget; - } + TryUpdateEvolutionTracker(IF_DEFEAT_X_WITH_ITEMS, 1, MOVE_NONE); + + gBattlerFainted = battler; + faintScript = BattleScript_FaintBattler; if (!(gAbsentBattlerFlags & (1u << battler)) && !IsBattlerAlive(battler)) { @@ -4234,30 +4226,11 @@ static void Cmd_tryfaintmon(void) gBattleResults.lastOpponentSpecies = GetMonData(GetBattlerMon(battler), MON_DATA_SPECIES, NULL); gSideTimers[B_SIDE_OPPONENT].retaliateTimer = 2; } - if ((gHitMarker & HITMARKER_DESTINYBOND) && IsBattlerAlive(gBattlerAttacker) - && !(GetActiveGimmick(gBattlerAttacker) == GIMMICK_DYNAMAX)) - { - gHitMarker &= ~HITMARKER_DESTINYBOND; - BattleScriptPush(gBattlescriptCurrInstr); - gBattleStruct->moveDamage[destinyBondBattler] = gBattleMons[destinyBondBattler].hp; - gBattlescriptCurrInstr = BattleScript_DestinyBondTakesLife; - } - if (gBattleMons[gBattlerTarget].volatiles.grudge - && !(gHitMarker & HITMARKER_GRUDGE) - && !IsBattlerAlly(gBattlerAttacker, gBattlerTarget) - && IsBattlerAlive(gBattlerAttacker) - && gCurrentMove != MOVE_STRUGGLE) - { - u8 moveIndex = gBattleStruct->chosenMovePositions[gBattlerAttacker]; - gBattleMons[gBattlerAttacker].pp[moveIndex] = 0; - BattleScriptPush(gBattlescriptCurrInstr); - gBattlescriptCurrInstr = BattleScript_GrudgeTakesPp; - BtlController_EmitSetMonData(gBattlerAttacker, B_COMM_TO_CONTROLLER, moveIndex + REQUEST_PPMOVE1_BATTLE, 0, sizeof(gBattleMons[gBattlerAttacker].pp[moveIndex]), &gBattleMons[gBattlerAttacker].pp[moveIndex]); - MarkBattlerForControllerExec(gBattlerAttacker); - - PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleMons[gBattlerAttacker].moves[moveIndex]) - } + if (gBattleMons[gBattlerTarget].volatiles.destinyBond) + gBattleStruct->tryDestinyBond = TRUE; + if (gBattleMons[gBattlerTarget].volatiles.grudge) + gBattleStruct->tryGrudge = TRUE; TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]); } @@ -4408,7 +4381,7 @@ static void Cmd_jumpifstat(void) u8 value = cmd->value; u8 comparison = cmd->comparison; - ret = CompareStat(battler, stat, value, comparison); + ret = CompareStat(battler, stat, value, comparison, GetBattlerAbility(battler)); if (ret) gBattlescriptCurrInstr = cmd->jumpInstr; @@ -4416,8 +4389,22 @@ static void Cmd_jumpifstat(void) gBattlescriptCurrInstr = cmd->nextInstr; } -static void Cmd_unused_0x21(void) +static void Cmd_jumpifstatignorecontrary(void) { + CMD_ARGS(u8 battler, u8 comparison, u8 stat, u8 value, const u8 *jumpInstr); + + bool32 ret = 0; + u8 battler = GetBattlerForBattleScript(cmd->battler); + u8 stat = cmd->stat; + u8 value = cmd->value; + u8 comparison = cmd->comparison; + + ret = CompareStat(battler, stat, value, comparison, ABILITY_NONE); + + if (ret) + gBattlescriptCurrInstr = cmd->jumpInstr; + else + gBattlescriptCurrInstr = cmd->nextInstr; } static void Cmd_jumpbasedontype(void) @@ -4467,7 +4454,7 @@ static bool32 BattleTypeAllowsExp(void) static u32 GetMonHoldEffect(struct Pokemon *mon) { - enum ItemHoldEffect holdEffect; + enum HoldEffect holdEffect; u32 item = GetMonData(mon, MON_DATA_HELD_ITEM); if (item == ITEM_ENIGMA_BERRY_E_READER) @@ -4486,7 +4473,7 @@ static void Cmd_getexp(void) { CMD_ARGS(u8 battler); - enum ItemHoldEffect holdEffect; + enum HoldEffect holdEffect; s32 i; // also used as stringId u8 *expMonId = &gBattleStruct->expGetterMonId; u32 currLvl; @@ -4615,7 +4602,7 @@ static void Cmd_getexp(void) if (!(gBattleTypeFlags & BATTLE_TYPE_TRAINER) && (gBattleMons[0].hp || (IsDoubleBattle() && gBattleMons[2].hp)) && !IsBattlerAlive(GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT)) - && !IsBattlerAlive(GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT)) + && (!IsDoubleBattle() || !IsBattlerAlive(GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT))) && !gBattleStruct->wildVictorySong) { BattleStopLowHpSound(); @@ -4748,7 +4735,15 @@ static void Cmd_getexp(void) if (battler != 0xFF) { - CopyMonLevelAndBaseStatsToBattleMon(battler, &gPlayerParty[*expMonId]); + if (gBattleMons[battler].volatiles.transformed) + { + gBattleMons[battler].level = GetMonData(&gPlayerParty[*expMonId], MON_DATA_LEVEL); + gBattleMons[battler].hp = GetMonData(&gPlayerParty[*expMonId], MON_DATA_HP); + } + else + { + CopyMonLevelAndBaseStatsToBattleMon(battler, &gPlayerParty[*expMonId]); + } if (gBattleMons[battler].volatiles.powerTrick) SWAP(gBattleMons[battler].attack, gBattleMons[battler].defense, temp); } @@ -4834,16 +4829,14 @@ bool32 NoAliveMonsForPlayer(void) { HP_count += GetMonData(&gPlayerParty[i], MON_DATA_HP); } - // Get the number of fainted mons or eggs (not empty slots) in the first three party slots. if (i < 3 && ((GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) && !GetMonData(&gPlayerParty[i], MON_DATA_HP)) || GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG))) ineligibleMonsCount++; } - // Get the number of inelligible slots in the saved player party. if (B_MULTI_BATTLE_WHITEOUT > GEN_3 && gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_INGAME_PARTNER) - && !(gBattleTypeFlags & BATTLE_TYPE_ARENA)) + && !(gBattleTypeFlags & BATTLE_TYPE_ARENA) && !(IsMultibattleTest())) // Multibattle tests appear to not save the player party data for the check below. { for (i = 0; i < PARTY_SIZE; i++) { @@ -4896,7 +4889,6 @@ static void Cmd_checkteamslost(void) if (NoAliveMonsForPlayer()) gBattleOutcome |= B_OUTCOME_LOST; - if (NoAliveMonsForOpponent()) gBattleOutcome |= B_OUTCOME_WON; @@ -4911,14 +4903,14 @@ static void Cmd_checkteamslost(void) for (emptyPlayerSpots = 0, i = 0; i < gBattlersCount; i += 2) { - if ((gHitMarker & HITMARKER_FAINTED2(i)) && (!gSpecialStatuses[i].faintedHasReplacement)) + if ((gHitMarker & HITMARKER_FAINTED(i)) && (!gSpecialStatuses[i].faintedHasReplacement)) emptyPlayerSpots++; } emptyOpponentSpots = 0; for (i = 1; i < gBattlersCount; i += 2) { - if ((gHitMarker & HITMARKER_FAINTED2(i)) && (!gSpecialStatuses[i].faintedHasReplacement)) + if ((gHitMarker & HITMARKER_FAINTED(i)) && (!gSpecialStatuses[i].faintedHasReplacement)) emptyOpponentSpots++; } @@ -4953,8 +4945,6 @@ static void MoveValuesCleanUp(void) gBattleScripting.moveEffect = MOVE_EFFECT_NONE; gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_NONE; gBattleCommunication[MISS_TYPE] = 0; - if (!gMultiHitCounter) - gHitMarker &= ~HITMARKER_DESTINYBOND; } static void Cmd_movevaluescleanup(void) @@ -5304,21 +5294,29 @@ static void Cmd_waitstate(void) gBattlescriptCurrInstr = cmd->nextInstr; } -static void Cmd_absorb(void) +static void Cmd_isdmgblockedbydisguise(void) { - CMD_ARGS(u8 battler); + CMD_ARGS(); - if (gBattleControllerExecFlags) + if (!IsMimikyuDisguised(gBattlerAttacker) + || gBattleMons[gBattlerAttacker].volatiles.transformed + || !IsAbilityAndRecord(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), ABILITY_DISGUISE)) + { + gBattlescriptCurrInstr = cmd->nextInstr; return; + } - u32 battler = GetBattlerForBattleScript(cmd->battler); - BtlController_EmitHealthBarUpdate(battler, B_COMM_TO_CONTROLLER, gBattleStruct->moveDamage[battler]); - MarkBattlerForControllerExec(battler); - - if (IsOnPlayerSide(battler) && gBattleStruct->moveDamage[battler] > 0) - gBattleResults.playerMonWasDamaged = TRUE; - - gBattlescriptCurrInstr = cmd->nextInstr; + gBattleScripting.battler = gBattlerAttacker; + if (GetBattlerPartyState(gBattlerAttacker)->changedSpecies == SPECIES_NONE) + GetBattlerPartyState(gBattlerAttacker)->changedSpecies = gBattleMons[gBattlerAttacker].species; + if (gBattleMons[gBattlerAttacker].species == SPECIES_MIMIKYU_TOTEM_DISGUISED) + gBattleMons[gBattlerAttacker].species = SPECIES_MIMIKYU_BUSTED_TOTEM; + else + gBattleMons[gBattlerAttacker].species = SPECIES_MIMIKYU_BUSTED; + if (GetGenConfig(GEN_CONFIG_DISGUISE_HP_LOSS) >= GEN_8) + SetPassiveDamageAmount(gBattlerAttacker, GetNonDynamaxMaxHP(gBattlerAttacker) / 8); + BattleScriptPush(BattleScript_MoveEnd); + gBattlescriptCurrInstr = BattleScript_TargetFormChange; } static void Cmd_return(void) @@ -5390,8 +5388,7 @@ static void Cmd_jumpifabilitypresent(void) static void Cmd_endselectionscript(void) { CMD_ARGS(); - - *(gBattlerAttacker + gBattleStruct->selectionScriptFinished) = TRUE; + gBattleStruct->battlerState[gBattlerAttacker].selectionScriptFinished = TRUE; } static void PlayAnimation(u32 battler, u8 animId, const u16 *argPtr, const u8 *nextInstr) @@ -5505,7 +5502,7 @@ static u32 GetNextTarget(u32 moveTarget, bool32 excludeCurrent) return battler; } -static inline bool32 IsProtectivePadsProtected(u32 battler, enum ItemHoldEffect holdEffect) +static inline bool32 IsProtectivePadsProtected(u32 battler, enum HoldEffect holdEffect) { if (holdEffect != HOLD_EFFECT_PROTECTIVE_PADS) return FALSE; @@ -5549,22 +5546,54 @@ static bool32 HandleMoveEndAbilityBlock(u32 battlerAtk, u32 battlerDef, u32 move switch (abilityAtk) { case ABILITY_MAGICIAN: - if (move != MOVE_FLING && move != MOVE_NATURAL_GIFT + if (GetMoveEffect(move) != EFFECT_FLING + && GetMoveEffect(move) != EFFECT_NATURAL_GIFT && gBattleMons[battlerAtk].item == ITEM_NONE - && gBattleMons[battlerDef].item != ITEM_NONE && IsBattlerAlive(battlerAtk) - && IsBattlerTurnDamaged(battlerDef) - && CanStealItem(battlerAtk, battlerDef, gBattleMons[battlerDef].item) - && !gSpecialStatuses[battlerAtk].gemBoost // In base game, gems are consumed after magician would activate. - && !(gWishFutureKnock.knockedOffMons[GetBattlerSide(battlerDef)] & (1u << gBattlerPartyIndexes[battlerDef])) - && !DoesSubstituteBlockMove(battlerAtk, battlerDef, move) - && (GetBattlerAbility(battlerDef) != ABILITY_STICKY_HOLD || !IsBattlerAlive(battlerDef))) + && !gSpecialStatuses[battlerAtk].gemBoost) // In base game, gems are consumed after magician would activate. { - StealTargetItem(battlerAtk, battlerDef); - gBattleScripting.battler = gBattlerAbility = battlerAtk; - gEffectBattler = battlerDef; - BattleScriptCall(BattleScript_MagicianActivates); - effect = TRUE; + u32 numMagicianTargets = 0; + u32 magicianTargets = 0; + + for (u32 i = 0; i < gBattlersCount; i++) + { + if (gBattleMons[i].item != ITEM_NONE + && i != battlerAtk + && IsBattlerTurnDamaged(i) + && CanStealItem(battlerAtk, i, gBattleMons[i].item) + && !(gWishFutureKnock.knockedOffMons[GetBattlerSide(i)] & (1u << gBattlerPartyIndexes[i])) + && !DoesSubstituteBlockMove(battlerAtk, i, move) + && (GetBattlerAbility(i) != ABILITY_STICKY_HOLD || !IsBattlerAlive(i))) + { + magicianTargets |= 1u << i; + numMagicianTargets++; + } + } + + if (numMagicianTargets == 0) + { + effect = FALSE; + break; + } + + u8 battlers[4] = {0, 1, 2, 3}; + if (numMagicianTargets > 1) + SortBattlersBySpeed(battlers, FALSE); + + for (u32 i = 0; i < gBattlersCount; i++) + { + u32 battler = battlers[i]; + + if (!(magicianTargets & 1u << battler)) + continue; + + StealTargetItem(battlerAtk, battler); + gBattlerAbility = battlerAtk; + gEffectBattler = battler; + BattleScriptCall(BattleScript_MagicianActivates); + effect = TRUE; + break; // found target to steal from + } } break; case ABILITY_MOXIE: @@ -5577,7 +5606,7 @@ static bool32 HandleMoveEndAbilityBlock(u32 battlerAtk, u32 battlerDef, u32 move if (!IsBattlerAlive(battlerAtk) || NoAliveMonsForEitherParty()) break; - u32 stat = STAT_ATK; + enum Stat stat = STAT_ATK; u32 numMonsFainted = NumFaintedBattlersByAttacker(battlerAtk); if (abilityAtk == ABILITY_BEAST_BOOST) @@ -5585,7 +5614,7 @@ static bool32 HandleMoveEndAbilityBlock(u32 battlerAtk, u32 battlerDef, u32 move else if (abilityAtk == ABILITY_GRIM_NEIGH || abilityAtk == ABILITY_AS_ONE_SHADOW_RIDER) stat = STAT_SPATK; - if (numMonsFainted && CompareStat(battlerAtk, stat, MAX_STAT_STAGE, CMP_LESS_THAN)) + if (numMonsFainted && CompareStat(battlerAtk, stat, MAX_STAT_STAGE, CMP_LESS_THAN, abilityAtk)) { gLastUsedAbility = abilityAtk; if (abilityAtk == ABILITY_AS_ONE_ICE_RIDER) @@ -5625,17 +5654,17 @@ static bool32 HandleMoveEndAbilityBlock(u32 battlerAtk, u32 battlerDef, u32 move else { u32 numStatBuffs = 0; - if (CompareStat(battlerAtk, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN)) + if (CompareStat(battlerAtk, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN, abilityAtk)) { gBattleScripting.animArg1 = GET_STAT_BUFF_ID(STAT_ATK) + STAT_ANIM_PLUS1; numStatBuffs++; } - if (CompareStat(battlerAtk, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN)) + if (CompareStat(battlerAtk, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN, abilityAtk)) { gBattleScripting.animArg1 = GET_STAT_BUFF_ID(STAT_SPATK) + STAT_ANIM_PLUS1; numStatBuffs++; } - if (CompareStat(battlerAtk, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN)) + if (CompareStat(battlerAtk, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN, abilityAtk)) { gBattleScripting.animArg1 = GET_STAT_BUFF_ID(STAT_SPEED) + STAT_ANIM_PLUS1; numStatBuffs++; @@ -5667,38 +5696,51 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect) if (gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) return FALSE; - u32 effect = FALSE; + bool32 effect = FALSE; + enum BattleSide side = GetBattlerSide(gBattlerTarget); switch (moveEffect) { case EFFECT_KNOCK_OFF: - if (gBattleStruct->battlerState[gBattlerTarget].itemCanBeKnockedOff - && gBattleMons[gBattlerTarget].item != ITEM_NONE + if (gBattleMons[gBattlerTarget].item != ITEM_NONE + && IsBattlerAlive(gBattlerAttacker) + && !(B_KNOCK_OFF_REMOVAL >= GEN_5 && side == B_SIDE_PLAYER && !(gBattleTypeFlags & BATTLE_TYPE_TRAINER)) && IsBattlerTurnDamaged(gBattlerTarget) - && IsBattlerAlive(gBattlerAttacker)) + && !DoesSubstituteBlockMove(gBattlerAttacker, gBattlerTarget, gCurrentMove) + && CanBattlerGetOrLoseItem(gBattlerTarget, gBattleMons[gBattlerTarget].item) + && !NoAliveMonsForEitherParty()) { u32 side = GetBattlerSide(gBattlerTarget); + + if (GetBattlerAbility(gBattlerTarget) == ABILITY_STICKY_HOLD) + { + gBattlerAbility = gBattlerTarget; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_StickyHoldActivatesRet; + effect = TRUE; + break; + } gLastUsedItem = gBattleMons[gBattlerTarget].item; gBattleMons[gBattlerTarget].item = 0; if (gBattleMons[gBattlerTarget].ability != ABILITY_GORILLA_TACTICS) - gBattleStruct->choicedMove[gBattlerTarget] = 0; + gBattleStruct->choicedMove[gBattlerTarget] = MOVE_NONE; CheckSetUnburden(gBattlerTarget); - // In Gen 5+, Knock Off removes the target's item rather than rendering it unusable. + // In Gen 5+, Knock Off removes the target's item rather than rendering it unusable if (B_KNOCK_OFF_REMOVAL >= GEN_5) { BtlController_EmitSetMonData(gBattlerTarget, B_COMM_TO_CONTROLLER, REQUEST_HELDITEM_BATTLE, 0, sizeof(gBattleMons[gBattlerTarget].item), &gBattleMons[gBattlerTarget].item); MarkBattlerForControllerExec(gBattlerTarget); + // Mark item as stolen so it will be restored after battle + gBattleStruct->itemLost[side][gBattlerPartyIndexes[gBattlerTarget]].stolen = TRUE; } else { gWishFutureKnock.knockedOffMons[side] |= 1u << gBattlerPartyIndexes[gBattlerTarget]; } - gBattleStruct->battlerState[gBattlerTarget].itemCanBeKnockedOff = FALSE; BattleScriptCall(BattleScript_KnockedOff); effect = TRUE; } - gBattleStruct->battlerState[gBattlerTarget].itemCanBeKnockedOff = FALSE; break; case EFFECT_STEAL_ITEM: if (!CanStealItem(gBattlerAttacker, gBattlerTarget, gBattleMons[gBattlerTarget].item) @@ -5726,6 +5768,7 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect) gBattleMons[gBattlerAttacker].item = ITEM_NONE; // Item assigned later on with thief (see MOVEEND_CHANGED_ITEMS) gBattleStruct->changedItems[gBattlerAttacker] = gLastUsedItem; // Stolen item to be assigned later } + gEffectBattler = gBattlerTarget; BattleScriptCall(BattleScript_ItemSteal); effect = TRUE; } @@ -5779,16 +5822,14 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect) && (!IsBattlerTurnDamaged(gBattlerTarget) || gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT) && !gBattleStruct->noTargetPresent) { + s32 recoil = 0; if (B_RECOIL_IF_MISS_DMG >= GEN_5 || (B_CRASH_IF_TARGET_IMMUNE == GEN_4 && gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_DOESNT_AFFECT_FOE)) - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 2; + recoil = GetNonDynamaxMaxHP(gBattlerAttacker) / 2; else if (B_RECOIL_IF_MISS_DMG == GEN_4 && (GetNonDynamaxMaxHP(gBattlerTarget) / 2) < gBattleStruct->moveDamage[gBattlerTarget]) - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerTarget) / 2; + recoil = GetNonDynamaxMaxHP(gBattlerTarget) / 2; else // Fallback if B_RECOIL_IF_MISS_DMG is set to gen3 or lower. - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerTarget) / 2; - - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; - + recoil = GetNonDynamaxMaxHP(gBattlerTarget) / 2; + SetPassiveDamageAmount(gBattlerAttacker, recoil); BattleScriptCall(BattleScript_RecoilIfMiss); effect = TRUE; } @@ -5796,15 +5837,22 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect) case EFFECT_RECOIL: if (IsBattlerTurnDamaged(gBattlerTarget) && IsBattlerAlive(gBattlerAttacker)) { - gBattleStruct->moveDamage[gBattlerAttacker] = max(1, gBattleScripting.savedDmg * max(1, GetMoveRecoil(gCurrentMove)) / 100); + enum Ability ability = GetBattlerAbility(gBattlerAttacker); + if (IsAbilityAndRecord(gBattlerAttacker, ability, ABILITY_ROCK_HEAD) + || IsAbilityAndRecord(gBattlerAttacker, ability, ABILITY_MAGIC_GUARD)) + break; + + SetPassiveDamageAmount(gBattlerAttacker, gBattleScripting.savedDmg * max(1, GetMoveRecoil(gCurrentMove)) / 100); + TryUpdateEvolutionTracker(IF_RECOIL_DAMAGE_GE, gBattleStruct->passiveHpUpdate[gBattlerAttacker], MOVE_NONE); BattleScriptCall(BattleScript_MoveEffectRecoil); effect = TRUE; } break; case EFFECT_EXPLOSION: + case EFFECT_MISTY_EXPLOSION: if (!IsAbilityOnField(ABILITY_DAMP)) { - gBattleStruct->moveDamage[gBattlerAttacker] = 0; + gBattleStruct->passiveHpUpdate[gBattlerAttacker] = 0; BattleScriptCall(BattleScript_FaintAttackerForExplosion); effect = TRUE; } @@ -5812,9 +5860,11 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect) case EFFECT_MAX_HP_50_RECOIL: if (IsBattlerAlive(gBattlerAttacker) && !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_FAILED) - && GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD) + && !IsAbilityAndRecord(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), ABILITY_MAGIC_GUARD)) { - gBattleStruct->moveDamage[gBattlerAttacker] = (GetNonDynamaxMaxHP(gBattlerAttacker) + 1) / 2; // Half of Max HP Rounded UP + s32 recoil = (GetNonDynamaxMaxHP(gBattlerAttacker) + 1) / 2; // Half of Max HP Rounded UP + SetPassiveDamageAmount(gBattlerAttacker, recoil); + TryUpdateEvolutionTracker(IF_RECOIL_DAMAGE_GE, gBattleStruct->passiveHpUpdate[gBattlerAttacker], MOVE_NONE); BattleScriptCall(BattleScript_MaxHp50Recoil); effect = TRUE; } @@ -5822,13 +5872,20 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect) case EFFECT_CHLOROBLAST: if (IsBattlerTurnDamaged(gBattlerTarget) && IsBattlerAlive(gBattlerAttacker)) { - gBattleStruct->moveDamage[gBattlerAttacker] = (GetNonDynamaxMaxHP(gBattlerAttacker) + 1) / 2; // Half of Max HP Rounded UP + enum Ability ability = GetBattlerAbility(gBattlerAttacker); + if (IsAbilityAndRecord(gBattlerAttacker, ability, ABILITY_ROCK_HEAD) + || IsAbilityAndRecord(gBattlerAttacker, ability, ABILITY_MAGIC_GUARD)) + break; + + s32 recoil = (GetNonDynamaxMaxHP(gBattlerAttacker) + 1) / 2; // Half of Max HP Rounded UP + SetPassiveDamageAmount(gBattlerAttacker, recoil); + TryUpdateEvolutionTracker(IF_RECOIL_DAMAGE_GE, gBattleStruct->passiveHpUpdate[gBattlerAttacker], MOVE_NONE); BattleScriptCall(BattleScript_MoveEffectRecoil); effect = TRUE; } break; case EFFECT_RAPID_SPIN: - if (IsBattlerTurnDamaged(gBattlerTarget)) + if (IsBattlerTurnDamaged(gBattlerTarget) && IsBattlerAlive(gBattlerAttacker)) { BattleScriptCall(BattleScript_RapidSpinAway); effect = TRUE; @@ -5839,7 +5896,7 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect) && !IsBattlerAlive(gBattlerTarget) && IsBattlerTurnDamaged(gBattlerTarget) && !NoAliveMonsForEitherParty() - && CompareStat(gBattlerAttacker, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN)) + && CompareStat(gBattlerAttacker, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(gBattlerAttacker))) { SET_STATCHANGER(STAT_ATK, GetGenConfig(GEN_CONFIG_FELL_STINGER_STAT_RAISE) >= GEN_7 ? 3 : 2, FALSE); PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_ATK); @@ -5849,7 +5906,7 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect) } break; case EFFECT_STONE_AXE: - if (!IsHazardOnSide(GetBattlerSide(gBattlerTarget), HAZARDS_STEALTH_ROCK) + if (!IsHazardOnSide(side, HAZARDS_STEALTH_ROCK) && IsBattlerTurnDamaged(gBattlerTarget) && IsBattlerAlive(gBattlerAttacker)) { @@ -5860,7 +5917,7 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect) } break; case EFFECT_CEASELESS_EDGE: - if (gSideTimers[GetBattlerSide(gBattlerTarget)].spikesAmount < 3 + if (gSideTimers[side].spikesAmount < 3 && IsBattlerTurnDamaged(gBattlerTarget) && IsBattlerAlive(gBattlerAttacker)) { @@ -5914,7 +5971,7 @@ static void Cmd_moveend(void) { case MOVEEND_SET_VALUES: gBattleScripting.savedDmg += gBattleStruct->moveDamage[gBattlerTarget]; - gBattleStruct->moveEndBattlerId = 0; + gBattleStruct->eventState.moveEndBattler = 0; gBattleScripting.moveendState++; break; case MOVEEND_PROTECT_LIKE_EFFECT: @@ -5929,9 +5986,7 @@ static void Cmd_moveend(void) && !IsAbilityAndRecord(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), ABILITY_MAGIC_GUARD)) { gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE; - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 8; - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; + SetPassiveDamageAmount(gBattlerAttacker, GetNonDynamaxMaxHP(gBattlerAttacker) / 8); PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_SPIKY_SHIELD); BattleScriptCall(BattleScript_SpikyShieldEffect); effect = 1; @@ -6020,6 +6075,43 @@ static void Cmd_moveend(void) } gBattleScripting.moveendState++; break; + + case MOVEEND_GRUDGE: + if (gBattleStruct->tryGrudge + && IsBattlerTurnDamaged(gBattlerTarget) + && !IsBattlerAlive(gBattlerTarget) + && IsBattlerAlive(gBattlerAttacker) + && !IsBattlerAlly(gBattlerAttacker, gBattlerTarget) + && !IsZMove(gCurrentMove) + && gCurrentMove != MOVE_STRUGGLE) + { + u32 moveIndex = gBattleStruct->chosenMovePositions[gBattlerAttacker]; + + gBattleStruct->tryGrudge = FALSE; + gBattleMons[gBattlerAttacker].pp[moveIndex] = 0; + BattleScriptCall(BattleScript_GrudgeTakesPp); + BtlController_EmitSetMonData(gBattlerAttacker, B_COMM_TO_CONTROLLER, moveIndex + REQUEST_PPMOVE1_BATTLE, 0, sizeof(gBattleMons[gBattlerAttacker].pp[moveIndex]), &gBattleMons[gBattlerAttacker].pp[moveIndex]); + MarkBattlerForControllerExec(gBattlerAttacker); + PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleMons[gBattlerAttacker].moves[moveIndex]) + } + gBattleScripting.moveendState++; + break; + + case MOVEEND_DESTINY_BOND: + if (gBattleStruct->tryDestinyBond + && IsBattlerTurnDamaged(gBattlerTarget) + && !IsBattlerAlive(gBattlerTarget) + && IsBattlerAlive(gBattlerAttacker) + && !(GetActiveGimmick(gBattlerAttacker) == GIMMICK_DYNAMAX) + && !IsBattlerAlly(gBattlerAttacker, gBattlerTarget)) + { + gBattleStruct->tryDestinyBond = FALSE; + gBattleStruct->passiveHpUpdate[gBattlerAttacker] = gBattleMons[gBattlerAttacker].hp; + BattleScriptCall(BattleScript_DestinyBondTakesLife); + effect = TRUE; + } + gBattleScripting.moveendState++; + break; case MOVEEND_ABSORB: if (gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE || !IsBattlerTurnDamaged(gBattlerTarget)) @@ -6035,20 +6127,19 @@ static void Cmd_moveend(void) && gBattleStruct->moveDamage[gBattlerTarget] > 0 && IsBattlerAlive(gBattlerAttacker)) { - gBattleStruct->moveDamage[gBattlerAttacker] = max(1, (gBattleStruct->moveDamage[gBattlerTarget] * GetMoveAbsorbPercentage(gCurrentMove) / 100)); - gBattleStruct->moveDamage[gBattlerAttacker] = GetDrainedBigRootHp(gBattlerAttacker, gBattleStruct->moveDamage[gBattlerAttacker]); - - gHitMarker |= HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_IGNORE_DISGUISE | HITMARKER_PASSIVE_HP_UPDATE; + s32 healAmount = (gBattleStruct->moveDamage[gBattlerTarget] * GetMoveAbsorbPercentage(gCurrentMove) / 100); + healAmount = GetDrainedBigRootHp(gBattlerAttacker, healAmount); effect = TRUE; if ((moveEffect == EFFECT_DREAM_EATER && GetGenConfig(GEN_DREAM_EATER_LIQUID_OOZE) < GEN_5) || GetBattlerAbility(gBattlerTarget) != ABILITY_LIQUID_OOZE) { + SetHealAmount(gBattlerAttacker, healAmount); gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_ABSORB; BattleScriptCall(BattleScript_EffectAbsorb); } - else + else // Liquid Ooze damage { - gBattleStruct->moveDamage[gBattlerAttacker] *= -1; + SetPassiveDamageAmount(gBattlerAttacker, healAmount); gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_ABSORB_OOZE; BattleScriptCall(BattleScript_EffectAbsorbLiquidOoze); } @@ -6070,7 +6161,7 @@ static void Cmd_moveend(void) && !IsBattlerAlly(gBattlerAttacker, gBattlerTarget) && IsBattlerTurnDamaged(gBattlerTarget) && !IsBattleMoveStatus(gCurrentMove) - && CompareStat(gBattlerTarget, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN)) + && CompareStat(gBattlerTarget, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(gBattlerTarget))) { SET_STATCHANGER(STAT_ATK, 1, FALSE); BattleScriptCall(BattleScript_RageIsBuilding); @@ -6096,9 +6187,12 @@ static void Cmd_moveend(void) gBattleScripting.moveendState++; break; case MOVEEND_STATUS_IMMUNITY_ABILITIES: // status immunities - if (AbilityBattleEffects(ABILITYEFFECT_IMMUNITY, 0, 0, 0, 0)) - effect = TRUE; // it loops through all battlers, so we increment after its done with all battlers - else + for (u16 battler = 0; battler < gBattlersCount; battler++) + { + if (AbilityBattleEffects(ABILITYEFFECT_IMMUNITY, battler, 0, 0, 0)) + effect = TRUE; + } + if (!effect) gBattleScripting.moveendState++; break; case MOVEEND_SYNCHRONIZE_ATTACKER: // attacker synchronize @@ -6107,10 +6201,24 @@ static void Cmd_moveend(void) gBattleScripting.moveendState++; break; case MOVEEND_ITEM_EFFECTS_TARGET: - if (ItemBattleEffects(ITEMEFFECT_TARGET, gBattlerTarget)) + { + enum HoldEffect holdEffect = GetBattlerHoldEffect(gBattlerTarget); + if (ItemBattleEffects(gBattlerTarget, gBattlerAttacker, holdEffect, IsOnTargetHitActivation) + || ItemBattleEffects(gBattlerTarget, gBattlerAttacker, holdEffect, IsOnStatusChangeActivation)) effect = TRUE; gBattleScripting.moveendState++; break; + } + case MOVEEND_ITEM_EFFECTS_ATTACKER_1: + { + enum HoldEffect holdEffect = GetBattlerHoldEffect(gBattlerAttacker); + if (ItemBattleEffects(gBattlerAttacker, gBattlerTarget, holdEffect, IsOnAttackerAfterHitActivation) + || ItemBattleEffects(gBattlerAttacker, gBattlerTarget, holdEffect, IsOnStatusChangeActivation) + || ItemBattleEffects(gBattlerAttacker, gBattlerTarget, holdEffect, IsOnHpThresholdActivation)) + effect = TRUE; + gBattleScripting.moveendState++; + break; + } case MOVEEND_SYMBIOSIS: for (i = 0; i < gBattlersCount; i++) { @@ -6130,12 +6238,6 @@ static void Cmd_moveend(void) } gBattleScripting.moveendState++; break; - case MOVEEND_ITEM_EFFECTS_ALL: // item effects for all battlers - if (ItemBattleEffects(ITEMEFFECT_MOVE_END, 0)) - effect = TRUE; - else - gBattleScripting.moveendState++; - break; case MOVEEND_ATTACKER_INVISIBLE: // make attacker sprite invisible if (IsSemiInvulnerable(gBattlerAttacker, CHECK_ALL) && gHitMarker & (HITMARKER_NO_ANIMATIONS | HITMARKER_DISABLE_ANIMATION)) @@ -6173,12 +6275,6 @@ static void Cmd_moveend(void) } gBattleScripting.moveendState++; break; - case MOVEEND_KINGSROCK: // King's rock - // These effects will occur at each hit in a multi-strike move - if (ItemBattleEffects(ITEMEFFECT_KINGSROCK, 0)) - effect = TRUE; - gBattleScripting.moveendState++; - break; case MOVEEND_SUBSTITUTE: for (i = 0; i < gBattlersCount; i++) { @@ -6250,13 +6346,6 @@ static void Cmd_moveend(void) { gDisableStructs[gBattlerAttacker].usedMoves |= 1u << gCurrMovePos; gBattleStruct->lastMoveTarget[gBattlerAttacker] = gBattlerTarget; - if (gHitMarker & HITMARKER_ATTACKSTRING_PRINTED) - { - gLastPrintedMoves[gBattlerAttacker] = gChosenMove; - gLastUsedMove = gCurrentMove; - if (IsMaxMove(gCurrentMove)) - gBattleStruct->dynamax.lastUsedBaseMove = gBattleStruct->dynamax.baseMoves[gBattlerAttacker]; - } } enum BattleMoveEffects originalEffect = GetMoveEffect(originallyUsedMove); if (!(gAbsentBattlerFlags & (1u << gBattlerAttacker)) @@ -6292,6 +6381,12 @@ static void Cmd_moveend(void) { gLastLandedMoves[gBattlerTarget] = gCurrentMove; gLastHitByType[gBattlerTarget] = GetBattleMoveType(gCurrentMove); + if (!gSpecialStatuses[gBattlerAttacker].dancerUsedMove) + { + gLastUsedMove = gCurrentMove; + if (IsMaxMove(gCurrentMove)) + gBattleStruct->dynamax.lastUsedBaseMove = gBattleStruct->dynamax.baseMoves[gBattlerAttacker]; + } } } else @@ -6367,7 +6462,8 @@ static void Cmd_moveend(void) if (moveEffect == EFFECT_EXPLOSION || moveEffect == EFFECT_MISTY_EXPLOSION || moveEffect == EFFECT_MAGNITUDE - || moveEffect == EFFECT_SYNCHRONOISE) + || moveEffect == EFFECT_SYNCHRONOISE + || gBattleMoveEffects[moveEffect].battleScript == BattleScript_EffectTwoTurnsAttack) BattleScriptPush(gBattleMoveEffects[EFFECT_HIT].battleScript); else BattleScriptPush(GetMoveBattleScript(gCurrentMove)); @@ -6402,6 +6498,12 @@ static void Cmd_moveend(void) gBattleScripting.moveendState++; break; } + case MOVEEND_HP_THRESHHOLD_ITEMS_TARGET: + if (gMultiHitCounter + && ItemBattleEffects(gBattlerTarget, gBattlerAttacker, GetBattlerHoldEffect(gBattlerTarget), IsOnHpThresholdActivation)) + effect = TRUE; + gBattleScripting.moveendState++; + break; case MOVEEND_MULTIHIT_MOVE: { if (!(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT) @@ -6466,11 +6568,15 @@ static void Cmd_moveend(void) effect = HandleMoveEndMoveBlock(moveEffect); gBattleScripting.moveendState++; break; - case MOVEEND_ITEM_EFFECTS_ATTACKER: - if (ItemBattleEffects(ITEMEFFECT_MOVE_END, gBattlerAttacker)) + case MOVEEND_ITEM_EFFECTS_ATTACKER_2: + { + enum HoldEffect holdEffect = GetBattlerHoldEffect(gBattlerAttacker); + if (ItemBattleEffects(gBattlerAttacker, gBattlerTarget, holdEffect, IsOnStatusChangeActivation) + || ItemBattleEffects(gBattlerAttacker, gBattlerTarget, holdEffect, IsOnHpThresholdActivation)) effect = TRUE; gBattleScripting.moveendState++; break; + } case MOVEEND_ABILITY_BLOCK: effect = HandleMoveEndAbilityBlock(gBattlerAttacker, gBattlerTarget, gCurrentMove); gBattleScripting.moveendState++; @@ -6482,15 +6588,28 @@ static void Cmd_moveend(void) gBattleScripting.moveendState++; break; case MOVEEND_COLOR_CHANGE: - while (gBattleStruct->moveEndBattlerId < gBattlersCount) + while (gBattleStruct->eventState.moveEndBattler < gBattlersCount) { - u32 battler = gBattleStruct->moveEndBattlerId++; + u32 battler = gBattleStruct->eventState.moveEndBattler++; if (battler == gBattlerAttacker) continue; if (AbilityBattleEffects(ABILITYEFFECT_COLOR_CHANGE, battler, GetBattlerAbility(battler), 0, 0)) return; } - gBattleStruct->moveEndBattlerId = 0; + gBattleStruct->eventState.moveEndBattler = 0; + gBattleScripting.moveendState++; + break; + case MOVEEND_KEE_MARANGA_HP_THRESHOLD_ITEM_TARGET: + while (gBattleStruct->eventState.moveEndBattler < gBattlersCount) + { + u32 battlerDef = gBattleStruct->eventState.moveEndBattler++; + if (battlerDef == gBattlerAttacker) + continue; + enum HoldEffect holdEffect = GetBattlerHoldEffect(battlerDef); + if (ItemBattleEffects(battlerDef, gBattlerAttacker, holdEffect, IsKeeMarangaBerryActivation) + || ItemBattleEffects(battlerDef, gBattlerAttacker, holdEffect, IsOnHpThresholdActivation)) + return; + } gBattleScripting.moveendState++; break; case MOVEEND_RED_CARD: @@ -6540,7 +6659,7 @@ static void Cmd_moveend(void) } } if (effect) - gBattleScripting.moveendState = MOVEEND_OPPORTUNIST; + gBattleScripting.moveendState = MOVEEND_JUMP_TO_HIT_ESCAPE_PLUS_ONE; else gBattleScripting.moveendState++; break; @@ -6589,12 +6708,12 @@ static void Cmd_moveend(void) } } if (effect) - gBattleScripting.moveendState = MOVEEND_OPPORTUNIST; + gBattleScripting.moveendState = MOVEEND_JUMP_TO_HIT_ESCAPE_PLUS_ONE; else gBattleScripting.moveendState++; break; - case MOVEEND_LIFEORB_SHELLBELL: - if (ItemBattleEffects(ITEMEFFECT_LIFEORB_SHELLBELL, 0)) + case MOVEEND_LIFE_ORB_SHELL_BELL: + if (ItemBattleEffects(gBattlerAttacker, 0, GetBattlerHoldEffect(gBattlerAttacker), IsLifeOrbShellBellActivation)) effect = TRUE; gBattleScripting.moveendState++; break; @@ -6609,13 +6728,13 @@ static void Cmd_moveend(void) case MOVEEND_EMERGENCY_EXIT: // Special case, because moves hitting multiple opponents stop after switching out { // Because sorting the battlers by speed takes lots of cycles, - // we check if EE can be activated and cound how many. + // we check if EE can be activated and count how many. u32 numEmergencyExitBattlers = 0; u32 emergencyExitBattlers = 0; for (i = 0; i < gBattlersCount; i++) { - if (EmergencyExitCanBeTriggered(i)) + if (IsBattlerTurnDamaged(i) && EmergencyExitCanBeTriggered(i)) { emergencyExitBattlers |= 1u << i; numEmergencyExitBattlers++; @@ -6645,7 +6764,7 @@ static void Cmd_moveend(void) effect = TRUE; gBattleScripting.battler = battler; - if (gBattleTypeFlags & BATTLE_TYPE_TRAINER || IsOnPlayerSide(battler)) + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) BattleScriptCall(BattleScript_EmergencyExit); else BattleScriptCall(BattleScript_EmergencyExitWild); @@ -6654,10 +6773,22 @@ static void Cmd_moveend(void) } } if (effect) - gBattleScripting.moveendState = MOVEEND_OPPORTUNIST; + gBattleScripting.moveendState = MOVEEND_JUMP_TO_HIT_ESCAPE_PLUS_ONE; else gBattleScripting.moveendState++; break; + case MOVEEND_HIT_ESCAPE: + if (moveEffect == EFFECT_HIT_ESCAPE + && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) + && IsBattlerTurnDamaged(gBattlerTarget) + && IsBattlerAlive(gBattlerAttacker) + && !NoAliveMonsForBattlerSide(gBattlerTarget)) + { + effect = TRUE; + BattleScriptCall(BattleScript_EffectHitEscape); + } + gBattleScripting.moveendState++; + break; case MOVEEND_EJECT_PACK: { // 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. @@ -6693,10 +6824,6 @@ static void Cmd_moveend(void) if (!(ejectPackBattlers & 1u << battler)) continue; - // Hit escape moves activate before Eject Pack for user - if (moveEffect == EFFECT_HIT_ESCAPE && gBattlerAttacker == battler) - continue; - gBattleScripting.battler = battler; gLastUsedItem = gBattleMons[battler].item; effect = TRUE; @@ -6706,45 +6833,57 @@ static void Cmd_moveend(void) break; // Only the fastest Eject item activates } } - if (effect) - gBattleScripting.moveendState = MOVEEND_OPPORTUNIST; - else - gBattleScripting.moveendState++; + gBattleScripting.moveendState++; break; - case MOVEEND_HIT_ESCAPE: - if (moveEffect == EFFECT_HIT_ESCAPE - && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) - && IsBattlerTurnDamaged(gBattlerTarget) - && IsBattlerAlive(gBattlerAttacker) - && !NoAliveMonsForBattlerSide(gBattlerTarget)) + + case MOVEEND_ITEMS_EFFECTS_ALL: + while (gBattleStruct->eventState.moveEndBattler < gBattlersCount) { - effect = TRUE; - BattleScriptCall(BattleScript_EffectHitEscape); + u32 battler = gBattleStruct->eventState.moveEndBattler++; + enum HoldEffect holdEffect = GetBattlerHoldEffect(battler); + if (ItemBattleEffects(battler, 0, holdEffect, IsOnStatusChangeActivation) + || ItemBattleEffects(battler, 0, holdEffect, IsOnHpThresholdActivation)) + return; } + gBattleStruct->eventState.moveEndBattler = 0; + gBattleScripting.moveendState++; + break; + case MOVEEND_WHITE_HERB: + while (gBattleStruct->eventState.moveEndBattler < gBattlersCount) + { + u32 battler = gBattleStruct->eventState.moveEndBattler++; + if (!IsBattlerAlive(battler)) + continue; + + if (ItemBattleEffects(battler, 0, GetBattlerHoldEffect(battler), IsWhiteHerbActivation)) + return; + } + gBattleStruct->eventState.moveEndBattler = 0; gBattleScripting.moveendState++; break; case MOVEEND_OPPORTUNIST: - while (gBattleStruct->moveEndBattlerId < gBattlersCount) + while (gBattleStruct->eventState.moveEndBattler < gBattlersCount) { - u32 battler = gBattleStruct->moveEndBattlerId++; + u32 battler = gBattleStruct->eventState.moveEndBattler++; if (!IsBattlerAlive(battler)) continue; if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, battler, GetBattlerAbility(battler), 0, 0)) return; } - gBattleStruct->moveEndBattlerId = 0; + gBattleStruct->eventState.moveEndBattler = 0; gBattleScripting.moveendState++; break; case MOVEEND_MIRROR_HERB: - while (gBattleStruct->moveEndBattlerId < gBattlersCount) + while (gBattleStruct->eventState.moveEndBattler < gBattlersCount) { - u32 battler = gBattleStruct->moveEndBattlerId++; + u32 battler = gBattleStruct->eventState.moveEndBattler++; if (!IsBattlerAlive(battler)) continue; - if (ItemBattleEffects(ITEMEFFECT_MIRROR_HERB, battler)) + + if (ItemBattleEffects(battler, 0, GetBattlerHoldEffect(battler), IsMirrorHerbActivation)) return; } - gBattleStruct->moveEndBattlerId = 0; + gBattleStruct->eventState.moveEndBattler = 0; gBattleScripting.moveendState++; break; case MOVEEND_PICKPOCKET: @@ -6782,18 +6921,13 @@ static void Cmd_moveend(void) } gBattleScripting.moveendState++; break; - case MOVEEND_WHITE_HERB: - for (i = 0; i < gBattlersCount; i++) - { - if (!IsBattlerAlive(i)) - continue; - - if (ItemBattleEffects(ITEMEFFECT_WHITE_HERB, i)) - return; - } - gBattleScripting.moveendState++; - break; case MOVEEND_THIRD_MOVE_BLOCK: + if (gChosenMove == MOVE_UNAVAILABLE) + { + gBattleScripting.moveendState++; + break; + } + // Special case for Steel Roller since it has to check the chosen move if (GetMoveEffect(gChosenMove) == EFFECT_STEEL_ROLLER && IsBattlerTurnDamaged(gBattlerTarget)) { @@ -6820,7 +6954,7 @@ static void Cmd_moveend(void) u32 item = gBattleMons[gBattlerAttacker].item; gBattleMons[gBattlerAttacker].item = ITEM_NONE; gBattleStruct->battlerState[gBattlerAttacker].canPickupItem = TRUE; - gBattleStruct->usedHeldItems[gBattlerPartyIndexes[gBattlerAttacker]][GetBattlerSide(gBattlerAttacker)] = item; + GetBattlerPartyState(gBattlerAttacker)->usedHeldItem = item; CheckSetUnburden(gBattlerAttacker); BtlController_EmitSetMonData( gBattlerAttacker, @@ -6855,9 +6989,9 @@ static void Cmd_moveend(void) if (gCurrentMove != gLastResultingMoves[gBattlerAttacker] || gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT || gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) - gBattleStruct->sameMoveTurns[gBattlerAttacker] = 0; + gBattleStruct->metronomeItemCounter[gBattlerAttacker] = 0; else if (gCurrentMove == gLastResultingMoves[gBattlerAttacker] && gSpecialStatuses[gBattlerAttacker].parentalBondState != PARENTAL_BOND_1ST_HIT) - gBattleStruct->sameMoveTurns[gBattlerAttacker]++; + gBattleStruct->metronomeItemCounter[gBattlerAttacker]++; gBattleScripting.moveendState++; break; case MOVEEND_CLEAR_BITS: // Clear/Set bits for things like using a move for all targets and all hits. @@ -6899,6 +7033,8 @@ static void Cmd_moveend(void) gBattleMons[gBattlerAttacker].volatiles.charge = FALSE; if (gBattleMons[gBattlerAttacker].volatiles.destinyBond > 0) gBattleMons[gBattlerAttacker].volatiles.destinyBond--; + if (moveEffect == EFFECT_ECHOED_VOICE && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)) + gBattleStruct->incrementEchoedVoice = TRUE; // check if Stellar type boost should be used up if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_TERA && GetBattlerTeraType(gBattlerAttacker) == TYPE_STELLAR @@ -7018,7 +7154,7 @@ static void Cmd_sethealblock(void) else { gBattleMons[gBattlerTarget].volatiles.healBlock = TRUE; - gDisableStructs[gBattlerTarget].healBlockTimer = gBattleTurnCounter + 5; + gDisableStructs[gBattlerTarget].healBlockTimer = 5; gBattlescriptCurrInstr = cmd->nextInstr; } } @@ -7045,7 +7181,7 @@ static void Cmd_getswitchedmondata(void) if (TESTING && gBattlerPartyIndexes[battler] == gBattleStruct->monToSwitchIntoId[battler] - && gBattleStruct->hpBefore[battler] != 0) // battler is alive + && IsBattlerAlive(battler)) Test_ExitWithResult(TEST_RESULT_ERROR, 0, ":L:%s:%d: battler is trying to switch to themself", __FILE__, __LINE__); gBattlerPartyIndexes[battler] = gBattleStruct->monToSwitchIntoId[battler]; @@ -7172,6 +7308,9 @@ static void Cmd_switchinanim(void) | BATTLE_TYPE_GHOST))) HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[battler].species), FLAG_SET_SEEN, gBattleMons[battler].personality); + + GetBattlerPartyState(battler)->sentOut = TRUE; + gAbsentBattlerFlags &= ~(1u << battler); BtlController_EmitSwitchInAnim(battler, B_COMM_TO_CONTROLLER, gBattlerPartyIndexes[battler], cmd->dontClearTransform, cmd->dontClearSubstitute); @@ -7403,7 +7542,7 @@ static void Cmd_openpartyscreen(void) { if (((1u << i) & hitmarkerFaintBits)) { - u32 skipPartnerCheck = FALSE; + bool32 skipPartnerCheck = FALSE; if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS && GetBattlerSide(i) == B_SIDE_OPPONENT && TRAINER_BATTLE_PARAM.opponentB != TRAINER_NONE) @@ -7649,15 +7788,10 @@ static void UpdateSentMonFlags(u32 battler) gHitMarker &= ~HITMARKER_FAINTED(battler); gSpecialStatuses[battler].faintedHasReplacement = FALSE; - - if (!BattlerHasAi(battler)) - gBattleStruct->appearedInBattle |= 1u << gBattlerPartyIndexes[battler]; } static void SetDmgHazardsBattlescript(u8 battler, u8 multistringId) { - gBattleMons[battler].volatiles.destinyBond = 0; - gHitMarker &= ~HITMARKER_DESTINYBOND; gBattleScripting.battler = battler; gBattleCommunication[MULTISTRING_CHOOSER] = multistringId; @@ -7684,10 +7818,8 @@ void TryHazardsOnSwitchIn(u32 battler, u32 side, enum Hazards hazardType) && IsBattlerAffectedByHazards(battler, FALSE) && IsBattlerGrounded(battler, ability, GetBattlerHoldEffect(battler))) { - u8 spikesDmg = (5 - gSideTimers[side].spikesAmount) * 2; - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / (spikesDmg); - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; + s32 spikesDmg = GetNonDynamaxMaxHP(battler) / ((5 - gSideTimers[side].spikesAmount) * 2); + SetPassiveDamageAmount(battler, spikesDmg); SetDmgHazardsBattlescript(battler, B_MSG_PKMNHURTBYSPIKES); } break; @@ -7735,16 +7867,16 @@ void TryHazardsOnSwitchIn(u32 battler, u32 side, enum Hazards hazardType) case HAZARDS_STEALTH_ROCK: if (IsBattlerAffectedByHazards(battler, FALSE) && GetBattlerAbility(battler) != ABILITY_MAGIC_GUARD) { - gBattleStruct->moveDamage[battler] = GetStealthHazardDamage(TYPE_SIDE_HAZARD_POINTED_STONES, battler); - if (gBattleStruct->moveDamage[battler] != 0) + gBattleStruct->passiveHpUpdate[battler] = GetStealthHazardDamage(TYPE_SIDE_HAZARD_POINTED_STONES, battler); + if (gBattleStruct->passiveHpUpdate[battler] != 0) SetDmgHazardsBattlescript(battler, B_MSG_STEALTHROCKDMG); } break; case HAZARDS_STEELSURGE: if (IsBattlerAffectedByHazards(battler, FALSE) && GetBattlerAbility(battler) != ABILITY_MAGIC_GUARD) { - gBattleStruct->moveDamage[battler] = GetStealthHazardDamage(TYPE_SIDE_HAZARD_SHARP_STEEL, battler); - if (gBattleStruct->moveDamage[battler] != 0) + gBattleStruct->passiveHpUpdate[battler] = GetStealthHazardDamage(TYPE_SIDE_HAZARD_SHARP_STEEL, battler); + if (gBattleStruct->passiveHpUpdate[battler] != 0) SetDmgHazardsBattlescript(battler, B_MSG_SHARPSTEELDMG); } break; @@ -7780,6 +7912,16 @@ static bool32 DoSwitchInEffectsForBattler(u32 battler) gBattleStruct->battlerState[battler].storedLunarDance = FALSE; } } + else if (EmergencyExitCanBeTriggered(battler)) + { + gBattleScripting.battler = gBattlerAbility = battler; + gSpecialStatuses[battler].switchInItemDone = FALSE; + gBattleStruct->battlerState[battler].forcedSwitch = FALSE; + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + BattleScriptCall(BattleScript_EmergencyExit); + else + BattleScriptCall(BattleScript_EmergencyExitWild); + } else if (!gDisableStructs[battler].hazardsDone) { TryHazardsOnSwitchIn(battler, side, gBattleStruct->hazardsQueue[side][gBattleStruct->hazardsCounter]); @@ -7795,11 +7937,10 @@ static bool32 DoSwitchInEffectsForBattler(u32 battler) else if (gBattleMons[battler].hp != gBattleMons[battler].maxHP && gBattleStruct->zmove.healReplacement) { gBattleStruct->zmove.healReplacement = FALSE; - gBattleStruct->moveDamage[battler] = -1 * (gBattleMons[battler].maxHP); + SetHealAmount(battler, gBattleMons[battler].maxHP); gBattleScripting.battler = battler; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_Z_HP_TRAP; BattleScriptCall(BattleScript_HealReplacementZMove); - return TRUE; } else { @@ -7813,7 +7954,10 @@ static bool32 DoSwitchInEffectsForBattler(u32 battler) gDisableStructs[battler].truantSwitchInHack = 0; - if (DoSwitchInAbilities(battler) || ItemBattleEffects(ITEMEFFECT_ON_SWITCH_IN, battler)) + if (DoSwitchInAbilities(battler)) + return TRUE; + + if (ItemBattleEffects(battler, 0, GetBattlerHoldEffect(battler), IsOnSwitchInActivation)) return TRUE; for (i = 0; i < gBattlersCount; i++) @@ -7844,7 +7988,7 @@ static bool32 DoSwitchInEffectsForBattler(u32 battler) for (i = 0; i < gBattlersCount; i++) { - if (ItemBattleEffects(ITEMEFFECT_WHITE_HERB, i)) + if (ItemBattleEffects(i, 0, GetBattlerHoldEffect(i), IsWhiteHerbActivation)) return TRUE; } for (i = 0; i < gBattlersCount; i++) @@ -7854,7 +7998,7 @@ static bool32 DoSwitchInEffectsForBattler(u32 battler) } for (i = 0; i < gBattlersCount; i++) { - if (ItemBattleEffects(ITEMEFFECT_MIRROR_HERB, i)) + if (ItemBattleEffects(i, 0, GetBattlerHoldEffect(i), IsMirrorHerbActivation)) return TRUE; } @@ -7866,8 +8010,9 @@ static bool32 DoSwitchInEffectsForBattler(u32 battler) gBattleStruct->hpOnSwitchout[GetBattlerSide(i)] = gBattleMons[i].hp; } - gDisableStructs[battler].hazardsDone = FALSE; + gSpecialStatuses[battler].switchInItemDone = FALSE; gBattleStruct->battlerState[battler].forcedSwitch = FALSE; + gBattleStruct->battlerState[battler].wasAboveHalfHp = FALSE; return FALSE; } @@ -7918,7 +8063,7 @@ static void Cmd_switchineffects(void) return; } } - if (TrySwitchInEjectPack(ITEMEFFECT_NONE)) + if (TrySwitchInEjectPack(OTHER)) return; // All battlers done, end for (i = 0; i < gBattlersCount; i++) @@ -7930,7 +8075,7 @@ static void Cmd_switchineffects(void) break; default: UpdateSentMonFlags(battler); - if (!DoSwitchInEffectsForBattler(battler) && !TrySwitchInEjectPack(ITEMEFFECT_NONE)) + if (!DoSwitchInEffectsForBattler(battler) && !TrySwitchInEjectPack(OTHER)) gBattlescriptCurrInstr = cmd->nextInstr; break; } @@ -8233,6 +8378,7 @@ static void Cmd_yesnoboxstoplearningmove(void) } } +// TODO: passive damage hit anim for sub static void Cmd_hitanimation(void) { CMD_ARGS(u8 battler); @@ -8243,7 +8389,7 @@ static void Cmd_hitanimation(void) if (!(gBattleStruct->moveResultFlags[battler] & MOVE_RESULT_NO_EFFECT)) { - if (!(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE) + if (gBattleStruct->passiveHpUpdate[battler] > 0 || !(DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove)) || gDisableStructs[battler].substituteHP == 0) { @@ -8261,8 +8407,7 @@ static void Cmd_hitanimation(void) || gBattleStruct->noResultString[battlerDef] != CAN_DAMAGE) continue; - if (!(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE) - || !(DoesSubstituteBlockMove(gBattlerAttacker, battlerDef, gCurrentMove)) + if (!(DoesSubstituteBlockMove(gBattlerAttacker, battlerDef, gCurrentMove)) || gDisableStructs[battlerDef].substituteHP == 0) { BtlController_EmitHitAnimation(battlerDef, B_COMM_TO_CONTROLLER); @@ -8447,9 +8592,9 @@ static void Cmd_hidepartystatussummary(void) static void ResetValuesForCalledMove(void) { if (gBattlerByTurnOrder[gCurrentTurnActionNumber] != gBattlerAttacker) - gBattleStruct->atkCancellerTracker = 0; + gBattleStruct->eventState.atkCanceller = 0; else - gBattleStruct->atkCancellerTracker = CANCELLER_VOLATILE_BLOCKED; + gBattleStruct->eventState.atkCanceller = CANCELLER_VOLATILE_BLOCKED; gBattleScripting.animTurn = 0; gBattleScripting.animTargetsHit = 0; SetTypeBeforeUsingMove(gCurrentMove, gBattlerAttacker); @@ -8566,7 +8711,7 @@ static void Cmd_setgravity(void) else { gFieldStatuses |= STATUS_FIELD_GRAVITY; - gFieldTimers.gravityTimer = gBattleTurnCounter + 5; + gFieldTimers.gravityTimer = 5; gBattlescriptCurrInstr = cmd->nextInstr; } } @@ -8579,13 +8724,8 @@ static bool32 TryCheekPouch(u32 battler, u32 itemId) && GetBattlerPartyState(battler)->ateBerry && !IsBattlerAtMaxHp(battler)) { - gBattleStruct->cheekPouchActivated = TRUE; - gBattleStruct->savedcheekPouchDamage = gBattleStruct->moveDamage[battler]; - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 3; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; - gBattleStruct->moveDamage[battler] *= -1; gBattlerAbility = battler; + SetHealAmount(battler, GetNonDynamaxMaxHP(battler) / 3); BattleScriptPush(gBattlescriptCurrInstr + 2); gBattlescriptCurrInstr = BattleScript_CheekPouchActivates; return TRUE; @@ -8593,16 +8733,6 @@ static bool32 TryCheekPouch(u32 battler, u32 itemId) return FALSE; } -// When Cheek Pouch activates mid-battle it overwrites the current damage, so restore it -static void TryRestoreDamageAfterCheekPouch(u32 battler) -{ - if (gBattleStruct->cheekPouchActivated) - { - gBattleStruct->moveDamage[battler] = gBattleStruct->savedcheekPouchDamage; - gBattleStruct->cheekPouchActivated = FALSE; - } -} - // Used by Bestow and Symbiosis to take an item from one battler and give to another. static void BestowItem(u32 battlerAtk, u32 battlerDef) { @@ -8665,8 +8795,8 @@ static void Cmd_removeitem(void) // Popped Air Balloon cannot be restored by any means. // Corroded items cannot be restored either. if (GetBattlerHoldEffect(battler) != HOLD_EFFECT_AIR_BALLOON - && GetMoveEffect(gCurrentMove) != EFFECT_CORROSIVE_GAS) - gBattleStruct->usedHeldItems[gBattlerPartyIndexes[battler]][GetBattlerSide(battler)] = itemId; // Remember if switched out + && GetMoveEffect(gCurrentMove) != EFFECT_CORROSIVE_GAS) + GetBattlerPartyState(battler)->usedHeldItem = itemId; // Remember if switched out gBattleMons[battler].item = ITEM_NONE; gBattleStruct->battlerState[battler].canPickupItem = TRUE; @@ -9093,18 +9223,18 @@ static void Cmd_useitemonopponent(void) bool32 CanUseLastResort(u8 battler) { - u32 i; - u32 knownMovesCount = 0, usedMovesCount = 0; - - for (i = 0; i < 4; i++) + u32 moveIndex; + for (moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++) { - if (gBattleMons[battler].moves[i] != MOVE_NONE) - knownMovesCount++; - if (i != gCurrMovePos && gDisableStructs[battler].usedMoves & (1u << i)) // Increment used move count for all moves except current Last Resort. - usedMovesCount++; + u32 move = gBattleMons[battler].moves[moveIndex]; + // Assumes that an empty slot cannot have a non-empty slot after it + if (move == MOVE_NONE) + break; + // If not Last Resort and has not been used, can't use Last Resort + if (GetMoveEffect(move) != EFFECT_LAST_RESORT && !(gDisableStructs[battler].usedMoves & (1u << moveIndex))) + return FALSE; } - - return (knownMovesCount >= 2 && usedMovesCount >= knownMovesCount - 1); + return moveIndex >= 2; // At least two usable moves that are either Last Resort or have been used } static void RemoveAllWeather(void) @@ -9306,9 +9436,11 @@ u32 IsAbilityStatusProtected(u32 battler, enum Ability ability) || IsFlowerVeilProtected(battler); } -u32 GetHighestStatId(u32 battler) +enum Stat GetHighestStatId(u32 battler) { - u32 i, highestId = STAT_ATK, highestStat = gBattleMons[battler].attack; + enum Stat i; + enum Stat highestId = STAT_ATK; + u32 highestStat = gBattleMons[battler].attack; for (i = STAT_DEF; i < NUM_STATS; i++) { @@ -9515,15 +9647,8 @@ static bool32 ChangeOrderTargetAfterAttacker(void) return TRUE; } -// will be deprecated next release cycle -static void Cmd_various(void) +static void Cmd_unused_0x78(void) { - CMD_ARGS(u8 battler, u8 id); - - if (gBattleControllerExecFlags) - return; - - gBattlescriptCurrInstr = cmd->nextInstr; } static void TryResetProtectUseCounter(u32 battler) @@ -9550,7 +9675,7 @@ static void Cmd_setprotectlike(void) if (gCurrentTurnActionNumber == (gBattlersCount - 1)) notLastTurn = FALSE; - if ((sProtectSuccessRates[gDisableStructs[gBattlerAttacker].protectUses] >= Random() && notLastTurn) + if ((sProtectSuccessRates[gDisableStructs[gBattlerAttacker].protectUses] >= RandomUniform(RNG_PROTECT_FAIL, 0, USHRT_MAX) && notLastTurn) || (protectMethod == PROTECT_WIDE_GUARD && B_WIDE_GUARD != GEN_5) || (protectMethod == PROTECT_QUICK_GUARD && B_QUICK_GUARD != GEN_5)) { @@ -9579,6 +9704,7 @@ static void Cmd_setprotectlike(void) gDisableStructs[gBattlerAttacker].protectUses = 0; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_PROTECT_FAILED; gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED; + gBattleStruct->battlerState[gBattlerAttacker].stompingTantrumTimer = 2; } gBattlescriptCurrInstr = cmd->nextInstr; @@ -9591,7 +9717,7 @@ static void Cmd_tryexplosion(void) if (gBattleControllerExecFlags) return; - gBattleStruct->moveDamage[gBattlerAttacker] = gBattleMons[gBattlerAttacker].hp; + gBattleStruct->passiveHpUpdate[gBattlerAttacker] = gBattleMons[gBattlerAttacker].hp; BtlController_EmitHealthBarUpdate(gBattlerAttacker, B_COMM_TO_CONTROLLER, INSTANT_HP_BAR_DROP); MarkBattlerForControllerExec(gBattlerAttacker); gBattlescriptCurrInstr = cmd->nextInstr; @@ -9645,11 +9771,7 @@ static void Cmd_tryhealhalfhealth(void) if (cmd->battler == BS_ATTACKER) gBattlerTarget = gBattlerAttacker; - gBattleStruct->moveDamage[gBattlerTarget] = GetNonDynamaxMaxHP(gBattlerTarget) / 2; - if (gBattleStruct->moveDamage[gBattlerTarget] == 0) - gBattleStruct->moveDamage[gBattlerTarget] = 1; - gBattleStruct->moveDamage[gBattlerTarget] *= -1; - + SetHealAmount(gBattlerTarget, GetNonDynamaxMaxHP(gBattlerTarget) / 2); if (gBattleMons[gBattlerTarget].hp == gBattleMons[gBattlerTarget].maxHP) gBattlescriptCurrInstr = failInstr; else @@ -9666,7 +9788,7 @@ static void Cmd_setfieldweather(void) u8 battleWeatherId = cmd->weather; - if (!TryChangeBattleWeather(gBattlerAttacker, battleWeatherId, FALSE)) + if (!TryChangeBattleWeather(gBattlerAttacker, battleWeatherId, ABILITY_NONE)) { gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_FAILED; @@ -9739,21 +9861,19 @@ static void Cmd_manipulatedamage(void) switch (cmd->mode) { case DMG_CHANGE_SIGN: - gBattleStruct->moveDamage[gBattlerAttacker] *= -1; + gBattleStruct->passiveHpUpdate[gBattlerAttacker] *= -1; break; case DMG_DOUBLED: gBattleStruct->moveDamage[gBattlerTarget] *= 2; break; case DMG_1_8_TARGET_HP: - gBattleStruct->moveDamage[gBattlerTarget] = GetNonDynamaxMaxHP(gBattlerTarget) / 8; - if (gBattleStruct->moveDamage[gBattlerTarget] == 0) - gBattleStruct->moveDamage[gBattlerTarget] = 1; + SetPassiveDamageAmount(gBattlerTarget, GetNonDynamaxMaxHP(gBattlerTarget) / 8); break; case DMG_FULL_ATTACKER_HP: - gBattleStruct->moveDamage[gBattlerTarget] = GetNonDynamaxMaxHP(gBattlerAttacker); + gBattleStruct->passiveHpUpdate[gBattlerTarget] = GetNonDynamaxMaxHP(gBattlerAttacker); break; case DMG_BIG_ROOT: - gBattleStruct->moveDamage[gBattlerAttacker] = GetDrainedBigRootHp(gBattlerAttacker, gBattleStruct->moveDamage[gBattlerAttacker]); + gBattleStruct->passiveHpUpdate[gBattlerAttacker] = -1 * GetDrainedBigRootHp(gBattlerAttacker, gBattleStruct->passiveHpUpdate[gBattlerAttacker]); break; } @@ -9765,9 +9885,9 @@ static void Cmd_trysetrest(void) CMD_ARGS(); gBattlerTarget = gBattlerAttacker; - gBattleStruct->moveDamage[gBattlerTarget] = gBattleMons[gBattlerTarget].maxHP * (-1); + SetHealAmount(gBattlerTarget, gBattleMons[gBattlerTarget].maxHP); enum Ability ability = GetBattlerAbility(gBattlerTarget); - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(gBattlerTarget); + enum HoldEffect holdEffect = GetBattlerHoldEffect(gBattlerTarget); if (IsBattlerTerrainAffected(gBattlerTarget, ability, holdEffect, STATUS_FIELD_ELECTRIC_TERRAIN)) { @@ -9887,19 +10007,15 @@ static void Cmd_stockpiletohpheal(void) { if (gDisableStructs[gBattlerAttacker].stockpileCounter > 0) { - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / (1 << (3 - gDisableStructs[gBattlerAttacker].stockpileCounter)); + SetHealAmount(gBattlerAttacker, GetNonDynamaxMaxHP(gBattlerAttacker) / (1 << (3 - gDisableStructs[gBattlerAttacker].stockpileCounter))); gBattleScripting.animTurn = gDisableStructs[gBattlerAttacker].stockpileCounter; } else // Snatched move { - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 4; + SetHealAmount(gBattlerAttacker, GetNonDynamaxMaxHP(gBattlerAttacker) / 4); gBattleScripting.animTurn = 1; } - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; - gBattleStruct->moveDamage[gBattlerAttacker] *= -1; - gBattlescriptCurrInstr = cmd->nextInstr; gBattlerTarget = gBattlerAttacker; } @@ -9923,17 +10039,8 @@ void BS_RemoveStockpileCounters(void) } } -// Sign change for drained HP handled in GetDrainedBigRootHp -static void Cmd_setdrainedhp(void) +static void Cmd_unused_0x88(void) { - CMD_ARGS(); - - gBattleStruct->moveDamage[gBattlerAttacker] = (gBattleStruct->moveDamage[gBattlerTarget] * GetMoveAbsorbPercentage(gCurrentMove) / 100); - - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; - - gBattlescriptCurrInstr = cmd->nextInstr; } static u16 ReverseStatChangeMoveEffect(u16 moveEffect) @@ -10006,7 +10113,7 @@ static u16 ReverseStatChangeMoveEffect(u16 moveEffect) static void TryPlayStatChangeAnimation(u32 battler, enum Ability ability, u32 stats, s32 statValue, u32 statId, bool32 certain) { - u32 currStat = 0; + enum Stat currStat = 0; u32 changeableStatsCount = 1; // current stat is counted automatically u32 statAnimId = statId; bool32 statChangeByTwo = statValue > 1 || statValue < -1; @@ -10092,10 +10199,10 @@ static void TryPlayStatChangeAnimation(u32 battler, enum Ability ability, u32 st } } -static u32 ChangeStatBuffs(u32 battler, s8 statValue, u32 statId, union StatChangeFlags flags, u32 stats, const u8 *BS_ptr) +static u32 ChangeStatBuffs(u32 battler, s8 statValue, enum Stat statId, union StatChangeFlags flags, u32 stats, const u8 *BS_ptr) { u32 index, battlerAbility; - enum ItemHoldEffect battlerHoldEffect; + enum HoldEffect battlerHoldEffect; battlerAbility = GetBattlerAbility(battler); battlerHoldEffect = GetBattlerHoldEffect(battler); gSpecialStatuses[battler].changedStatsBattlerId = gBattlerAttacker; @@ -10796,7 +10903,7 @@ static void Cmd_tryKO(void) CMD_ARGS(const u8 *failInstr); enum BattleMoveEffects effect = GetMoveEffect(gCurrentMove); - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(gBattlerTarget); + enum HoldEffect holdEffect = GetBattlerHoldEffect(gBattlerTarget); enum Ability targetAbility = GetBattlerAbility(gBattlerTarget); u32 rand = Random() % 100; u32 affectionScore = GetBattlerAffectionHearts(gBattlerTarget); @@ -11022,7 +11129,7 @@ static void Cmd_setmist(void) } else { - gSideTimers[GetBattlerSide(gBattlerAttacker)].mistTimer = gBattleTurnCounter + 5; + gSideTimers[GetBattlerSide(gBattlerAttacker)].mistTimer = 5; gSideStatuses[GetBattlerSide(gBattlerAttacker)] |= SIDE_STATUS_MIST; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_MIST; } @@ -11048,7 +11155,8 @@ static void Cmd_setfocusenergy(void) } else { - if (GetGenConfig(GEN_CONFIG_FOCUS_ENERGY_CRIT_RATIO) >= GEN_3) + if (GetGenConfig(GEN_CONFIG_FOCUS_ENERGY_CRIT_RATIO) >= GEN_3 + || GetGenConfig(GEN_CONFIG_CRIT_CHANCE) == GEN_1) gBattleMons[battler].volatiles.focusEnergy = TRUE; else gBattleMons[battler].volatiles.dragonCheer = TRUE; @@ -11080,7 +11188,10 @@ static void Cmd_transformdataexecution(void) gDisableStructs[gBattlerAttacker].disabledMove = MOVE_NONE; gDisableStructs[gBattlerAttacker].disableTimer = 0; gDisableStructs[gBattlerAttacker].transformedMonPersonality = gBattleMons[gBattlerTarget].personality; - gDisableStructs[gBattlerAttacker].transformedMonShininess = gBattleMons[gBattlerTarget].isShiny; + if (B_TRANSFORM_SHINY >= GEN_4) + gDisableStructs[gBattlerAttacker].transformedMonShininess = gBattleMons[gBattlerTarget].isShiny; + else + gDisableStructs[gBattlerAttacker].transformedMonShininess = gBattleMons[gBattlerAttacker].isShiny; gDisableStructs[gBattlerAttacker].mimickedMoves = 0; gDisableStructs[gBattlerAttacker].usedMoves = 0; @@ -11120,7 +11231,7 @@ static void Cmd_setsubstitute(void) CMD_ARGS(); u32 factor = GetMoveEffect(gCurrentMove) == EFFECT_SHED_TAIL ? 2 : 4; - u32 hp; + s32 hp = 0; if (factor == 2) hp = (GetNonDynamaxMaxHP(gBattlerAttacker)+1) / factor; // shed tail rounds up @@ -11132,25 +11243,22 @@ static void Cmd_setsubstitute(void) if (gBattleMons[gBattlerAttacker].hp <= hp) { - gBattleStruct->moveDamage[gBattlerAttacker] = 0; + hp = 0; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SUBSTITUTE_FAILED; } else { - gBattleStruct->moveDamage[gBattlerAttacker] = hp; // one bit value will only work for Pokémon which max hp can go to 1020(which is more than possible in games) - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; - gBattleMons[gBattlerAttacker].volatiles.substitute = TRUE; gBattleMons[gBattlerAttacker].volatiles.wrapped = FALSE; + // gDisableStructs[gBattlerAttacker].substituteHP = (factor == 2) ? (hp / 2) : hp; if (factor == 2) - gDisableStructs[gBattlerAttacker].substituteHP = gBattleStruct->moveDamage[gBattlerAttacker] / 2; + gDisableStructs[gBattlerAttacker].substituteHP = hp / 2; else - gDisableStructs[gBattlerAttacker].substituteHP = gBattleStruct->moveDamage[gBattlerAttacker]; + gDisableStructs[gBattlerAttacker].substituteHP = hp; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_SUBSTITUTE; - gHitMarker |= HITMARKER_IGNORE_SUBSTITUTE; } + gBattleStruct->passiveHpUpdate[gBattlerAttacker] = hp; gBattlescriptCurrInstr = cmd->nextInstr; } @@ -11351,8 +11459,8 @@ static void Cmd_painsplitdmgcalc(void) { s32 hpDiff = (gBattleMons[gBattlerAttacker].hp + GetNonDynamaxHP(gBattlerTarget)) / 2; - gBattleStruct->moveDamage[gBattlerTarget] = GetNonDynamaxHP(gBattlerTarget) - hpDiff; - gBattleStruct->moveDamage[gBattlerAttacker] = gBattleMons[gBattlerAttacker].hp - hpDiff; + gBattleStruct->passiveHpUpdate[gBattlerTarget] = GetNonDynamaxHP(gBattlerTarget) - hpDiff; + gBattleStruct->passiveHpUpdate[gBattlerAttacker] = gBattleMons[gBattlerAttacker].hp - hpDiff; gBattlescriptCurrInstr = cmd->nextInstr; } @@ -11569,22 +11677,8 @@ static void Cmd_unused_AA(void) { } -static void TrySetDestinyBondToHappen(void) +static void Cmd_unused_0xab(void) { - if (gBattleMons[gBattlerTarget].volatiles.destinyBond - && !IsBattlerAlly(gBattlerAttacker, gBattlerTarget) - && !(gHitMarker & HITMARKER_GRUDGE)) - { - gHitMarker |= HITMARKER_DESTINYBOND; - } -} - -static void Cmd_trysetdestinybondtohappen(void) -{ - CMD_ARGS(); - - TrySetDestinyBondToHappen(); - gBattlescriptCurrInstr = cmd->nextInstr; } static void Cmd_settailwind(void) @@ -11596,7 +11690,7 @@ static void Cmd_settailwind(void) if (!(gSideStatuses[side] & SIDE_STATUS_TAILWIND)) { gSideStatuses[side] |= SIDE_STATUS_TAILWIND; - gSideTimers[side].tailwindTimer = gBattleTurnCounter + (B_TAILWIND_TURNS >= GEN_5 ? 4 : 3); + gSideTimers[side].tailwindTimer = (B_TAILWIND_TURNS >= GEN_5 ? 4 : 3); gBattlescriptCurrInstr = cmd->nextInstr; } else @@ -11783,10 +11877,7 @@ static void Cmd_cursetarget(void) else { gBattleMons[gBattlerTarget].volatiles.cursed = TRUE; - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 2; - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; - + SetPassiveDamageAmount(gBattlerAttacker, GetNonDynamaxMaxHP(gBattlerAttacker) / 2); gBattlescriptCurrInstr = cmd->nextInstr; } } @@ -11879,7 +11970,7 @@ static void Cmd_jumpifconfusedandstatmaxed(void) CMD_ARGS(u8 stat, const u8 *jumpInstr); if (gBattleMons[gBattlerTarget].volatiles.confusionTurns > 0 - && !CompareStat(gBattlerTarget, cmd->stat, MAX_STAT_STAGE, CMP_LESS_THAN)) + && !CompareStat(gBattlerTarget, cmd->stat, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(gBattlerTarget))) gBattlescriptCurrInstr = cmd->jumpInstr; // Fails if we're confused AND stat cannot be raised else gBattlescriptCurrInstr = cmd->nextInstr; @@ -11924,7 +12015,7 @@ static void Cmd_setembargo(void) else { gBattleMons[gBattlerTarget].volatiles.embargo = TRUE; - gDisableStructs[gBattlerTarget].embargoTimer = gBattleTurnCounter + 5; + gDisableStructs[gBattlerTarget].embargoTimer = 5; gBattlescriptCurrInstr = cmd->nextInstr; } } @@ -11957,11 +12048,7 @@ static void Cmd_presentdamagecalculation(void) } else { - // TODO: Check if this is correct - gBattleStruct->moveDamage[gBattlerTarget] = GetNonDynamaxMaxHP(gBattlerTarget) / 4; - if (gBattleStruct->moveDamage[gBattlerTarget] == 0) - gBattleStruct->moveDamage[gBattlerTarget] = 1; - gBattleStruct->moveDamage[gBattlerTarget] *= -1; + SetHealAmount(gBattlerTarget, GetNonDynamaxMaxHP(gBattlerTarget) / 4); gBattleStruct->presentBasePower = 0; } } @@ -11993,7 +12080,7 @@ static void Cmd_setsafeguard(void) else { gSideStatuses[GetBattlerSide(gBattlerAttacker)] |= SIDE_STATUS_SAFEGUARD; - gSideTimers[GetBattlerSide(gBattlerAttacker)].safeguardTimer = gBattleTurnCounter + 5; + gSideTimers[GetBattlerSide(gBattlerAttacker)].safeguardTimer = 5; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_SAFEGUARD; } @@ -12099,12 +12186,29 @@ static void Cmd_jumpifnopursuitswitchdmg(void) } } -static void Cmd_tryrestorehpberry(void) +static void Cmd_tryactivateitem(void) { - CMD_ARGS(u8 battler); + CMD_ARGS(u8 battler, u8 flag); u32 battler = GetBattlerForBattleScript(cmd->battler); - if (TryRestoreHPBerries(battler, ITEMEFFECT_TRY_HEALING)) - return; + + switch ((enum ItemActivationState)cmd->flag) + { + case ACTIVATION_ON_USABLE_AGAIN: + case ACTIVATION_ON_PICK_UP: + if (ItemBattleEffects(battler, 0, GetBattlerHoldEffect(battler), IsForceTriggerItemActivation)) + return; + break; + case ACTIVATION_ON_HARVEST: + gLastUsedItem = gBattleMons[battler].item; + if (ItemBattleEffects(battler, 0, GetBattlerHoldEffect(battler), IsOnBerryActivation)) + return; + break; + case ACTIVATION_ON_HP_THRESHOLD: + if (ItemBattleEffects(battler, 0, GetBattlerHoldEffect(battler), IsOnHpThresholdActivation)) + return; + break; + } + gBattlescriptCurrInstr = cmd->nextInstr; } @@ -12120,10 +12224,7 @@ static void Cmd_halvehp(void) if (gBattleMons[gBattlerAttacker].hp > halfHp) { - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 2; - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; - + SetPassiveDamageAmount(gBattlerAttacker, GetNonDynamaxMaxHP(gBattlerAttacker) / 2); gBattlescriptCurrInstr = cmd->nextInstr; } else @@ -12158,8 +12259,8 @@ static void Cmd_rapidspinfree(void) { gBattleScripting.battler = gBattlerTarget; gBattleMons[gBattlerAttacker].volatiles.wrapped = FALSE; - gBattlerTarget = gBattleStruct->wrappedBy[gBattlerAttacker]; - PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleStruct->wrappedMove[gBattlerAttacker]); + gBattlerTarget = gBattleMons[gBattlerAttacker].volatiles.wrappedBy; + PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleMons[gBattlerAttacker].volatiles.wrappedMove); BattleScriptCall(BattleScript_WrapFree); } else if (gBattleMons[gBattlerAttacker].volatiles.leechSeed) @@ -12197,21 +12298,22 @@ static void Cmd_recoverbasedonsunlight(void) gBattlerTarget = gBattlerAttacker; if (gBattleMons[gBattlerAttacker].hp != gBattleMons[gBattlerAttacker].maxHP) { + s32 recoverAmount = 0; if (GetMoveEffect(gCurrentMove) == EFFECT_SHORE_UP) { if (HasWeatherEffect() && gBattleWeather & B_WEATHER_SANDSTORM) - gBattleStruct->moveDamage[gBattlerAttacker] = 20 * GetNonDynamaxMaxHP(gBattlerAttacker) / 30; + recoverAmount = 20 * GetNonDynamaxMaxHP(gBattlerAttacker) / 30; else - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 2; + recoverAmount = GetNonDynamaxMaxHP(gBattlerAttacker) / 2; } else if (GetGenConfig(GEN_CONFIG_TIME_OF_DAY_HEALING_MOVES) != GEN_2) { if (!(gBattleWeather & B_WEATHER_ANY) || !HasWeatherEffect() || GetBattlerHoldEffect(gBattlerAttacker) == HOLD_EFFECT_UTILITY_UMBRELLA) - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 2; + recoverAmount = GetNonDynamaxMaxHP(gBattlerAttacker) / 2; else if (gBattleWeather & B_WEATHER_SUN) - gBattleStruct->moveDamage[gBattlerAttacker] = 20 * GetNonDynamaxMaxHP(gBattlerAttacker) / 30; + recoverAmount = 20 * GetNonDynamaxMaxHP(gBattlerAttacker) / 30; else // not sunny weather - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 4; + recoverAmount = GetNonDynamaxMaxHP(gBattlerAttacker) / 4; } else // B_TIME_OF_DAY_HEALING_MOVES == GEN_2 { @@ -12239,18 +12341,15 @@ static void Cmd_recoverbasedonsunlight(void) } if (!(gBattleWeather & B_WEATHER_ANY) || !HasWeatherEffect() || GetBattlerHoldEffect(gBattlerAttacker) == HOLD_EFFECT_UTILITY_UMBRELLA) - gBattleStruct->moveDamage[gBattlerAttacker] = healingModifier * GetNonDynamaxMaxHP(gBattlerAttacker) / 4; + recoverAmount = healingModifier * GetNonDynamaxMaxHP(gBattlerAttacker) / 4; else if (gBattleWeather & B_WEATHER_SUN) - gBattleStruct->moveDamage[gBattlerAttacker] = healingModifier * GetNonDynamaxMaxHP(gBattlerAttacker) / 2; + recoverAmount = healingModifier * GetNonDynamaxMaxHP(gBattlerAttacker) / 2; else // not sunny weather - gBattleStruct->moveDamage[gBattlerAttacker] = healingModifier * GetNonDynamaxMaxHP(gBattlerAttacker) / 8; + recoverAmount = healingModifier * GetNonDynamaxMaxHP(gBattlerAttacker) / 8; } - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; - gBattleStruct->moveDamage[gBattlerAttacker] *= -1; - + SetHealAmount(gBattlerAttacker, recoverAmount); gBattlescriptCurrInstr = cmd->nextInstr; } else @@ -12298,11 +12397,10 @@ static void Cmd_setfutureattack(void) { CMD_ARGS(); - gSideStatuses[GetBattlerSide(gBattlerTarget)] |= SIDE_STATUS_FUTUREATTACK; gWishFutureKnock.futureSightMove[gBattlerTarget] = gCurrentMove; gWishFutureKnock.futureSightBattlerIndex[gBattlerTarget] = gBattlerAttacker; gWishFutureKnock.futureSightPartyIndex[gBattlerTarget] = gBattlerPartyIndexes[gBattlerAttacker]; - gWishFutureKnock.futureSightCounter[gBattlerTarget] = gBattleTurnCounter + 3; + gWishFutureKnock.futureSightCounter[gBattlerTarget] = 3; if (gCurrentMove == MOVE_DOOM_DESIRE) gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_DOOM_DESIRE; @@ -12441,9 +12539,10 @@ static void Cmd_trymemento(void) else { // Success, drop user's HP bar to 0 - gBattleStruct->moveDamage[gBattlerAttacker] = gBattleMons[gBattlerAttacker].hp; + gBattleStruct->passiveHpUpdate[gBattlerAttacker] = gBattleMons[gBattlerAttacker].hp; BtlController_EmitHealthBarUpdate(gBattlerAttacker, B_COMM_TO_CONTROLLER, INSTANT_HP_BAR_DROP); MarkBattlerForControllerExec(gBattlerAttacker); + gBattlescriptCurrInstr = cmd->nextInstr; } } @@ -12532,7 +12631,7 @@ static void Cmd_settaunt(void) { CMD_ARGS(const u8 *failInstr); - if (B_OBLIVIOUS_TAUNT >= GEN_6 && GetBattlerAbility(gBattlerTarget) == ABILITY_OBLIVIOUS) + if (GetGenConfig(GEN_CONFIG_OBLIVIOUS_TAUNT) >= GEN_6 && GetBattlerAbility(gBattlerTarget) == ABILITY_OBLIVIOUS) { gBattlescriptCurrInstr = BattleScript_NotAffectedAbilityPopUp; gLastUsedAbility = ABILITY_OBLIVIOUS; @@ -12569,11 +12668,16 @@ static void Cmd_trysethelpinghand(void) { CMD_ARGS(const u8 *failInstr); + if (!IsDoubleBattle()) + { + gBattlescriptCurrInstr = cmd->failInstr; + return; + } + gBattlerTarget = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gBattlerAttacker))); - if (IsDoubleBattle() - && !(gAbsentBattlerFlags & (1u << gBattlerTarget)) - && !HasBattlerActedThisTurn(gBattlerTarget)) + if (!(gAbsentBattlerFlags & (1u << gBattlerTarget)) + && !HasBattlerActedThisTurn(gBattlerTarget)) { gProtectStructs[gBattlerTarget].helpingHand++; gBattlescriptCurrInstr = cmd->nextInstr; @@ -12584,7 +12688,7 @@ static void Cmd_trysethelpinghand(void) } } -// Trick +// Trick // TODO: Sticky Hold static void Cmd_tryswapitems(void) { CMD_ARGS(const u8 *failInstr); @@ -12656,8 +12760,10 @@ static void Cmd_tryswapitems(void) BtlController_EmitSetMonData(gBattlerTarget, B_COMM_TO_CONTROLLER, REQUEST_HELDITEM_BATTLE, 0, sizeof(gBattleMons[gBattlerTarget].item), &gBattleMons[gBattlerTarget].item); MarkBattlerForControllerExec(gBattlerTarget); - gBattleStruct->choicedMove[gBattlerTarget] = MOVE_NONE; - gBattleStruct->choicedMove[gBattlerAttacker] = MOVE_NONE; + if (GetBattlerAbility(gBattlerTarget) != ABILITY_GORILLA_TACTICS) + gBattleStruct->choicedMove[gBattlerTarget] = MOVE_NONE; + if (GetBattlerAbility(gBattlerTarget) != ABILITY_GORILLA_TACTICS) + gBattleStruct->choicedMove[gBattlerAttacker] = MOVE_NONE; gBattlescriptCurrInstr = cmd->nextInstr; @@ -12745,9 +12851,9 @@ static void Cmd_trywish(void) { gBattlescriptCurrInstr = cmd->failInstr; } - else if (gWishFutureKnock.wishCounter[gBattlerAttacker] <= gBattleTurnCounter) + else if (gWishFutureKnock.wishCounter[gBattlerAttacker] == 0) { - gWishFutureKnock.wishCounter[gBattlerAttacker] = gBattleTurnCounter + 2; + gWishFutureKnock.wishCounter[gBattlerAttacker] = 2; gWishFutureKnock.wishPartyId[gBattlerAttacker] = gBattlerPartyIndexes[gBattlerAttacker]; gBattlescriptCurrInstr = cmd->nextInstr; } @@ -12802,7 +12908,7 @@ static void Cmd_setyawn(void) { CMD_ARGS(const u8 *failInstr); enum Ability ability = GetBattlerAbility(gBattlerTarget); - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(gBattlerTarget); + enum HoldEffect holdEffect = GetBattlerHoldEffect(gBattlerTarget); if (gBattleMons[gBattlerTarget].volatiles.yawn || gBattleMons[gBattlerTarget].status1 & STATUS1_ANY) @@ -12853,7 +12959,7 @@ static void HandleRoomMove(u32 statusFlag, u16 *timer, u8 stringId) else { gFieldStatuses |= statusFlag; - *timer = gBattleTurnCounter + 5; + *timer = 5; gBattleCommunication[MULTISTRING_CHOOSER] = stringId; } } @@ -12996,10 +13102,10 @@ static void Cmd_trysetvolatile(void) switch (cmd->_volatile) { case VOLATILE_MAGNET_RISE: - gDisableStructs[battler].magnetRiseTimer = gBattleTurnCounter + 5; + gDisableStructs[battler].magnetRiseTimer = 5; break; case VOLATILE_LASER_FOCUS: - gDisableStructs[battler].laserFocusTimer = gBattleTurnCounter + 2; + gDisableStructs[battler].laserFocusTimer = 2; break; default: break; @@ -13194,7 +13300,7 @@ static void Cmd_settypebasedhalvers(void) if (!(gFieldStatuses & STATUS_FIELD_MUDSPORT)) { gFieldStatuses |= STATUS_FIELD_MUDSPORT; - gFieldTimers.mudSportTimer = gBattleTurnCounter + 5; + gFieldTimers.mudSportTimer = 5; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEAKEN_ELECTRIC; worked = TRUE; } @@ -13216,7 +13322,7 @@ static void Cmd_settypebasedhalvers(void) if (!(gFieldStatuses & STATUS_FIELD_WATERSPORT)) { gFieldStatuses |= STATUS_FIELD_WATERSPORT; - gFieldTimers.waterSportTimer = gBattleTurnCounter + 5; + gFieldTimers.waterSportTimer = 5; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEAKEN_FIRE; worked = TRUE; } @@ -13252,11 +13358,10 @@ bool32 DoesSubstituteBlockMove(u32 battlerAtk, u32 battlerDef, u32 move) bool32 DoesDisguiseBlockMove(u32 battler, u32 move) { - if (!(gBattleMons[battler].species == SPECIES_MIMIKYU_DISGUISED || gBattleMons[battler].species == SPECIES_MIMIKYU_TOTEM_DISGUISED) - || gBattleMons[battler].volatiles.transformed - || (!gProtectStructs[battler].confusionSelfDmg && (IsBattleMoveStatus(move) || gHitMarker & HITMARKER_PASSIVE_HP_UPDATE)) - || gHitMarker & HITMARKER_IGNORE_DISGUISE - || !IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_DISGUISE)) + if (!IsMimikyuDisguised(battler) + || gBattleMons[battler].volatiles.transformed + || (!gProtectStructs[battler].confusionSelfDmg && IsBattleMoveStatus(move)) + || !IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_DISGUISE)) return FALSE; else return TRUE; @@ -13279,9 +13384,9 @@ static void Cmd_tryrecycleitem(void) u16 *usedHeldItem; if (gCurrentMove == MOVE_NONE && GetBattlerAbility(gBattlerAttacker) == ABILITY_PICKUP) - usedHeldItem = &gBattleStruct->usedHeldItems[gBattlerPartyIndexes[gBattlerTarget]][GetBattlerSide(gBattlerTarget)]; + usedHeldItem = &GetBattlerPartyState(gBattlerTarget)->usedHeldItem; else - usedHeldItem = &gBattleStruct->usedHeldItems[gBattlerPartyIndexes[gBattlerAttacker]][GetBattlerSide(gBattlerAttacker)]; + usedHeldItem = &GetBattlerPartyState(gBattlerAttacker)->usedHeldItem; if (*usedHeldItem != ITEM_NONE && gBattleMons[gBattlerAttacker].item == ITEM_NONE) { gLastUsedItem = *usedHeldItem; @@ -13843,6 +13948,8 @@ static void Cmd_givecaughtmon(void) } else { + //Before sending to PC, we revert battle form + TryRevertPartyMonFormChange(gSelectedMonPartyId); // Mon chosen, try to put it in the PC if (CopyMonToPC(&gPlayerParty[gSelectedMonPartyId]) == MON_GIVEN_TO_PC) { @@ -14136,12 +14243,8 @@ static void Cmd_trygivecaughtmonnick(void) } } -static void Cmd_subattackerhpbydmg(void) +static void Cmd_unused_0xf4(void) { - CMD_ARGS(); - - gBattleMons[gBattlerAttacker].hp -= gBattleStruct->moveDamage[gBattlerTarget]; - gBattlescriptCurrInstr = cmd->nextInstr; } static void Cmd_removeattackerstatus1(void) @@ -14213,7 +14316,7 @@ static void Cmd_settelekinesis(void) else { gBattleMons[gBattlerTarget].volatiles.telekinesis = TRUE; - gDisableStructs[gBattlerTarget].telekinesisTimer = gBattleTurnCounter + 3; + gDisableStructs[gBattlerTarget].telekinesisTimer = 3; gBattlescriptCurrInstr = cmd->nextInstr; } } @@ -14232,7 +14335,7 @@ static void Cmd_swapstatstages(void) gBattlescriptCurrInstr = cmd->nextInstr; } -static u16 *GetBattlerStat(struct BattlePokemon *battler, u32 stat) +static u16 *GetBattlerStat(struct BattlePokemon *battler, enum Stat stat) { switch (stat) { @@ -14279,31 +14382,30 @@ static void Cmd_jumpifcaptivateaffected(void) static void Cmd_setnonvolatilestatus(void) { CMD_ARGS(u8 trigger); - gBattlescriptCurrInstr = cmd->nextInstr - 1; switch (cmd->trigger) { case TRIGGER_ON_ABILITY: if (gBattleScripting.moveEffect >= MOVE_EFFECT_CONFUSION) - SetMoveEffect(gBattleScripting.battler, gEffectBattler, FALSE, FALSE); + SetMoveEffect(gBattleScripting.battler, gEffectBattler, gBattleScripting.moveEffect, cmd->nextInstr, EFFECT_PRIMARY); else - SetNonVolatileStatus(gEffectBattler, gBattleScripting.moveEffect, TRIGGER_ON_ABILITY); + SetNonVolatileStatus(gEffectBattler, gBattleScripting.moveEffect, cmd->nextInstr, TRIGGER_ON_ABILITY); break; case TRIGGER_ON_MOVE: - SetNonVolatileStatus(gBattlerTarget, GetMoveNonVolatileStatus(gCurrentMove), TRIGGER_ON_MOVE); + SetNonVolatileStatus(gBattlerTarget, GetMoveNonVolatileStatus(gCurrentMove), cmd->nextInstr, TRIGGER_ON_MOVE); break; case TRIGGER_ON_PROTECT: - SetNonVolatileStatus(gBattlerAttacker, gBattleScripting.moveEffect, TRIGGER_ON_PROTECT); + SetNonVolatileStatus(gBattlerAttacker, gBattleScripting.moveEffect, cmd->nextInstr, TRIGGER_ON_PROTECT); break; } } -static void Cmd_tryworryseed(void) +static void Cmd_tryoverwriteability(void) { CMD_ARGS(const u8 *failInstr); if (gAbilitiesInfo[gBattleMons[gBattlerTarget].ability].cantBeOverwritten - || gBattleMons[gBattlerTarget].ability == ABILITY_INSOMNIA) + || gBattleMons[gBattlerTarget].ability == GetMoveOverwriteAbility(gCurrentMove)) { RecordAbilityBattle(gBattlerTarget, gBattleMons[gBattlerTarget].ability); gBattlescriptCurrInstr = cmd->failInstr; @@ -14320,7 +14422,7 @@ static void Cmd_tryworryseed(void) RemoveAbilityFlags(gBattlerTarget); gBattleScripting.abilityPopupOverwrite = gBattleMons[gBattlerTarget].ability; - gBattleMons[gBattlerTarget].ability = gDisableStructs[gBattlerTarget].overwrittenAbility = ABILITY_INSOMNIA; + gBattleMons[gBattlerTarget].ability = gDisableStructs[gBattlerTarget].overwrittenAbility = GetMoveOverwriteAbility(gCurrentMove); gBattlescriptCurrInstr = cmd->nextInstr; } } @@ -14549,16 +14651,19 @@ bool32 IsMoveAffectedByParentalBond(u32 move, u32 battler) return FALSE; } -static bool8 IsFinalStrikeEffect(enum BattleMoveEffects moveEffect) +static bool32 IsFinalStrikeEffect(enum MoveEffect moveEffect) { - u32 i; - - for (i = 0; i < ARRAY_COUNT(sFinalStrikeOnlyEffects); i++) + switch (moveEffect) { - if (moveEffect == sFinalStrikeOnlyEffects[i]) - return TRUE; + case MOVE_EFFECT_REMOVE_ARG_TYPE: + case MOVE_EFFECT_REMOVE_STATUS: + case MOVE_EFFECT_RECOIL_HP_25: + case MOVE_EFFECT_PREVENT_ESCAPE: + case MOVE_EFFECT_WRAP: + return TRUE; + default: + return FALSE; } - return FALSE; } static bool32 CanAbilityPreventStatLoss(enum Ability abilityDef) @@ -14731,7 +14836,7 @@ u8 GetFirstFaintedPartyIndex(u8 battler) void ApplyExperienceMultipliers(s32 *expAmount, u8 expGetterMonId, u8 faintedBattler) { - enum ItemHoldEffect holdEffect = GetMonHoldEffect(&gPlayerParty[expGetterMonId]); + enum HoldEffect holdEffect = GetMonHoldEffect(&gPlayerParty[expGetterMonId]); if (IsTradedMon(&gPlayerParty[expGetterMonId])) *expAmount = (*expAmount * 150) / 100; @@ -14811,7 +14916,7 @@ void BS_ItemRestoreHP(void) // Heal is applied as move damage if battler is active. if (battler != MAX_BATTLERS_COUNT && hp != 0) { - gBattleStruct->moveDamage[battler] = -healAmount; + gBattleStruct->passiveHpUpdate[battler] = -healAmount; gBattlescriptCurrInstr = cmd->restoreBattlerInstr; } else @@ -15000,34 +15105,49 @@ void BS_SetTerrain(void) switch (GetMoveEffect(gCurrentMove)) { case EFFECT_MISTY_TERRAIN: - statusFlag = STATUS_FIELD_MISTY_TERRAIN; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_MISTY; + if (!(gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)) + { + statusFlag = STATUS_FIELD_MISTY_TERRAIN; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_MISTY; + } break; case EFFECT_GRASSY_TERRAIN: - statusFlag = STATUS_FIELD_GRASSY_TERRAIN; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_GRASSY; + if (!(gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN)) + { + statusFlag = STATUS_FIELD_GRASSY_TERRAIN; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_GRASSY; + } break; case EFFECT_ELECTRIC_TERRAIN: - statusFlag = STATUS_FIELD_ELECTRIC_TERRAIN; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_ELECTRIC; + if (!(gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN)) + { + statusFlag = STATUS_FIELD_ELECTRIC_TERRAIN; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_ELECTRIC; + } break; case EFFECT_PSYCHIC_TERRAIN: - statusFlag = STATUS_FIELD_PSYCHIC_TERRAIN; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_PSYCHIC; - break; - case EFFECT_HIT_SET_TERRAIN: - statusFlag = GetMoveTerrainFlag(gCurrentMove); - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_PSYCHIC; + if (!(gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN)) + { + statusFlag = STATUS_FIELD_PSYCHIC_TERRAIN; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_PSYCHIC; + } break; default: break; } - enum ItemHoldEffect atkHoldEffect = GetBattlerHoldEffect(gBattlerAttacker); - - gFieldStatuses &= ~STATUS_FIELD_TERRAIN_ANY; - gFieldStatuses |= statusFlag; - gFieldTimers.terrainTimer = gBattleTurnCounter + (atkHoldEffect == HOLD_EFFECT_TERRAIN_EXTENDER) ? 8 : 5; - gBattlescriptCurrInstr = cmd->nextInstr; + if (gBattleStruct->isSkyBattle) + { + gBattlescriptCurrInstr = cmd->jumpInstr; + } + else if (statusFlag) + { + TryChangeBattleTerrain(gBattlerAttacker, statusFlag); + gBattlescriptCurrInstr = cmd->nextInstr; + } + else + { + gBattlescriptCurrInstr = cmd->jumpInstr; + } } void BS_JumpIfTerrainAffected(void) @@ -15045,7 +15165,7 @@ void BS_TryReflectType(void) { NATIVE_ARGS(const u8 *failInstr); u16 targetBaseSpecies = GET_BASE_SPECIES_ID(gBattleMons[gBattlerTarget].species); - u32 targetTypes[3]; + enum Type targetTypes[3]; GetBattlerTypes(gBattlerTarget, FALSE, targetTypes); if (targetBaseSpecies == SPECIES_ARCEUS || targetBaseSpecies == SPECIES_SILVALLY) @@ -15203,13 +15323,13 @@ void BS_SetPledgeStatus(void) switch (cmd->sideStatus) { case SIDE_STATUS_RAINBOW: - gSideTimers[side].rainbowTimer = gBattleTurnCounter + 4; + gSideTimers[side].rainbowTimer = 4; break; case SIDE_STATUS_SEA_OF_FIRE: - gSideTimers[side].seaOfFireTimer = gBattleTurnCounter + 4; + gSideTimers[side].seaOfFireTimer = 4; break; case SIDE_STATUS_SWAMP: - gSideTimers[side].swampTimer = gBattleTurnCounter + 4; + gSideTimers[side].swampTimer = 4; } gBattlescriptCurrInstr = cmd->nextInstr; @@ -15272,15 +15392,15 @@ void BS_TryHealPulse(void) } else { + s32 healAmount = 0; if (GetBattlerAbility(gBattlerAttacker) == ABILITY_MEGA_LAUNCHER && IsPulseMove(gCurrentMove)) - gBattleStruct->moveDamage[gBattlerTarget] = -(GetNonDynamaxMaxHP(gBattlerTarget) * 75 / 100); + healAmount = GetNonDynamaxMaxHP(gBattlerTarget) * 75 / 100; else if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN && GetMoveEffectArg_MoveProperty(gCurrentMove) == MOVE_EFFECT_FLORAL_HEALING) - gBattleStruct->moveDamage[gBattlerTarget] = -(GetNonDynamaxMaxHP(gBattlerTarget) * 2 / 3); + healAmount = GetNonDynamaxMaxHP(gBattlerTarget) * 2 / 3; else - gBattleStruct->moveDamage[gBattlerTarget] = -(GetNonDynamaxMaxHP(gBattlerTarget) / 2); + healAmount = GetNonDynamaxMaxHP(gBattlerTarget) / 2; - if (gBattleStruct->moveDamage[gBattlerTarget] == 0) - gBattleStruct->moveDamage[gBattlerTarget] = -1; + SetHealAmount(gBattlerTarget, healAmount); gBattlescriptCurrInstr = cmd->nextInstr; } } @@ -15349,9 +15469,7 @@ void BS_TryAllySwitch(void) { NATIVE_ARGS(const u8 *failInstr); - if (!IsBattlerAlive(BATTLE_PARTNER(gBattlerAttacker)) - || (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER && gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) - || (GetBattlerSide(gBattlerAttacker) == B_SIDE_OPPONENT && gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)) + if (!IsBattlerAlive(BATTLE_PARTNER(gBattlerAttacker)) || HasPartnerTrainer(gBattlerAttacker)) { gBattlescriptCurrInstr = cmd->failInstr; } @@ -15430,20 +15548,6 @@ static void TryUpdateEvolutionTracker(u32 evolutionCondition, u32 upAmount, u16 } } -void BS_TryUpdateRecoilTracker(void) -{ - NATIVE_ARGS(); - TryUpdateEvolutionTracker(IF_RECOIL_DAMAGE_GE, gBattleStruct->moveDamage[gBattlerAttacker], MOVE_NONE); - gBattlescriptCurrInstr = cmd->nextInstr; -} - -void BS_TryUpdateLeadersCrestTracker(void) -{ - NATIVE_ARGS(); - TryUpdateEvolutionTracker(IF_DEFEAT_X_WITH_ITEMS, 1, MOVE_NONE); - gBattlescriptCurrInstr = cmd->nextInstr; -} - void BS_TryTidyUp(void) { NATIVE_ARGS(u8 clear, const u8 *jumpInstr); @@ -15492,12 +15596,8 @@ void BS_TryActivateGulpMissile(void) && gBattleMons[gBattlerTarget].species != SPECIES_CRAMORANT && GetBattlerAbility(gBattlerTarget) == ABILITY_GULP_MISSILE) { - if (GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD) - { - gBattleStruct->moveDamage[gBattlerTarget] = GetNonDynamaxMaxHP(gBattlerAttacker) / 4; - if (gBattleStruct->moveDamage[gBattlerTarget] == 0) - gBattleStruct->moveDamage[gBattlerTarget] = 1; - } + if (!IsAbilityAndRecord(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), ABILITY_MAGIC_GUARD)) + SetPassiveDamageAmount(gBattlerTarget, GetNonDynamaxMaxHP(gBattlerAttacker) / 4); switch(gBattleMons[gBattlerTarget].species) { @@ -15529,13 +15629,22 @@ void BS_TryQuash(void) // If the above condition is not true, it means we are faster than the foe, so we can set the quash bit gProtectStructs[gBattlerTarget].quash = TRUE; + struct BattleContext ctx = {0}; + for (i = 0; i < gBattlersCount; i++) + { + ctx.abilities[i] = GetBattlerAbility(i); + ctx.holdEffects[i] = GetBattlerHoldEffect(i); + } // this implementation assumes turn order is correct when using Quash i = GetBattlerTurnOrderNum(gBattlerTarget); for (j = i + 1; j < gBattlersCount; j++) { + ctx.battlerAtk = gBattlerByTurnOrder[i]; + ctx.battlerDef = gBattlerByTurnOrder[j]; + // Gen 7- config makes target go last so that the order of quash targets is kept for the correct turn order // Gen 8+ config alters Turn Order of the target according to speed, dynamic speed should handle the rest - if (B_QUASH_TURN_ORDER < GEN_8 || GetWhichBattlerFaster(gBattlerByTurnOrder[i], gBattlerByTurnOrder[j], FALSE) == -1) + if (B_QUASH_TURN_ORDER < GEN_8 || GetWhichBattlerFaster(&ctx, FALSE) == -1) SwapTurnOrder(i, j); else break; @@ -15571,7 +15680,6 @@ void BS_CopyFoesStatIncrease(void) SET_STATCHANGER(stat + 1, gQueuedStatBoosts[battler].statChanges[stat], FALSE); gQueuedStatBoosts[battler].stats &= ~(1 << stat); - gBattlerTarget = battler; gBattlescriptCurrInstr = cmd->nextInstr; return; } @@ -15646,7 +15754,7 @@ void BS_CanTarShotWork(void) NATIVE_ARGS(const u8 *failInstr); // Tar Shot will fail if it's already been used on the target or if its speed can't be lowered further if (!gDisableStructs[gBattlerTarget].tarShot - && CompareStat(gBattlerTarget, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN)) + && CompareStat(gBattlerTarget, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(gBattlerTarget))) gBattlescriptCurrInstr = cmd->nextInstr; else gBattlescriptCurrInstr = cmd->failInstr; @@ -15909,7 +16017,7 @@ void BS_TrySpectralThiefSteal(void) bool32 contrary = GetBattlerAbility(gBattlerAttacker) == ABILITY_CONTRARY; gBattleStruct->stolenStats[0] = 0; // Stats to steal. gBattleScripting.animArg1 = 0; - for (u32 stat = STAT_ATK; stat < NUM_BATTLE_STATS; stat++) + for (enum Stat stat = STAT_ATK; stat < NUM_BATTLE_STATS; stat++) { if (gBattleMons[gBattlerTarget].statStages[stat] > DEFAULT_STAT_STAGE && gBattleMons[gBattlerAttacker].statStages[stat] != MAX_STAT_STAGE) { @@ -15954,7 +16062,7 @@ void BS_SpectralThiefPrintStats(void) { NATIVE_ARGS(); - for (u32 stat = STAT_ATK; stat < NUM_BATTLE_STATS; stat++) + for (enum Stat stat = STAT_ATK; stat < NUM_BATTLE_STATS; stat++) { if (gBattleStruct->stolenStats[0] & (1u << stat)) { @@ -15989,6 +16097,13 @@ void BS_ClearMoveResultFlags(void) gBattlescriptCurrInstr = cmd->nextInstr; } +void BS_ClearSpecialStatuses(void) +{ + NATIVE_ARGS(); + memset(&gSpecialStatuses, 0, sizeof(gSpecialStatuses)); + gBattlescriptCurrInstr = cmd->nextInstr; +} + void BS_JumpIfMoveResultFlags(void) { NATIVE_ARGS(u16 value, const u8 *jumpInstr); @@ -16013,7 +16128,7 @@ void BS_SwapStats(void) { NATIVE_ARGS(u8 stat); - u32 stat = cmd->stat; + enum Stat stat = cmd->stat; u32 temp; switch (stat) @@ -16036,6 +16151,8 @@ void BS_SwapStats(void) case STAT_SPDEF: SWAP(gBattleMons[gBattlerAttacker].spDefense, gBattleMons[gBattlerTarget].spDefense, temp); break; + default: + break; } PREPARE_STAT_BUFFER(gBattleTextBuff1, stat); gBattlescriptCurrInstr = cmd->nextInstr; @@ -16044,40 +16161,25 @@ void BS_SwapStats(void) static void TrySetParalysis(const u8 *nextInstr, const u8 *failInstr) { if (CanBeParalyzed(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerTarget))) - { - gBattlescriptCurrInstr = nextInstr - 1; - SetNonVolatileStatus(gBattlerTarget, MOVE_EFFECT_PARALYSIS, TRIGGER_ON_MOVE); - } + SetNonVolatileStatus(gBattlerTarget, MOVE_EFFECT_PARALYSIS, nextInstr, TRIGGER_ON_MOVE); else - { gBattlescriptCurrInstr = failInstr; - } } static void TrySetPoison(const u8 *nextInstr, const u8 *failInstr) { if (CanBePoisoned(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerAbility(gBattlerTarget))) - { - gBattlescriptCurrInstr = nextInstr - 1; - SetNonVolatileStatus(gBattlerTarget, MOVE_EFFECT_POISON, TRIGGER_ON_MOVE); - } + SetNonVolatileStatus(gBattlerTarget, MOVE_EFFECT_POISON, nextInstr, TRIGGER_ON_MOVE); else - { gBattlescriptCurrInstr = failInstr; - } } static void TrySetSleep(const u8 *nextInstr, const u8 *failInstr) { if (CanBeSlept(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerTarget), BLOCKED_BY_SLEEP_CLAUSE)) - { - gBattlescriptCurrInstr = nextInstr - 1; - SetNonVolatileStatus(gBattlerTarget, MOVE_EFFECT_SLEEP, TRIGGER_ON_MOVE); - } + SetNonVolatileStatus(gBattlerTarget, MOVE_EFFECT_SLEEP, nextInstr, TRIGGER_ON_MOVE); else - { gBattlescriptCurrInstr = failInstr; - } } void BS_TrySetParalysis(void) @@ -16182,7 +16284,7 @@ void BS_TrySetTorment(void) && !IsAbilityOnSide(gBattlerTarget, ABILITY_AROMA_VEIL)) { gBattleMons[gBattlerTarget].volatiles.torment = TRUE; - gDisableStructs[gBattlerTarget].tormentTimer = gBattleTurnCounter + 3; // 3 turns excluding current turn + gDisableStructs[gBattlerTarget].tormentTimer = 3; gEffectBattler = gBattlerTarget; gBattlescriptCurrInstr = cmd->nextInstr; } @@ -16196,11 +16298,7 @@ void BS_TrySetTorment(void) void BS_HealOneSixth(void) { NATIVE_ARGS(const u8* failInstr); - gBattleStruct->moveDamage[gBattlerTarget] = gBattleMons[gBattlerTarget].maxHP / 6; - if (gBattleStruct->moveDamage[gBattlerTarget] == 0) - gBattleStruct->moveDamage[gBattlerTarget] = 1; - gBattleStruct->moveDamage[gBattlerTarget] *= -1; - + SetHealAmount(gBattlerTarget, gBattleMons[gBattlerTarget].maxHP / 6); if (gBattleMons[gBattlerTarget].hp == gBattleMons[gBattlerTarget].maxHP) gBattlescriptCurrInstr = cmd->failInstr; // fail else @@ -16211,7 +16309,7 @@ void BS_HealOneSixth(void) void BS_TryRecycleBerry(void) { NATIVE_ARGS(const u8 *failInstr); - u16* usedHeldItem = &gBattleStruct->usedHeldItems[gBattlerPartyIndexes[gBattlerTarget]][GetBattlerSide(gBattlerTarget)]; + u16 *usedHeldItem = &GetBattlerPartyState(gBattlerTarget)->usedHeldItem; if (gBattleMons[gBattlerTarget].item == ITEM_NONE && gBattleStruct->changedItems[gBattlerTarget] == ITEM_NONE // Will not inherit an item && GetItemPocket(*usedHeldItem) == POCKET_BERRIES) @@ -16251,7 +16349,7 @@ void BS_JumpIfIntimidateAbilityPrevented(void) { NATIVE_ARGS(); - u32 hasAbility = FALSE; + bool32 hasAbility = FALSE; enum Ability ability = GetBattlerAbility(gBattlerTarget); switch (ability) @@ -16299,14 +16397,54 @@ void BS_JumpIfCanGigantamax(void) gBattlescriptCurrInstr = cmd->nextInstr; } -void BS_JumpIfLastUsedItemHoldEffect(void) +void BS_TryFlingHoldEffect(void) { - NATIVE_ARGS(u8 holdEffect, u16 secondaryId, const u8 *jumpInstr); - if (GetItemHoldEffect(gLastUsedItem) == cmd->holdEffect - && (cmd->secondaryId == 0 || GetItemSecondaryId(gLastUsedItem) == cmd->secondaryId)) - gBattlescriptCurrInstr = cmd->jumpInstr; - else + NATIVE_ARGS(); + enum HoldEffect holdEffect = GetItemHoldEffect(gBattleStruct->flingItem); + gBattleStruct->flingItem = ITEM_NONE; + + if (IsMoveEffectBlockedByTarget(GetBattlerAbility(gBattlerTarget))) + { + gBattlescriptCurrInstr = BattleScript_FlingBlockedByShieldDust; + return; + } + + switch (holdEffect) + { + case HOLD_EFFECT_FLAME_ORB: + SetMoveEffect(gBattlerAttacker, gBattlerTarget, MOVE_EFFECT_BURN, cmd->nextInstr, NO_FLAGS); + break; + case HOLD_EFFECT_TOXIC_ORB: + SetMoveEffect(gBattlerAttacker, gBattlerTarget, MOVE_EFFECT_TOXIC, cmd->nextInstr, NO_FLAGS); + break; + case HOLD_EFFECT_LIGHT_BALL: + SetMoveEffect(gBattlerAttacker, gBattlerTarget, MOVE_EFFECT_PARALYSIS, cmd->nextInstr, NO_FLAGS); + break; + case HOLD_EFFECT_TYPE_POWER: + if (GetItemSecondaryId(gLastUsedItem) != TYPE_POISON) + gBattlescriptCurrInstr = cmd->nextInstr; + else + SetMoveEffect(gBattlerAttacker, gBattlerTarget, MOVE_EFFECT_POISON, cmd->nextInstr, NO_FLAGS); + break; + case HOLD_EFFECT_FLINCH: + SetMoveEffect(gBattlerAttacker, gBattlerTarget, MOVE_EFFECT_FLINCH, cmd->nextInstr, NO_FLAGS); + break; + case HOLD_EFFECT_MENTAL_HERB: + if (ItemBattleEffects(gBattlerTarget, 0, holdEffect, IsOnFlingActivation)) + return; + else + gBattlescriptCurrInstr = cmd->nextInstr; + break; + case HOLD_EFFECT_WHITE_HERB: + if (ItemBattleEffects(gBattlerTarget, 0, holdEffect, IsOnFlingActivation)) + return; + else + gBattlescriptCurrInstr = cmd->nextInstr; + break; + default: gBattlescriptCurrInstr = cmd->nextInstr; + break; + } } void BS_JumpIfNoWhiteOut(void) @@ -16325,16 +16463,17 @@ void BS_TryBoosterEnergy(void) for (u32 orderNum = 0; orderNum < gBattlersCount; orderNum++) { - u32 battlerByTurnOrder = gBattlerByTurnOrder[orderNum]; - if (GetBattlerHoldEffect(battlerByTurnOrder) != HOLD_EFFECT_BOOSTER_ENERGY) + u32 battler = gBattlerByTurnOrder[orderNum]; + enum HoldEffect holdEffect = GetBattlerHoldEffect(battler); + if (holdEffect != HOLD_EFFECT_BOOSTER_ENERGY) continue; - enum Ability ability = GetBattlerAbility(battlerByTurnOrder); + enum Ability ability = GetBattlerAbility(battler); if (!(ability == ABILITY_PROTOSYNTHESIS && cmd->onFieldStatus != ON_TERRAIN) && !(ability == ABILITY_QUARK_DRIVE && cmd->onFieldStatus != ON_WEATHER)) continue; - if (TryBoosterEnergy(battlerByTurnOrder, ability, ITEMEFFECT_NONE)) + if (ItemBattleEffects(battler, 0, holdEffect, IsOnEffectActivation)) return; } @@ -16461,19 +16600,11 @@ void BS_JumpIfNoAlly(void) gBattlescriptCurrInstr = cmd->nextInstr; } -void BS_InfatuateWithBattler(void) -{ - NATIVE_ARGS(u8 battler, u8 infatuateWith); - u32 battler = GetBattlerForBattleScript(cmd->battler); - gBattleScripting.battler = battler; - gBattleMons[battler].volatiles.infatuation = INFATUATED_WITH(GetBattlerForBattleScript(cmd->infatuateWith)); - gBattlescriptCurrInstr = cmd->nextInstr; -} - void BS_SetLastUsedItem(void) { NATIVE_ARGS(u8 battler); gLastUsedItem = gBattleMons[GetBattlerForBattleScript(cmd->battler)].item; + gBattleStruct->flingItem = gLastUsedItem; gBattlescriptCurrInstr = cmd->nextInstr; } @@ -16487,7 +16618,7 @@ void BS_TrySetFairyLock(void) else { gFieldStatuses |= STATUS_FIELD_FAIRY_LOCK; - gFieldTimers.fairyLockTimer = gBattleTurnCounter + 2; + gFieldTimers.fairyLockTimer = 2; gBattlescriptCurrInstr = cmd->nextInstr; } } @@ -16496,9 +16627,9 @@ void BS_GetStatValue(void) { NATIVE_ARGS(u8 stat); u32 stat = cmd->stat; - gBattleStruct->moveDamage[gBattlerAttacker] = *(u16 *)(&gBattleMons[gBattlerTarget].attack) + (stat - 1); - gBattleStruct->moveDamage[gBattlerAttacker] *= gStatStageRatios[gBattleMons[gBattlerTarget].statStages[stat]][0]; - gBattleStruct->moveDamage[gBattlerAttacker] /= gStatStageRatios[gBattleMons[gBattlerTarget].statStages[stat]][1]; + gBattleStruct->passiveHpUpdate[gBattlerAttacker] = *(u16 *)(&gBattleMons[gBattlerTarget].attack) + (stat - 1); + gBattleStruct->passiveHpUpdate[gBattlerAttacker] *= gStatStageRatios[gBattleMons[gBattlerTarget].statStages[stat]][0]; + gBattleStruct->passiveHpUpdate[gBattlerAttacker] /= gStatStageRatios[gBattleMons[gBattlerTarget].statStages[stat]][1]; gBattlescriptCurrInstr = cmd->nextInstr; } @@ -16598,9 +16729,9 @@ void BS_TryAcupressure(void) { NATIVE_ARGS(const u8 *failInstr); u32 bits = 0; - for (u32 stat = STAT_ATK; stat < NUM_BATTLE_STATS; stat++) + for (enum Stat stat = STAT_ATK; stat < NUM_BATTLE_STATS; stat++) { - if (CompareStat(gBattlerTarget, stat, MAX_STAT_STAGE, CMP_LESS_THAN)) + if (CompareStat(gBattlerTarget, stat, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(gBattlerTarget))) bits |= 1u << stat; } if (bits) @@ -16664,23 +16795,23 @@ void BS_ResetSwitchInAbilityBits(void) void BS_UpdateChoiceMoveOnLvlUp(void) { NATIVE_ARGS(); - // if (gBattlerPartyIndexes[0] == gBattleStruct->expGetterMonId || gBattlerPartyIndexes[2] == gBattleStruct->expGetterMonId) - // { - // u32 battler; - // if (gBattlerPartyIndexes[0] == gBattleStruct->expGetterMonId) - // battler = 0; - // else - // battler = 2; + if (gBattlerPartyIndexes[0] == gBattleStruct->expGetterMonId || gBattlerPartyIndexes[2] == gBattleStruct->expGetterMonId) + { + u32 battler; + if (gBattlerPartyIndexes[0] == gBattleStruct->expGetterMonId) + battler = 0; + else + battler = 2; - // u32 moveIndex; - // for (moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++) - // { - // if (gBattleMons[battler].moves[moveIndex] == gBattleStruct->choicedMove[battler]) - // break; - // } - // if (moveIndex == MAX_MON_MOVES) - // gBattleStruct->choicedMove[battler] = MOVE_NONE; - // } + u32 moveIndex; + for (moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++) + { + if (gBattleMons[battler].moves[moveIndex] == gBattleStruct->choicedMove[battler]) + break; + } + if (moveIndex == MAX_MON_MOVES) + gBattleStruct->choicedMove[battler] = MOVE_NONE; + } gBattlescriptCurrInstr = cmd->nextInstr; } @@ -16730,11 +16861,14 @@ void BS_ArenaJudgmentWindow(void) gBattlescriptCurrInstr = cmd->nextInstr; } -static void UNUSED SetArenMonLostValues(u32 battler) +static void SetArenMonLostValues(u32 battler, u32 side) { // gBattleMons[battler].hp = 0; // gHitMarker |= HITMARKER_FAINTED(battler); - // gBattleStruct->arenaLostOpponentMons |= 1u << gBattlerPartyIndexes[battler]; + // if (side == B_SIDE_PLAYER) + // gBattleStruct->arenaLostPlayerMons |= 1u << gBattlerPartyIndexes[battler]; + // else + // gBattleStruct->arenaLostOpponentMons |= 1u << gBattlerPartyIndexes[battler]; // gDisableStructs[battler].truantSwitchInHack = TRUE; } @@ -16743,22 +16877,22 @@ static void UNUSED SetArenMonLostValues(u32 battler) void BS_ArenaOpponentMonLost(void) { NATIVE_ARGS(); - // SetArenMonLostValues(opponentMon); + SetArenMonLostValues(opponentMon, B_SIDE_OPPONENT); gBattlescriptCurrInstr = cmd->nextInstr; } void BS_ArenaPlayerMonLost(void) { NATIVE_ARGS(); - // SetArenMonLostValues(playerMon); + SetArenMonLostValues(playerMon, B_SIDE_PLAYER); gBattlescriptCurrInstr = cmd->nextInstr; } void BS_ArenaBothMonsLost(void) { NATIVE_ARGS(); - // SetArenMonLostValues(playerMon); - // SetArenMonLostValues(opponentMon); + SetArenMonLostValues(playerMon, B_SIDE_PLAYER); + SetArenMonLostValues(opponentMon, B_SIDE_OPPONENT); gBattlescriptCurrInstr = cmd->nextInstr; } #undef playerMon @@ -16788,13 +16922,12 @@ void BS_EraseArenaRefTextBox(void) void BS_ArenaJudgmentString(void) { - CMD_ARGS(u8 id); + NATIVE_ARGS(u8 id); // BattleStringExpandPlaceholdersToDisplayedString(gRefereeStringsTable[cmd->id]); // BattlePutTextOnWindow(gDisplayedStringBattle, ARENA_WIN_JUDGMENT_TEXT); gBattlescriptCurrInstr = cmd->nextInstr; } -// Argument passed but no use void BS_ArenaWaitMessage(void) { NATIVE_ARGS(); @@ -16919,6 +17052,7 @@ void BS_SwitchinAbilities(void) AbilityBattleEffects(ABILITYEFFECT_NEUTRALIZINGGAS, battler, 0, 0, 0); AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, battler, 0, 0, 0); AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, battler, 0, 0, 0); + AbilityBattleEffects(ABILITYEFFECT_IMMUNITY, battler, 0, 0, 0); if (gBattleWeather & B_WEATHER_ANY && HasWeatherEffect()) AbilityBattleEffects(ABILITYEFFECT_ON_WEATHER, battler, 0, 0, 0); @@ -16976,7 +17110,7 @@ void BS_TryActivateReceiver(void) u32 partnerAbility = GetBattlerAbility(gBattlerAbility); if (IsBattlerAlive(gBattlerAbility) && (partnerAbility == ABILITY_RECEIVER || partnerAbility == ABILITY_POWER_OF_ALCHEMY) - && GetBattlerHoldEffect(battler) != HOLD_EFFECT_ABILITY_SHIELD + && GetBattlerHoldEffectIgnoreAbility(battler) != HOLD_EFFECT_ABILITY_SHIELD && !gAbilitiesInfo[gBattleMons[battler].ability].cantBeCopied) { gBattleStruct->tracedAbility[gBattlerAbility] = gBattleMons[battler].ability; // re-using the variable for trace @@ -16996,10 +17130,11 @@ void BS_TryActivateSoulheart(void) while (gBattleStruct->soulheartBattlerId < gBattlersCount) { gBattleScripting.battler = gBattleStruct->soulheartBattlerId++; - if (GetBattlerAbility(gBattleScripting.battler) == ABILITY_SOUL_HEART + u32 ability = GetBattlerAbility(gBattleScripting.battler); + if (ability == ABILITY_SOUL_HEART && IsBattlerAlive(gBattleScripting.battler) && !NoAliveMonsForEitherParty() - && CompareStat(gBattleScripting.battler, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN)) + && CompareStat(gBattleScripting.battler, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN, ability)) { SET_STATCHANGER(STAT_SPATK, 1, FALSE); PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_SPATK); @@ -17035,7 +17170,7 @@ void BS_SetLuckyChant(void) if (!(gSideStatuses[side] & SIDE_STATUS_LUCKY_CHANT)) { gSideStatuses[side] |= SIDE_STATUS_LUCKY_CHANT; - gSideTimers[side].luckyChantTimer = gBattleTurnCounter + 5; + gSideTimers[side].luckyChantTimer = 5; gBattlescriptCurrInstr = cmd->nextInstr; } else @@ -17044,32 +17179,6 @@ void BS_SetLuckyChant(void) } } -void BS_SetSimpleBeam(void) -{ - NATIVE_ARGS(const u8 *failInstr); - if (gAbilitiesInfo[gBattleMons[gBattlerTarget].ability].cantBeOverwritten - || gBattleMons[gBattlerTarget].ability == ABILITY_SIMPLE) - { - RecordAbilityBattle(gBattlerTarget, gBattleMons[gBattlerTarget].ability); - gBattlescriptCurrInstr = cmd->failInstr; - } - else if (CanAbilityShieldActivateForBattler(gBattlerTarget)) - { - gBattlescriptCurrInstr = BattleScript_MoveEnd; - BattleScriptCall(BattleScript_AbilityShieldProtects); - } - else - { - if (gBattleMons[gBattlerTarget].ability == ABILITY_NEUTRALIZING_GAS) - gSpecialStatuses[gBattlerTarget].neutralizingGasRemoved = TRUE; - - RemoveAbilityFlags(gBattlerTarget); - gBattleScripting.abilityPopupOverwrite = gBattleMons[gBattlerTarget].ability; - gBattleMons[gBattlerTarget].ability = gDisableStructs[gBattlerTarget].overwrittenAbility = ABILITY_SIMPLE; - gBattlescriptCurrInstr = cmd->nextInstr; - } -} - void BS_TryEntrainment(void) { NATIVE_ARGS(const u8 *failInstr); @@ -17137,9 +17246,9 @@ void BS_TryElectrify(void) void BS_TrySoak(void) { NATIVE_ARGS(const u8 *failInstr); - u32 types[3]; + enum Type types[3]; GetBattlerTypes(gBattlerTarget, FALSE, types); - u32 typeToSet = GetMoveArgType(gCurrentMove); + enum Type typeToSet = GetMoveArgType(gCurrentMove); if ((types[0] == typeToSet && types[1] == typeToSet) || GetActiveGimmick(gBattlerTarget) == GIMMICK_TERA) { @@ -17433,9 +17542,9 @@ void BS_SetAuroraVeil(void) { gSideStatuses[side] |= SIDE_STATUS_AURORA_VEIL; if (GetBattlerHoldEffect(gBattlerAttacker) == HOLD_EFFECT_LIGHT_CLAY) - gSideTimers[GetBattlerSide(gBattlerAttacker)].auroraVeilTimer = gBattleTurnCounter + 8; + gSideTimers[GetBattlerSide(gBattlerAttacker)].auroraVeilTimer = 8; else - gSideTimers[GetBattlerSide(gBattlerAttacker)].auroraVeilTimer = gBattleTurnCounter + 5; + gSideTimers[GetBattlerSide(gBattlerAttacker)].auroraVeilTimer = 5; if (IsDoubleBattle() && CountAliveMonsInBattle(BATTLE_ALIVE_SIDE, gBattlerAttacker) == 2) gBattleCommunication[MULTISTRING_CHOOSER] = 5; @@ -17510,8 +17619,14 @@ void BS_GetTotemBoost(void) void BS_ActivateItemEffects(void) { NATIVE_ARGS(); - if (ItemBattleEffects(ITEMEFFECT_TRY_HEALING, gBattlerTarget)) - return; + for (u32 battler = 0; battler < gBattlersCount; battler++) + { + if (!IsBattlerAlive(battler)) + continue; + + if (ItemBattleEffects(battler, 0, GetBattlerHoldEffect(battler), IsForceTriggerItemActivation)) + return; + } gBattlescriptCurrInstr = cmd->nextInstr; } @@ -17519,43 +17634,19 @@ void BS_TryRoomService(void) { NATIVE_ARGS(u8 battler, const u8 *failInstr); u32 battler = GetBattlerForBattleScript(cmd->battler); - if (GetBattlerHoldEffect(battler) == HOLD_EFFECT_ROOM_SERVICE && TryRoomService(battler)) - { - BattleScriptCall(BattleScript_ConsumableStatRaiseRet); - } - else - { - gBattlescriptCurrInstr = cmd->failInstr; - } + enum HoldEffect holdEffect = GetBattlerHoldEffect(battler); + if (holdEffect == HOLD_EFFECT_ROOM_SERVICE && ItemBattleEffects(battler, 0, holdEffect, IsOnEffectActivation)) + return; + gBattlescriptCurrInstr = cmd->failInstr; } void BS_TryTerrainSeed(void) { NATIVE_ARGS(u8 battler, const u8 *failInstr); u32 battler = GetBattlerForBattleScript(cmd->battler); - if (GetBattlerHoldEffect(battler) == HOLD_EFFECT_SEEDS) - { - enum ItemEffect effect = ITEM_NO_EFFECT; - u16 item = gBattleMons[battler].item; - switch (GetBattlerHoldEffectParam(battler)) - { - case HOLD_EFFECT_PARAM_ELECTRIC_TERRAIN: - effect = TryHandleSeed(battler, STATUS_FIELD_ELECTRIC_TERRAIN, STAT_DEF, item, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_PARAM_GRASSY_TERRAIN: - effect = TryHandleSeed(battler, STATUS_FIELD_GRASSY_TERRAIN, STAT_DEF, item, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_PARAM_MISTY_TERRAIN: - effect = TryHandleSeed(battler, STATUS_FIELD_MISTY_TERRAIN, STAT_SPDEF, item, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_PARAM_PSYCHIC_TERRAIN: - effect = TryHandleSeed(battler, STATUS_FIELD_PSYCHIC_TERRAIN, STAT_SPDEF, item, ITEMEFFECT_NONE); - break; - } - - if (effect != ITEM_NO_EFFECT) - return; - } + enum HoldEffect holdEffect = GetBattlerHoldEffect(battler); + if (holdEffect == HOLD_EFFECT_TERRAIN_SEED && ItemBattleEffects(battler, 0, holdEffect, IsOnEffectActivation)) + return; gBattlescriptCurrInstr = cmd->failInstr; } @@ -17598,11 +17689,7 @@ void BS_TryHealQuarterHealth(void) { NATIVE_ARGS(u8 battler, const u8 *failInstr); u32 battler = GetBattlerForBattleScript(cmd->battler); - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 4; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; - gBattleStruct->moveDamage[battler] *= -1; - + SetHealAmount(battler, GetNonDynamaxMaxHP(battler) / 4); if (gBattleMons[battler].hp == gBattleMons[battler].maxHP) gBattlescriptCurrInstr = cmd->failInstr; // fail else @@ -17789,23 +17876,29 @@ void BS_JumpIfNotRototillerAffected(void) } } +// TODO: There might be a way to do it without a flag void BS_ConsumeBerry(void) { NATIVE_ARGS(u8 battler, bool8 fromBattler); u32 battler = GetBattlerForBattleScript(cmd->battler); - if (gBattleScripting.overrideBerryRequirements == 2) - { - gBattlescriptCurrInstr = cmd->nextInstr; - return; - } if (cmd->fromBattler) gLastUsedItem = gBattleMons[battler].item; - GetBattlerPartyState(battler)->ateBerry = TRUE; - gBattleScripting.battler = gEffectBattler = gBattlerTarget = battler; // Cover all berry effect battler cases. e.g. ChangeStatBuffs uses target ID - if (ItemBattleEffects(ITEMEFFECT_USE_LAST_ITEM, battler)) + if (GetItemPocket(gLastUsedItem) != POCKET_BERRIES || gBattleScripting.overrideBerryRequirements == 2) + { + gBattleScripting.overrideBerryRequirements = 0; + gBattlescriptCurrInstr = cmd->nextInstr; return; + } + + gBattleScripting.overrideBerryRequirements = 1; + GetBattlerPartyState(battler)->ateBerry = TRUE; + if (ItemBattleEffects(battler, 0, GetItemHoldEffect(gLastUsedItem), IsOnBerryActivation)) + { + gBattleScripting.overrideBerryRequirements = 2; + return; + } gBattlescriptCurrInstr = cmd->nextInstr; } @@ -17828,19 +17921,17 @@ void BS_JumpIfSpecies(void) gBattlescriptCurrInstr = cmd->nextInstr; } -void BS_JumpIfLeafGuardProtected(void) +void BS_JumpIfAbilityPreventsRest(void) { NATIVE_ARGS(u8 battler, const u8 *jumpInstr); u32 battler = GetBattlerForBattleScript(cmd->battler); - if (IsLeafGuardProtected(battler, GetBattlerAbility(battler))) - { - gBattlerAbility = battler; + u32 ability = GetBattlerAbility(battler); + if (B_LEAF_GUARD_PREVENTS_REST >= GEN_5 && IsLeafGuardProtected(battler, ability)) + gBattlescriptCurrInstr = cmd->jumpInstr; + else if (IsShieldsDownProtected(battler, ability)) gBattlescriptCurrInstr = cmd->jumpInstr; - } else - { gBattlescriptCurrInstr = cmd->nextInstr; - } } void BS_SetAttackerToStickyWebUser(void) @@ -17858,11 +17949,12 @@ void BS_SetAttackerToStickyWebUser(void) void BS_CutOneThirdHpAndRaiseStats(void) { NATIVE_ARGS(const u8 *failInstr); - bool32 atLeastOneStatBoosted = FALSE; + u32 ability = GetBattlerAbility(gBattlerAttacker); + for (u32 stat = 1; stat < NUM_STATS; stat++) { - if (CompareStat(gBattlerAttacker, stat, MAX_STAT_STAGE, CMP_LESS_THAN)) + if (CompareStat(gBattlerAttacker, stat, MAX_STAT_STAGE, CMP_LESS_THAN, ability)) { atLeastOneStatBoosted = TRUE; break; @@ -17870,7 +17962,7 @@ void BS_CutOneThirdHpAndRaiseStats(void) } if (atLeastOneStatBoosted) { - gBattleStruct->moveDamage[gBattlerAttacker] = max(1, GetNonDynamaxMaxHP(gBattlerAttacker) / 3); + SetPassiveDamageAmount(gBattlerAttacker, GetNonDynamaxMaxHP(gBattlerAttacker) / 3); gBattlescriptCurrInstr = cmd->nextInstr; } else @@ -17887,52 +17979,6 @@ void BS_SetPoltergeistMessage(void) gBattlescriptCurrInstr = cmd->nextInstr; } -void BS_CureCertainStatuses(void) -{ - NATIVE_ARGS(); - // Check infatuation - if (gBattleMons[gBattlerTarget].volatiles.infatuation) - { - gBattleMons[gBattlerTarget].volatiles.infatuation = 0; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_INFATUATION; // STRINGID_TARGETGOTOVERINFATUATION - StringCopy(gBattleTextBuff1, gStatusConditionString_LoveJpn); - } - // Check taunt - if (gDisableStructs[gBattlerTarget].tauntTimer != 0) - { - gDisableStructs[gBattlerTarget].tauntTimer = 0; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_TAUNT; - PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_TAUNT); - } - // Check encore - if (gDisableStructs[gBattlerTarget].encoreTimer != 0) - { - gDisableStructs[gBattlerTarget].encoredMove = 0; - gDisableStructs[gBattlerTarget].encoreTimer = 0; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_ENCORE; // STRINGID_PKMNENCOREENDED - } - // Check torment - if (gBattleMons[gBattlerTarget].volatiles.torment == TRUE) - { - gBattleMons[gBattlerTarget].volatiles.torment = FALSE; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_TORMENT; - } - // Check heal block - if (gBattleMons[gBattlerTarget].volatiles.healBlock) - { - gBattleMons[gBattlerTarget].volatiles.healBlock = FALSE; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_HEALBLOCK; - } - // Check disable - if (gDisableStructs[gBattlerTarget].disableTimer != 0) - { - gDisableStructs[gBattlerTarget].disableTimer = 0; - gDisableStructs[gBattlerTarget].disabledMove = 0; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_DISABLE; - } - gBattlescriptCurrInstr = cmd->nextInstr; -} - void BS_TryResetNegativeStatStages(void) { NATIVE_ARGS(); diff --git a/src/battle_terastal.c b/src/battle_terastal.c index 05b27a48f..f0e720c93 100644 --- a/src/battle_terastal.c +++ b/src/battle_terastal.c @@ -14,7 +14,6 @@ #include "sprite.h" #include "util.h" #include "constants/abilities.h" -#include "constants/hold_effects.h" #include "constants/rgb.h" // Sets flags and variables upon a battler's Terastallization. @@ -62,7 +61,7 @@ void ApplyBattlerVisualsForTeraAnim(u32 battler) // Returns whether a battler can Terastallize. bool32 CanTerastallize(u32 battler) { - enum ItemHoldEffect holdEffect = GetBattlerHoldEffectIgnoreNegation(battler); + enum HoldEffect holdEffect = GetBattlerHoldEffectIgnoreNegation(battler); if (gBattleMons[battler].volatiles.transformed && GET_BASE_SPECIES_ID(gBattleMons[battler].species) == SPECIES_TERAPAGOS) return FALSE; @@ -109,20 +108,20 @@ bool32 CanTerastallize(u32 battler) } // Returns a battler's Tera type. -u32 GetBattlerTeraType(u32 battler) +enum Type GetBattlerTeraType(u32 battler) { return GetMonData(GetBattlerMon(battler), MON_DATA_TERA_TYPE); } // Uses up a type's Stellar boost. -void ExpendTypeStellarBoost(u32 battler, u32 type) +void ExpendTypeStellarBoost(u32 battler, enum Type type) { if (type < 32 && gBattleMons[battler].species != SPECIES_TERAPAGOS_STELLAR) // avoid OOB access gBattleStruct->stellarBoostFlags[GetBattlerSide(battler)] |= 1u << type; } // Checks whether a type's Stellar boost has been expended. -bool32 IsTypeStellarBoosted(u32 battler, u32 type) +bool32 IsTypeStellarBoosted(u32 battler, enum Type type) { if (type < 32) // avoid OOB access return !(gBattleStruct->stellarBoostFlags[GetBattlerSide(battler)] & (1u << type)); @@ -134,7 +133,7 @@ bool32 IsTypeStellarBoosted(u32 battler, u32 type) // Power multipliers from Smogon Research thread. uq4_12_t GetTeraMultiplier(struct DamageContext *ctx) { - u32 teraType = GetBattlerTeraType(ctx->battlerAtk); + enum Type teraType = GetBattlerTeraType(ctx->battlerAtk); // Safety check. if (GetActiveGimmick(ctx->battlerAtk) != GIMMICK_TERA) @@ -180,7 +179,7 @@ uq4_12_t GetTeraMultiplier(struct DamageContext *ctx) } } -u16 GetTeraTypeRGB(u32 type) +u16 GetTeraTypeRGB(enum Type type) { return gTypesInfo[type].teraTypeRGBValue; } diff --git a/src/battle_util.c b/src/battle_util.c index fb7092030..0eb54fd58 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -10,6 +10,7 @@ #include "battle_setup.h" #include "battle_z_move.h" #include "battle_gimmick.h" +#include "battle_hold_effects.h" #include "generational_changes.h" #include "party_menu.h" #include "pokemon.h" @@ -43,7 +44,6 @@ #include "constants/battle_move_effects.h" #include "constants/battle_script_commands.h" #include "constants/battle_string_ids.h" -#include "constants/hold_effects.h" #include "constants/items.h" #include "constants/item_effects.h" #include "constants/moves.h" @@ -64,11 +64,10 @@ static bool32 TryRemoveScreens(u32 battler); static bool32 IsUnnerveAbilityOnOpposingSide(u32 battler); static u32 GetFlingPowerFromItemId(u32 itemId); static void SetRandomMultiHitCounter(); -static u32 GetBattlerItemHoldEffectParam(u32 battler, u32 item); -static bool32 CanBeInfinitelyConfused(u32 battler); -static bool32 IsAnyTargetAffected(u32 battlerAtk); static bool32 IsNonVolatileStatusBlocked(u32 battlerDef, enum Ability abilityDef, enum Ability abilityAffected, const u8 *battleScript, enum FunctionCallOption option); static bool32 CanSleepDueToSleepClause(u32 battlerAtk, u32 battlerDef, enum FunctionCallOption option); +static bool32 IsOpposingSideEmpty(u32 battler); +static bool32 CanBattlerFormChange(u32 battler, enum FormChanges method); // Submoves static u32 GetMirrorMoveMove(void); @@ -192,12 +191,12 @@ static const struct BattleWeatherInfo sBattleWeatherInfo[BATTLE_WEATHER_COUNT] = // Helper function for actual dmg calcs during battle. For simulated AI dmg, CalcTypeEffectivenessMultiplier should be used directly // This should stay a static function. Ideally everything else is handled through CalcTypeEffectivenessMultiplier just like AI -static uq4_12_t CalcTypeEffectivenessMultiplierHelper(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum Ability abilityDef, bool32 recordAbilities) +static uq4_12_t CalcTypeEffectivenessMultiplierHelper(u32 move, enum Type moveType, u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum Ability abilityDef, bool32 recordAbilities) { struct DamageContext ctx = {0}; ctx.battlerAtk = battlerAtk; ctx.battlerDef = battlerDef; - ctx.move = move; + ctx.move = ctx.chosenMove = move; ctx.moveType = moveType; ctx.updateFlags = recordAbilities; ctx.abilityAtk = abilityAtk; @@ -280,6 +279,45 @@ static inline bool32 IsDragonDartsSecondHit(u32 effect) return FALSE; } +bool32 IsUnnerveBlocked(u32 battler, u32 itemId) +{ + if (GetItemPocket(itemId) != POCKET_BERRIES) + return FALSE; + + if (gBattleScripting.overrideBerryRequirements > 0) // Berries that aren't eaten naturally ignore unnerve + return FALSE; + + if (IsUnnerveAbilityOnOpposingSide(battler)) + return TRUE; + + return FALSE; +} + +static bool32 IsUnnerveAbilityOnOpposingSide(u32 battler) +{ + for (u32 battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) + { + if (battler == battlerDef || IsBattlerAlly(battler, battlerDef)) + continue; + + if (!IsBattlerAlive(battlerDef)) + continue; + + enum Ability ability = GetBattlerAbility(battlerDef); + switch (ability) + { + case ABILITY_UNNERVE: + case ABILITY_AS_ONE_ICE_RIDER: + case ABILITY_AS_ONE_SHADOW_RIDER: + return TRUE; + default: + break; + } + } + + return FALSE; +} + bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move) { enum Ability ability = GetBattlerAbility(battlerAtk); @@ -296,7 +334,7 @@ bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move) if (effect == EFFECT_PURSUIT && IsPursuitTargetSet()) return FALSE; - if (gSideTimers[defSide].followmePowder && !IsAffectedByPowder(battlerAtk, ability, GetBattlerHoldEffect(battlerAtk))) + if (gSideTimers[defSide].followmePowder && !IsAffectedByPowderMove(battlerAtk, ability, GetBattlerHoldEffect(battlerAtk))) return FALSE; return TRUE; @@ -306,7 +344,7 @@ bool32 HandleMoveTargetRedirection(void) { u32 redirectorOrderNum = MAX_BATTLERS_COUNT; u16 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove); - u32 moveType = GetBattleMoveType(gCurrentMove); + enum Type moveType = GetBattleMoveType(gCurrentMove); enum BattleMoveEffects moveEffect = GetMoveEffect(gCurrentMove); u32 side = BATTLE_OPPOSITE(GetBattlerSide(gBattlerAttacker)); enum Ability ability = GetBattlerAbility(gBattleStruct->moveTarget[gBattlerAttacker]); @@ -372,7 +410,7 @@ void HandleAction_UseMove(void) return; } - gBattleStruct->atkCancellerTracker = 0; + gBattleStruct->eventState.atkCanceller = 0; ClearDamageCalcResults(); gMultiHitCounter = 0; gBattleScripting.savedDmg = 0; @@ -387,7 +425,7 @@ void HandleAction_UseMove(void) gCurrentMove = gChosenMove = MOVE_STRUGGLE; gBattleStruct->moveTarget[gBattlerAttacker] = GetBattleMoveTarget(MOVE_STRUGGLE, NO_TARGET_OVERRIDE); } - else if (gBattleMons[gBattlerAttacker].volatiles.multipleTurns || gBattleMons[gBattlerAttacker].volatiles.recharge) + else if (gBattleMons[gBattlerAttacker].volatiles.multipleTurns || gDisableStructs[gBattlerAttacker].rechargeTimer > 0) { gCurrentMove = gChosenMove = gLockedMoves[gBattlerAttacker]; } @@ -397,7 +435,8 @@ void HandleAction_UseMove(void) { gCurrentMove = gChosenMove = gDisableStructs[gBattlerAttacker].encoredMove; gCurrMovePos = gChosenMovePos = gDisableStructs[gBattlerAttacker].encoredMovePos; - gBattleStruct->moveTarget[gBattlerAttacker] = GetBattleMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); + if (GetGenConfig(GEN_CONFIG_ENCORE_TARGET) < GEN_5) + gBattleStruct->moveTarget[gBattlerAttacker] = GetBattleMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); } // check if the encored move wasn't overwritten else if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[gBattlerAttacker].encoredMove != MOVE_NONE @@ -480,9 +519,10 @@ void HandleAction_UseMove(void) } else { - gBattlerTarget = *(gBattleStruct->moveTarget + gBattlerAttacker); + gBattlerTarget = gBattleStruct->moveTarget[gBattlerAttacker]; if (!IsBattlerAlive(gBattlerTarget) && moveTarget != MOVE_TARGET_OPPONENTS_FIELD + && IsDoubleBattle() && (!IsBattlerAlly(gBattlerAttacker, gBattlerTarget))) { gBattlerTarget = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gBattlerTarget))); @@ -510,7 +550,6 @@ void HandleAction_UseMove(void) // gBattlescriptCurrInstr = BattleScript_MoveUsedLoafingAround; // } // } - if (IsBattlerAlly(gBattlerAttacker, gBattlerTarget) && !IsBattlerAlive(gBattlerTarget)) { gBattlescriptCurrInstr = BattleScript_FailedFromAtkCanceler; @@ -530,7 +569,7 @@ void HandleAction_UseMove(void) // BattleArena_AddMindPoints(gBattlerAttacker); for (i = 0; i < MAX_BATTLERS_COUNT; i++) - gBattleStruct->hpBefore[i] = gBattleMons[i].hp; + gBattleStruct->battlerState[i].wasAboveHalfHp = gBattleMons[i].hp > gBattleMons[i].maxHP / 2; gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; } @@ -860,7 +899,7 @@ void HandleAction_TryFinish(void) { if (!HandleFaintedMonActions()) { - gBattleStruct->faintedActionsState = 0; + gBattleStruct->eventState.faintedAction = 0; gCurrentActionFuncId = B_ACTION_FINISHED; } } @@ -870,12 +909,7 @@ void HandleAction_NothingIsFainted(void) gCurrentTurnActionNumber++; gCurrentActionFuncId = gActionsByTurnOrder[gCurrentTurnActionNumber]; gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_NONE; - gHitMarker &= ~(HITMARKER_DESTINYBOND - | HITMARKER_ATTACKSTRING_PRINTED - | HITMARKER_IGNORE_SUBSTITUTE - | HITMARKER_STATUS_ABILITY_EFFECT - | HITMARKER_PASSIVE_HP_UPDATE - | HITMARKER_OBEYS); + gHitMarker &= ~(HITMARKER_OBEYS); } void HandleAction_ActionFinished(void) @@ -885,14 +919,8 @@ void HandleAction_ActionFinished(void) gBattleStruct->monToSwitchIntoId[gBattlerByTurnOrder[gCurrentTurnActionNumber]] = gSelectedMonPartyId = PARTY_SIZE; gCurrentTurnActionNumber++; gCurrentActionFuncId = gActionsByTurnOrder[gCurrentTurnActionNumber]; - SpecialStatusesClear(); - gHitMarker &= ~(HITMARKER_DESTINYBOND - | HITMARKER_IGNORE_SUBSTITUTE - | HITMARKER_ATTACKSTRING_PRINTED - | HITMARKER_STATUS_ABILITY_EFFECT - | HITMARKER_PASSIVE_HP_UPDATE - | HITMARKER_OBEYS - | HITMARKER_IGNORE_DISGUISE); + memset(&gSpecialStatuses, 0, sizeof(gSpecialStatuses)); + gHitMarker &= ~(HITMARKER_OBEYS); ClearDamageCalcResults(); gCurrentMove = 0; @@ -911,27 +939,34 @@ void HandleAction_ActionFinished(void) { // i starts at `gCurrentTurnActionNumber` because we don't want to recalculate turn order for mon that have already // taken action. It's been previously increased, which we want in order to not recalculate the turn of the mon that just finished its action + + struct BattleContext ctx = {0}; + for (i = 0; i < gBattlersCount; i++) + { + ctx.abilities[i] = GetBattlerAbility(i); + ctx.holdEffects[i] = GetBattlerHoldEffect(i); + } for (i = gCurrentTurnActionNumber; i < gBattlersCount - 1; i++) { for (j = i + 1; j < gBattlersCount; j++) { - u32 battler1 = gBattlerByTurnOrder[i]; - u32 battler2 = gBattlerByTurnOrder[j]; + ctx.battlerAtk = gBattlerByTurnOrder[i]; + ctx.battlerDef = gBattlerByTurnOrder[j]; - if (gProtectStructs[battler1].quash || gProtectStructs[battler2].quash - || gProtectStructs[battler1].shellTrap || gProtectStructs[battler2].shellTrap) + if (gProtectStructs[ctx.battlerAtk].quash || gProtectStructs[ctx.battlerDef].quash + || gProtectStructs[ctx.battlerAtk].shellTrap || gProtectStructs[ctx.battlerDef].shellTrap) continue; // We recalculate order only for action of the same priority. If any action other than switch/move has been taken, they should // have been executed before. The only recalculation needed is for moves/switch. Mega evolution is handled in src/battle_main.c/TryChangeOrder if ((gActionsByTurnOrder[i] == B_ACTION_USE_MOVE && gActionsByTurnOrder[j] == B_ACTION_USE_MOVE)) { - if (GetWhichBattlerFaster(battler1, battler2, FALSE) == -1) + if (GetWhichBattlerFaster(&ctx, FALSE) == -1) SwapTurnOrder(i, j); } else if ((gActionsByTurnOrder[i] == B_ACTION_SWITCH && gActionsByTurnOrder[j] == B_ACTION_SWITCH)) { - if (GetWhichBattlerFaster(battler1, battler2, TRUE) == -1) // If the actions chosen are switching, we recalc order but ignoring the moves + if (GetWhichBattlerFaster(&ctx, TRUE) == -1) // If the actions chosen are switching, we recalc order but ignoring the moves SwapTurnOrder(i, j); } } @@ -1195,7 +1230,7 @@ void PrepareStringBattle(enum StringID stringId, u32 battler) case STRINGID_PKMNCUTSATTACKWITH: if (GetGenConfig(GEN_CONFIG_UPDATED_INTIMIDATE) >= GEN_8 && targetAbility == ABILITY_RATTLED - && CompareStat(gBattlerTarget, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN)) + && CompareStat(gBattlerTarget, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN, targetAbility)) { gBattlerAbility = gBattlerTarget; BattleScriptCall(BattleScript_AbilityRaisesDefenderStat); @@ -1331,7 +1366,7 @@ u32 TrySetCantSelectMoveBattleScript(u32 battler) u32 limitations = 0; u8 moveId = gBattleResources->bufferB[battler][2] & ~RET_GIMMICK; u32 move = gBattleMons[battler].moves[moveId]; - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler); + enum HoldEffect holdEffect = GetBattlerHoldEffect(battler); u16 *choicedMove = &gBattleStruct->choicedMove[battler]; enum BattleMoveEffects moveEffect = GetMoveEffect(move); @@ -1402,7 +1437,7 @@ u32 TrySetCantSelectMoveBattleScript(u32 battler) // } } - if (DYNAMAX_BYPASS_CHECK && GetActiveGimmick(battler) != GIMMICK_Z_MOVE && gDisableStructs[battler].throatChopTimer > gBattleTurnCounter && IsSoundMove(move)) + if (DYNAMAX_BYPASS_CHECK && GetActiveGimmick(battler) != GIMMICK_Z_MOVE && gDisableStructs[battler].throatChopTimer > 0 && IsSoundMove(move)) { gCurrentMove = move; // if (gBattleTypeFlags & BATTLE_TYPE_PALACE) @@ -1593,7 +1628,7 @@ u32 CheckMoveLimitations(u32 battler, u8 unusableMoves, u16 check) { u32 move; enum BattleMoveEffects moveEffect; - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler); + enum HoldEffect holdEffect = GetBattlerHoldEffect(battler); u16 *choicedMove = &gBattleStruct->choicedMove[battler]; s32 i; @@ -1643,7 +1678,7 @@ u32 CheckMoveLimitations(u32 battler, u8 unusableMoves, u16 check) else if (check & MOVE_LIMITATION_BELCH && IsBelchPreventingMove(battler, move)) unusableMoves |= 1u << i; // Throat Chop - else if (check & MOVE_LIMITATION_THROAT_CHOP && gDisableStructs[battler].throatChopTimer > gBattleTurnCounter && IsSoundMove(move)) + else if (check & MOVE_LIMITATION_THROAT_CHOP && gDisableStructs[battler].throatChopTimer > 0 && IsSoundMove(move)) unusableMoves |= 1u << i; // Stuff Cheeks else if (check & MOVE_LIMITATION_STUFF_CHEEKS && moveEffect == EFFECT_STUFF_CHEEKS && GetItemPocket(gBattleMons[battler].item) != POCKET_BERRIES) @@ -1721,13 +1756,13 @@ u32 GetBattlerAffectionHearts(u32 battler) // gBattlerAttacker is the battler that's trying to raise their stats and due to limitations of RandomUniformExcept, cannot be an argument bool32 MoodyCantRaiseStat(u32 stat) { - return CompareStat(gBattlerAttacker, stat, MAX_STAT_STAGE, CMP_EQUAL); + return CompareStat(gBattlerAttacker, stat, MAX_STAT_STAGE, CMP_EQUAL, GetBattlerAbility(gBattlerAttacker)); } // gBattlerAttacker is the battler that's trying to lower their stats and due to limitations of RandomUniformExcept, cannot be an argument bool32 MoodyCantLowerStat(u32 stat) { - return stat == GET_STAT_BUFF_ID(gBattleScripting.statChanger) || CompareStat(gBattlerAttacker, stat, MIN_STAT_STAGE, CMP_EQUAL); + return stat == GET_STAT_BUFF_ID(gBattleScripting.statChanger) || CompareStat(gBattlerAttacker, stat, MIN_STAT_STAGE, CMP_EQUAL, GetBattlerAbility(gBattlerAttacker)); } void TryToRevertMimicryAndFlags(void) @@ -1742,10 +1777,8 @@ void TryToRevertMimicryAndFlags(void) // bool32 BattleArenaTurnEnd(void) // { -// gHitMarker |= (HITMARKER_GRUDGE | HITMARKER_IGNORE_BIDE); - // if ((gBattleTypeFlags & BATTLE_TYPE_ARENA) -// && gBattleStruct->arenaTurnCounter == 2 +// && gBattleStruct->eventState.arenaTurn == 2 // && IsBattlerAlive(B_POSITION_PLAYER_LEFT) && IsBattlerAlive(B_POSITION_OPPONENT_LEFT)) // { // for (u32 battler = 0; battler < 2; battler++) @@ -1755,9 +1788,6 @@ void TryToRevertMimicryAndFlags(void) // BattleScriptExecute(BattleScript_ArenaDoJudgment); // return TRUE; // } - -// gHitMarker &= ~(HITMARKER_GRUDGE | HITMARKER_IGNORE_BIDE); - // return FALSE; // } @@ -1769,7 +1799,7 @@ s32 GetDrainedBigRootHp(u32 battler, s32 hp) if (hp == 0) hp = 1; - return hp * -1; + return hp; } // Should always be the last check. Otherwise the ability might be wrongly recorded. @@ -1782,7 +1812,6 @@ bool32 IsAbilityAndRecord(u32 battler, enum Ability battlerAbility, enum Ability return TRUE; } -#define FAINTED_ACTIONS_MAX_CASE 6 bool32 HandleFaintedMonActions(void) { if (gBattleTypeFlags & BATTLE_TYPE_SAFARI) @@ -1790,38 +1819,38 @@ bool32 HandleFaintedMonActions(void) do { s32 i; - switch (gBattleStruct->faintedActionsState) + switch (gBattleStruct->eventState.faintedAction) { - case 0: - gBattleStruct->faintedActionsBattlerId = 0; - gBattleStruct->faintedActionsState++; + case FAINTED_ACTIONS_NO_MONS_TO_SWITCH: + gBattleStruct->eventState.faintedActionBattler = 0; + gBattleStruct->eventState.faintedAction++; for (i = 0; i < gBattlersCount; i++) { if (gAbsentBattlerFlags & (1u << i) && !HasNoMonsToSwitch(i, PARTY_SIZE, PARTY_SIZE)) gAbsentBattlerFlags &= ~(1u << i); } // fall through - case 1: + case FAINTED_ACTIONS_GIVE_EXP: do { - gBattlerFainted = gBattlerTarget = gBattleStruct->faintedActionsBattlerId; - if (gBattleMons[gBattleStruct->faintedActionsBattlerId].hp == 0 - && !(gBattleStruct->givenExpMons & (1u << gBattlerPartyIndexes[gBattleStruct->faintedActionsBattlerId])) - && !(gAbsentBattlerFlags & (1u << gBattleStruct->faintedActionsBattlerId))) + gBattlerFainted = gBattlerTarget = gBattleStruct->eventState.faintedActionBattler; + if (gBattleMons[gBattleStruct->eventState.faintedActionBattler].hp == 0 + && !(gBattleStruct->givenExpMons & (1u << gBattlerPartyIndexes[gBattleStruct->eventState.faintedActionBattler])) + && !(gAbsentBattlerFlags & (1u << gBattleStruct->eventState.faintedActionBattler))) { BattleScriptExecute(BattleScript_GiveExp); - gBattleStruct->faintedActionsState = 2; + gBattleStruct->eventState.faintedAction = 2; return TRUE; } - } while (++gBattleStruct->faintedActionsBattlerId != gBattlersCount); - gBattleStruct->faintedActionsState = 3; + } while (++gBattleStruct->eventState.faintedActionBattler != gBattlersCount); + gBattleStruct->eventState.faintedAction = 3; break; - case 2: + case FAINTED_ACTIONS_SET_ABSENT_FLAGS: OpponentSwitchInResetSentPokesToOpponentValue(gBattlerFainted); - if (++gBattleStruct->faintedActionsBattlerId == gBattlersCount) - gBattleStruct->faintedActionsState = 3; + if (++gBattleStruct->eventState.faintedActionBattler == gBattlersCount) + gBattleStruct->eventState.faintedAction = 3; else - gBattleStruct->faintedActionsState = 1; + gBattleStruct->eventState.faintedAction = 1; // Don't switch mons until all pokemon performed their actions or the battle's over. if (B_FAINT_SWITCH_IN >= GEN_4 && gBattleOutcome == 0 @@ -1829,11 +1858,11 @@ bool32 HandleFaintedMonActions(void) && gCurrentTurnActionNumber != gBattlersCount) { gAbsentBattlerFlags |= 1u << gBattlerFainted; - if (gBattleStruct->faintedActionsState != 1) + if (gBattleStruct->eventState.faintedAction != 1) return FALSE; } break; - case 3: + case FAINTED_ACTIONS_WAIT_STATE: // Don't switch mons until all pokemon performed their actions or the battle's over. if (B_FAINT_SWITCH_IN >= GEN_4 && gBattleOutcome == 0 @@ -1842,33 +1871,33 @@ bool32 HandleFaintedMonActions(void) { return FALSE; } - gBattleStruct->faintedActionsBattlerId = 0; - gBattleStruct->faintedActionsState++; + gBattleStruct->eventState.faintedActionBattler = 0; + gBattleStruct->eventState.faintedAction++; // fall through - case 4: + case FAINTED_ACTIONS_HANDLE_FAINTED_MON: do { - gBattlerFainted = gBattlerTarget = gBattleStruct->faintedActionsBattlerId; - if (gBattleMons[gBattleStruct->faintedActionsBattlerId].hp == 0 - && !(gAbsentBattlerFlags & (1u << gBattleStruct->faintedActionsBattlerId))) + gBattlerFainted = gBattlerTarget = gBattleStruct->eventState.faintedActionBattler; + if (gBattleMons[gBattleStruct->eventState.faintedActionBattler].hp == 0 + && !(gAbsentBattlerFlags & (1u << gBattleStruct->eventState.faintedActionBattler))) { BattleScriptExecute(BattleScript_HandleFaintedMon); - gBattleStruct->faintedActionsState = 5; + gBattleStruct->eventState.faintedAction = 5; return TRUE; } - } while (++gBattleStruct->faintedActionsBattlerId != gBattlersCount); - gBattleStruct->faintedActionsState = FAINTED_ACTIONS_MAX_CASE; + } while (++gBattleStruct->eventState.faintedActionBattler != gBattlersCount); + gBattleStruct->eventState.faintedAction = FAINTED_ACTIONS_MAX_CASE; break; - case 5: - if (++gBattleStruct->faintedActionsBattlerId == gBattlersCount) - gBattleStruct->faintedActionsState = FAINTED_ACTIONS_MAX_CASE; + case FAINTED_ACTIONS_HANDLE_NEXT_BATTLER: + if (++gBattleStruct->eventState.faintedActionBattler == gBattlersCount) + gBattleStruct->eventState.faintedAction = FAINTED_ACTIONS_MAX_CASE; else - gBattleStruct->faintedActionsState = 4; + gBattleStruct->eventState.faintedAction = 4; break; case FAINTED_ACTIONS_MAX_CASE: break; } - } while (gBattleStruct->faintedActionsState != FAINTED_ACTIONS_MAX_CASE); + } while (gBattleStruct->eventState.faintedAction != FAINTED_ACTIONS_MAX_CASE); return FALSE; } @@ -1939,10 +1968,8 @@ static enum MoveCanceller CancellerSkyDrop(struct BattleContext *ctx) static enum MoveCanceller CancellerRecharge(struct BattleContext *ctx) { - if (gBattleMons[ctx->battlerAtk].volatiles.recharge) + if (gDisableStructs[ctx->battlerAtk].rechargeTimer > 0) { - gBattleMons[ctx->battlerAtk].volatiles.recharge = TRUE; - gDisableStructs[ctx->battlerAtk].rechargeTimer = 0; CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELLER_CHECK); gBattlescriptCurrInstr = BattleScript_MoveUsedMustRecharge; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; @@ -1968,7 +1995,7 @@ static enum MoveCanceller CancellerAsleepOrFrozen(struct BattleContext *ctx) else { u8 toSub; - if (IsAbilityAndRecord(ctx->battlerAtk, ctx->ability[ctx->battlerAtk], ABILITY_EARLY_BIRD)) + if (IsAbilityAndRecord(ctx->battlerAtk, ctx->abilities[ctx->battlerAtk], ABILITY_EARLY_BIRD)) toSub = 2; else toSub = 1; @@ -1976,9 +2003,11 @@ static enum MoveCanceller CancellerAsleepOrFrozen(struct BattleContext *ctx) gBattleMons[ctx->battlerAtk].status1 &= ~STATUS1_SLEEP; else gBattleMons[ctx->battlerAtk].status1 -= toSub; + + enum BattleMoveEffects moveEffect = GetMoveEffect(ctx->currentMove); if (gBattleMons[ctx->battlerAtk].status1 & STATUS1_SLEEP) { - if (ctx->moveEffect != EFFECT_SNORE && ctx->moveEffect != EFFECT_SLEEP_TALK) + if (moveEffect != EFFECT_SNORE && moveEffect != EFFECT_SLEEP_TALK) { gProtectStructs[ctx->battlerAtk].nonVolatileStatusImmobility = TRUE; gBattlescriptCurrInstr = BattleScript_MoveUsedIsAsleep; @@ -2034,9 +2063,9 @@ static enum MoveCanceller CancellerObedience(struct BattleContext *ctx) return MOVE_STEP_FAILURE; case DISOBEYS_HITS_SELF: gBattlerTarget = ctx->battlerAtk; - struct DamageContext dmgCtx; + struct DamageContext dmgCtx = {0}; dmgCtx.battlerAtk = dmgCtx.battlerDef = ctx->battlerAtk; - dmgCtx.move = MOVE_NONE; + dmgCtx.move = dmgCtx.chosenMove = MOVE_NONE; dmgCtx.moveType = TYPE_MYSTERY; dmgCtx.isCrit = FALSE; dmgCtx.randomFactor = FALSE; @@ -2151,7 +2180,7 @@ static enum MoveCanceller CancellerVolatileBlocked(struct BattleContext *ctx) gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; return MOVE_STEP_FAILURE; } - else if (GetActiveGimmick(ctx->battlerAtk) != GIMMICK_Z_MOVE && gDisableStructs[ctx->battlerAtk].throatChopTimer > gBattleTurnCounter && IsSoundMove(ctx->currentMove)) + else if (GetActiveGimmick(ctx->battlerAtk) != GIMMICK_Z_MOVE && gDisableStructs[ctx->battlerAtk].throatChopTimer > 0 && IsSoundMove(ctx->currentMove)) { gProtectStructs[ctx->battlerAtk].unableToUseMove = TRUE; CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELLER_CHECK); @@ -2200,15 +2229,15 @@ static enum MoveCanceller CancellerConfused(struct BattleContext *ctx) if (RandomPercentage(RNG_CONFUSION, (GetGenConfig(GEN_CONFIG_CONFUSION_SELF_DMG_CHANCE) >= GEN_7 ? 33 : 50))) { gBattleCommunication[MULTISTRING_CHOOSER] = TRUE; - struct DamageContext dmgCtx; + struct DamageContext dmgCtx = {0}; dmgCtx.battlerAtk = dmgCtx.battlerDef = ctx->battlerAtk; - dmgCtx.move = MOVE_NONE; + dmgCtx.move = dmgCtx.chosenMove = MOVE_NONE; dmgCtx.moveType = TYPE_MYSTERY; dmgCtx.isCrit = FALSE; dmgCtx.randomFactor = FALSE; dmgCtx.updateFlags = TRUE; dmgCtx.fixedBasePower = 40; - gBattleStruct->moveDamage[ctx->battlerAtk] = CalculateMoveDamage(&dmgCtx); + gBattleStruct->passiveHpUpdate[ctx->battlerAtk] = CalculateMoveDamage(&dmgCtx); gProtectStructs[ctx->battlerAtk].confusionSelfDmg = TRUE; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; gBattlescriptCurrInstr = BattleScript_MoveUsedIsConfused; @@ -2245,7 +2274,7 @@ static enum MoveCanceller CancellerGhost(struct BattleContext *ctx) // GHOST in static enum MoveCanceller CancellerParalysed(struct BattleContext *ctx) { if (gBattleMons[ctx->battlerAtk].status1 & STATUS1_PARALYSIS - && !(B_MAGIC_GUARD == GEN_4 && IsAbilityAndRecord(ctx->battlerAtk, ctx->ability[ctx->battlerAtk], ABILITY_MAGIC_GUARD)) + && !(B_MAGIC_GUARD == GEN_4 && IsAbilityAndRecord(ctx->battlerAtk, ctx->abilities[ctx->battlerAtk], ABILITY_MAGIC_GUARD)) && !RandomPercentage(RNG_PARALYSIS, 75)) { gProtectStructs[ctx->battlerAtk].nonVolatileStatusImmobility = TRUE; @@ -2334,11 +2363,11 @@ static enum MoveCanceller CancellerZMoves(struct BattleContext *ctx) static enum MoveCanceller CancellerChoiceLock(struct BattleContext *ctx) { u16 *choicedMoveAtk = &gBattleStruct->choicedMove[ctx->battlerAtk]; - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(ctx->battlerAtk); + enum HoldEffect holdEffect = GetBattlerHoldEffect(ctx->battlerAtk); if (gChosenMove != MOVE_STRUGGLE && (*choicedMoveAtk == MOVE_NONE || *choicedMoveAtk == MOVE_UNAVAILABLE) - && (IsHoldEffectChoice(holdEffect) || ctx->ability[ctx->battlerAtk] == ABILITY_GORILLA_TACTICS)) + && (IsHoldEffectChoice(holdEffect) || ctx->abilities[ctx->battlerAtk] == ABILITY_GORILLA_TACTICS)) *choicedMoveAtk = gChosenMove; u32 moveIndex; @@ -2356,12 +2385,12 @@ static enum MoveCanceller CancellerChoiceLock(struct BattleContext *ctx) static enum MoveCanceller CancellerCallSubmove(struct BattleContext *ctx) { - u32 noEffect = FALSE; + bool32 noEffect = FALSE; u32 calledMove = MOVE_NONE; const u8 *battleScript = NULL; battleScript = BattleScript_SubmoveAttackstring; - switch(ctx->moveEffect) + switch(GetMoveEffect(ctx->currentMove)) { case EFFECT_MIRROR_MOVE: calledMove = GetMirrorMoveMove(); @@ -2402,7 +2431,7 @@ static enum MoveCanceller CancellerCallSubmove(struct BattleContext *ctx) { if (GetActiveGimmick(ctx->battlerAtk) == GIMMICK_Z_MOVE && !IsBattleMoveStatus(calledMove)) calledMove = GetTypeBasedZMove(calledMove); - if (ctx->moveEffect == EFFECT_COPYCAT && IsMaxMove(calledMove)) + if (GetMoveEffect(ctx->currentMove) == EFFECT_COPYCAT && IsMaxMove(calledMove)) calledMove = gBattleStruct->dynamax.lastUsedBaseMove; gBattleStruct->submoveAnnouncement = SUBMOVE_SUCCESS; @@ -2449,8 +2478,9 @@ static enum MoveCanceller CancellerStanceChangeTwo(struct BattleContext *ctx) static enum MoveCanceller CancellerAttackstring(struct BattleContext *ctx) { - gHitMarker |= HITMARKER_ATTACKSTRING_PRINTED; BattleScriptCall(BattleScript_Attackstring); + if (!gSpecialStatuses[gBattlerAttacker].dancerUsedMove) + gLastPrintedMoves[gBattlerAttacker] = gChosenMove; return MOVE_STEP_BREAK; } @@ -2481,13 +2511,13 @@ static enum MoveCanceller CancellerPPDeduction(struct BattleContext *ctx) } else if (moveTarget != MOVE_TARGET_OPPONENTS_FIELD) { - if (ctx->battlerAtk != ctx->battlerDef && ctx->ability[ctx->battlerDef] == ABILITY_PRESSURE) + if (ctx->battlerAtk != ctx->battlerDef && ctx->abilities[ctx->battlerDef] == ABILITY_PRESSURE) ppToDeduct++; } // For item Metronome, echoed voice if (ctx->currentMove != gLastResultingMoves[ctx->battlerAtk] || WasUnableToUseMove(ctx->battlerAtk)) - gBattleStruct->sameMoveTurns[ctx->battlerAtk] = 0; + gBattleStruct->metronomeItemCounter[ctx->battlerAtk] = 0; if (gBattleMons[ctx->battlerAtk].pp[movePosition] > ppToDeduct) gBattleMons[ctx->battlerAtk].pp[movePosition] -= ppToDeduct; @@ -2542,7 +2572,7 @@ static enum MoveCanceller CancellerWeatherPrimal(struct BattleContext *ctx) enum MoveCanceller effect = MOVE_STEP_SUCCESS; if (HasWeatherEffect() && GetMovePower(ctx->currentMove) > 0) { - u32 moveType = GetBattleMoveType(ctx->currentMove); + enum Type moveType = GetBattleMoveType(ctx->currentMove); if (moveType == TYPE_FIRE && (gBattleWeather & B_WEATHER_RAIN_PRIMAL) && (GetGenConfig(GEN_CONFIG_POWDER_RAIN) >= GEN_7 || !TryActivatePowderStatus(ctx->currentMove))) { gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_PRIMAL_WEATHER_FIZZLED_BY_RAIN; @@ -2555,7 +2585,6 @@ static enum MoveCanceller CancellerWeatherPrimal(struct BattleContext *ctx) } if (effect == MOVE_STEP_FAILURE) { - gBattleScripting.moveEffect = MOVE_EFFECT_NONE; gProtectStructs[ctx->battlerAtk].chargingTurn = FALSE; CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELLER_CHECK); gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; @@ -2569,7 +2598,7 @@ static enum MoveCanceller CancellerMoveFailure(struct BattleContext *ctx) { const u8 *battleScript = NULL; - switch (ctx->moveEffect) + switch (GetMoveEffect(ctx->currentMove)) { case EFFECT_FAIL_IF_NOT_ARG_TYPE: if (!IS_BATTLER_OF_TYPE(ctx->battlerAtk, GetMoveArgType(ctx->currentMove))) @@ -2614,7 +2643,7 @@ static enum MoveCanceller CancellerMoveFailure(struct BattleContext *ctx) battleScript = BattleScript_ButItFailed; break; case EFFECT_FUTURE_SIGHT: - if (gWishFutureKnock.futureSightCounter[ctx->battlerDef] > gBattleTurnCounter) + if (gWishFutureKnock.futureSightCounter[ctx->battlerDef] > 0) battleScript = BattleScript_ButItFailed; break; case EFFECT_LAST_RESORT: @@ -2628,7 +2657,7 @@ static enum MoveCanceller CancellerMoveFailure(struct BattleContext *ctx) case EFFECT_POLTERGEIST: if (gBattleMons[ctx->battlerDef].item == ITEM_NONE || gFieldStatuses & STATUS_FIELD_MAGIC_ROOM - || ctx->ability[ctx->battlerDef] == ABILITY_KLUTZ) + || ctx->abilities[ctx->battlerDef] == ABILITY_KLUTZ) battleScript = BattleScript_ButItFailed; break; case EFFECT_PROTECT: @@ -2636,13 +2665,13 @@ static enum MoveCanceller CancellerMoveFailure(struct BattleContext *ctx) break; case EFFECT_REST: if (gBattleMons[ctx->battlerAtk].status1 & STATUS1_SLEEP - || ctx->ability[ctx->battlerAtk] == ABILITY_COMATOSE) + || ctx->abilities[ctx->battlerAtk] == ABILITY_COMATOSE) battleScript = BattleScript_RestIsAlreadyAsleep; else if (gBattleMons[ctx->battlerAtk].hp == gBattleMons[ctx->battlerAtk].maxHP) battleScript = BattleScript_AlreadyAtFullHp; - else if (ctx->ability[ctx->battlerAtk] == ABILITY_INSOMNIA - || ctx->ability[ctx->battlerAtk] == ABILITY_VITAL_SPIRIT - || ctx->ability[ctx->battlerAtk] == ABILITY_PURIFYING_SALT) + else if (ctx->abilities[ctx->battlerAtk] == ABILITY_INSOMNIA + || ctx->abilities[ctx->battlerAtk] == ABILITY_VITAL_SPIRIT + || ctx->abilities[ctx->battlerAtk] == ABILITY_PURIFYING_SALT) battleScript = BattleScript_InsomniaProtects; break; case EFFECT_SUCKER_PUNCH: @@ -2652,7 +2681,7 @@ static enum MoveCanceller CancellerMoveFailure(struct BattleContext *ctx) break; case EFFECT_SNORE: if (!(gBattleMons[ctx->battlerAtk].status1 & STATUS1_SLEEP) - && ctx->ability[ctx->battlerAtk] != ABILITY_COMATOSE) + && ctx->abilities[ctx->battlerAtk] != ABILITY_COMATOSE) battleScript = BattleScript_ButItFailed; break; case EFFECT_STEEL_ROLLER: @@ -2698,8 +2727,8 @@ static enum MoveCanceller CancellerPowderStatus(struct BattleContext *ctx) { if (TryActivatePowderStatus(ctx->currentMove)) { - if (!IsAbilityAndRecord(ctx->battlerAtk, ctx->ability[ctx->battlerAtk], ABILITY_MAGIC_GUARD)) - gBattleStruct->moveDamage[ctx->battlerAtk] = GetNonDynamaxMaxHP(ctx->battlerAtk) / 4; + if (!IsAbilityAndRecord(ctx->battlerAtk, ctx->abilities[ctx->battlerAtk], ABILITY_MAGIC_GUARD)) + SetPassiveDamageAmount(ctx->battlerAtk, GetNonDynamaxMaxHP(ctx->battlerAtk) / 4); // This might be incorrect if (GetActiveGimmick(ctx->battlerAtk) != GIMMICK_Z_MOVE @@ -2726,16 +2755,16 @@ bool32 IsDazzlingAbility(enum Ability ability) static enum MoveCanceller CancellerPriorityBlock(struct BattleContext *ctx) { bool32 effect = FALSE; - s32 priority = GetChosenMovePriority(ctx->battlerAtk, ctx->ability[ctx->battlerAtk]); + s32 priority = GetChosenMovePriority(ctx->battlerAtk, ctx->abilities[ctx->battlerAtk]); u32 blockAbility = ABILITY_NONE; // ability of battler who is blocking u32 blockedByBattler = ctx->battlerDef; if (priority <= 0 || IsBattlerAlly(ctx->battlerAtk, ctx->battlerDef)) return MOVE_STEP_SUCCESS; - if (IsDazzlingAbility(ctx->ability[ctx->battlerDef])) + if (IsDazzlingAbility(ctx->abilities[ctx->battlerDef])) { - blockAbility = ctx->ability[ctx->battlerDef]; + blockAbility = ctx->abilities[ctx->battlerDef]; effect = TRUE; } else if (IsDoubleBattle() && IsBattlerAlive(BATTLE_PARTNER(ctx->battlerDef))) @@ -2764,8 +2793,8 @@ static enum MoveCanceller CancellerPriorityBlock(struct BattleContext *ctx) static enum MoveCanceller CancellerProtean(struct BattleContext *ctx) { - u32 moveType = GetBattleMoveType(ctx->currentMove); - if (ProteanTryChangeType(ctx->battlerAtk, ctx->ability[ctx->battlerAtk], ctx->currentMove, moveType)) + enum Type moveType = GetBattleMoveType(ctx->currentMove); + if (ProteanTryChangeType(ctx->battlerAtk, ctx->abilities[ctx->battlerAtk], ctx->currentMove, moveType)) { if (GetGenConfig(GEN_PROTEAN_LIBERO) >= GEN_9) gDisableStructs[ctx->battlerAtk].usedProteanLibero = TRUE; @@ -2796,7 +2825,7 @@ static enum MoveCanceller CancellerMultihitMoves(struct BattleContext *ctx) { if (GetMoveEffect(ctx->currentMove) == EFFECT_MULTI_HIT) { - enum Ability ability = ctx->ability[ctx->battlerAtk]; + enum Ability ability = ctx->abilities[ctx->battlerAtk]; if (ability == ABILITY_SKILL_LINK) { @@ -2817,7 +2846,7 @@ static enum MoveCanceller CancellerMultihitMoves(struct BattleContext *ctx) } else if (GetMoveStrikeCount(ctx->currentMove) > 1) { - if (ctx->moveEffect == EFFECT_POPULATION_BOMB && GetBattlerHoldEffect(ctx->battlerAtk) == HOLD_EFFECT_LOADED_DICE) + if (GetMoveEffect(ctx->currentMove) == EFFECT_POPULATION_BOMB && GetBattlerHoldEffect(ctx->battlerAtk) == HOLD_EFFECT_LOADED_DICE) { gMultiHitCounter = RandomUniform(RNG_LOADED_DICE, 4, 10); } @@ -2825,7 +2854,7 @@ static enum MoveCanceller CancellerMultihitMoves(struct BattleContext *ctx) { gMultiHitCounter = GetMoveStrikeCount(ctx->currentMove); - if (ctx->moveEffect == EFFECT_DRAGON_DARTS + if (GetMoveEffect(ctx->currentMove) == EFFECT_DRAGON_DARTS && !IsAffectedByFollowMe(ctx->battlerAtk, GetBattlerSide(ctx->battlerDef), ctx->currentMove) && CanTargetPartner(ctx->battlerAtk, ctx->battlerDef) && TargetFullyImmuneToCurrMove(ctx->battlerAtk, ctx->battlerDef)) @@ -2834,7 +2863,7 @@ static enum MoveCanceller CancellerMultihitMoves(struct BattleContext *ctx) PREPARE_BYTE_NUMBER_BUFFER(gBattleScripting.multihitString, 3, 0) } - else if (B_BEAT_UP >= GEN_5 && ctx->moveEffect == EFFECT_BEAT_UP) + else if (B_BEAT_UP >= GEN_5 && GetMoveEffect(ctx->currentMove) == EFFECT_BEAT_UP) { struct Pokemon* party = GetBattlerParty(ctx->battlerAtk); int i; @@ -2867,7 +2896,7 @@ static enum MoveCanceller CancellerMultihitMoves(struct BattleContext *ctx) static enum MoveCanceller CancellerMultiTargetMoves(struct BattleContext *ctx) { u32 moveTarget = GetBattlerMoveTargetType(ctx->battlerAtk, ctx->currentMove); - enum Ability abilityAtk = ctx->ability[ctx->battlerAtk]; + enum Ability abilityAtk = ctx->abilities[ctx->battlerAtk]; if (IsSpreadMove(moveTarget)) { @@ -2880,7 +2909,7 @@ static enum MoveCanceller CancellerMultiTargetMoves(struct BattleContext *ctx) if (ctx->battlerAtk == battlerDef || !IsBattlerAlive(battlerDef) - || (ctx->moveEffect == EFFECT_SYNCHRONOISE && !DoBattlersShareType(ctx->battlerAtk, battlerDef)) + || (GetMoveEffect(ctx->currentMove) == EFFECT_SYNCHRONOISE && !DoBattlersShareType(ctx->battlerAtk, battlerDef)) || (moveTarget == MOVE_TARGET_BOTH && ctx->battlerAtk == BATTLE_PARTNER(battlerDef)) || IsBattlerProtected(ctx->battlerAtk, battlerDef, ctx->currentMove)) // Missing Invulnerable check { @@ -2952,10 +2981,10 @@ enum MoveCanceller AtkCanceller_MoveSuccessOrder(struct BattleContext *ctx) { enum MoveCanceller effect = MOVE_STEP_SUCCESS; - while (gBattleStruct->atkCancellerTracker < CANCELLER_END && effect == MOVE_STEP_SUCCESS) + while (gBattleStruct->eventState.atkCanceller < CANCELLER_END && effect == MOVE_STEP_SUCCESS) { - effect = sMoveSuccessOrderCancellers[gBattleStruct->atkCancellerTracker](ctx); - gBattleStruct->atkCancellerTracker++; + effect = sMoveSuccessOrderCancellers[gBattleStruct->eventState.atkCanceller](ctx); + gBattleStruct->eventState.atkCanceller++; } if (effect == MOVE_STEP_REMOVES_STATUS) @@ -3131,24 +3160,24 @@ bool32 HasNoMonsToSwitch(u32 battler, u8 partyIdBattlerOn1, u8 partyIdBattlerOn2 } } -bool32 TryChangeBattleWeather(u32 battler, u32 battleWeatherId, bool32 viaAbility) +bool32 TryChangeBattleWeather(u32 battler, u32 battleWeatherId, u32 ability) { - enum Ability battlerAbility = GetBattlerAbility(battler); - if (gBattleWeather & sBattleWeatherInfo[battleWeatherId].flag) { return FALSE; } else if (gBattleWeather & B_WEATHER_PRIMAL_ANY - && battlerAbility != ABILITY_DESOLATE_LAND - && battlerAbility != ABILITY_PRIMORDIAL_SEA - && battlerAbility != ABILITY_DELTA_STREAM) + && ability != ABILITY_DESOLATE_LAND + && ability != ABILITY_PRIMORDIAL_SEA + && ability != ABILITY_DELTA_STREAM) { return FALSE; } - else if (GetGenConfig(GEN_CONFIG_ABILITY_WEATHER) < GEN_6 && viaAbility) + else if (GetGenConfig(GEN_CONFIG_ABILITY_WEATHER) < GEN_6 && ability != ABILITY_NONE) { gBattleWeather = sBattleWeatherInfo[battleWeatherId].flag; + for (u32 i = 0; i < gBattlersCount; i++) + gDisableStructs[i].weatherAbilityDone = FALSE; return TRUE; } else @@ -3161,25 +3190,29 @@ bool32 TryChangeBattleWeather(u32 battler, u32 battleWeatherId, bool32 viaAbilit gWishFutureKnock.weatherDuration = 8; else gWishFutureKnock.weatherDuration = 5; + for (u32 i = 0; i < gBattlersCount; i++) + gDisableStructs[i].weatherAbilityDone = FALSE; return TRUE; } return FALSE; } -static bool32 TryChangeBattleTerrain(u32 battler, u32 statusFlag, u16 *timer) +bool32 TryChangeBattleTerrain(u32 battler, u32 statusFlag) { - if ((!(gFieldStatuses & statusFlag) && (!gBattleStruct->isSkyBattle))) + if (gBattleStruct->isSkyBattle) + return FALSE; + + if (!(gFieldStatuses & statusFlag)) { gFieldStatuses &= ~STATUS_FIELD_TERRAIN_ANY; gFieldStatuses |= statusFlag; - gDisableStructs[battler].terrainAbilityDone = FALSE; - + for (u32 i = 0; i < gBattlersCount; i++) + gDisableStructs[i].terrainAbilityDone = FALSE; if (GetBattlerHoldEffect(battler) == HOLD_EFFECT_TERRAIN_EXTENDER) - *timer = gBattleTurnCounter + 8; + gFieldTimers.terrainTimer = 8; else - *timer = gBattleTurnCounter + 5; - + gFieldTimers.terrainTimer = 5; gBattleScripting.battler = battler; return TRUE; } @@ -3251,7 +3284,7 @@ static void ForewarnChooseMove(u32 battler) bool32 ChangeTypeBasedOnTerrain(u32 battler) { - u32 battlerType; + enum Type battlerType; if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) battlerType = TYPE_ELECTRIC; @@ -3269,7 +3302,7 @@ bool32 ChangeTypeBasedOnTerrain(u32 battler) return TRUE; } -static inline u8 GetSideFaintCounter(u32 side) +static inline u8 GetSideFaintCounter(enum BattleSide side) { return (side == B_SIDE_PLAYER) ? gBattleResults.playerFaintCounter : gBattleResults.opponentFaintCounter; } @@ -3287,10 +3320,9 @@ static inline uq4_12_t GetSupremeOverlordModifier(u32 battler) bool32 HadMoreThanHalfHpNowDoesnt(u32 battler) { - u32 cutoff = gBattleMons[battler].maxHP / 2; // Had more than half of hp before, now has less - return gBattleStruct->hpBefore[battler] > cutoff - && gBattleMons[battler].hp <= cutoff; + return gBattleStruct->battlerState[battler].wasAboveHalfHp + && gBattleMons[battler].hp <= gBattleMons[battler].maxHP / 2; } #define ANIM_STAT_HP 0 @@ -3301,7 +3333,7 @@ bool32 HadMoreThanHalfHpNowDoesnt(u32 battler) #define ANIM_STAT_SPEED 5 #define ANIM_STAT_ACC 6 #define ANIM_STAT_EVASION 7 -static void ChooseStatBoostAnimation(u32 battler) +void ChooseStatBoostAnimation(u32 battler) { u32 stat; bool32 statBuffMoreThan1 = FALSE; @@ -3418,11 +3450,11 @@ bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, enum Ability abilityA return TRUE; } -bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef, u32 move, u32 moveType, enum FunctionCallOption option) +bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef, u32 move, enum Type moveType, enum FunctionCallOption option) { enum MoveAbsorbed effect = MOVE_ABSORBED_BY_NO_ABILITY; const u8 *battleScript = NULL; - u32 statId = 0; + enum Stat statId = 0; u32 statAmount = 1; switch (abilityDef) @@ -3508,15 +3540,12 @@ bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, enum Ability ability else { battleScript = BattleScript_MoveHPDrain; - gBattleStruct->moveDamage[battlerDef] = GetNonDynamaxMaxHP(battlerDef) / 4; - if (gBattleStruct->moveDamage[battlerDef] == 0) - gBattleStruct->moveDamage[battlerDef] = 1; - gBattleStruct->moveDamage[battlerDef] *= -1; + SetHealAmount(battlerDef, GetNonDynamaxMaxHP(battlerDef) / 4); } break; case MOVE_ABSORBED_BY_STAT_INCREASE_ABILITY: gBattleStruct->pledgeMove = FALSE; - if (!CompareStat(battlerDef, statId, MAX_STAT_STAGE, CMP_LESS_THAN)) + if (!CompareStat(battlerDef, statId, MAX_STAT_STAGE, CMP_LESS_THAN, abilityDef)) { battleScript = BattleScript_MonMadeMoveUseless; } @@ -3556,7 +3585,7 @@ bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, enum Ability ability return effect; } -static inline u32 SetStartingFieldStatus(u32 flag, u32 message, u32 anim, u16 *timer) +static inline bool32 SetStartingFieldStatus(u32 flag, u32 message, u32 anim, u16 *timer) { if (!(gFieldStatuses & flag)) { @@ -3564,17 +3593,17 @@ static inline u32 SetStartingFieldStatus(u32 flag, u32 message, u32 anim, u16 *t gFieldStatuses |= flag; gBattleScripting.animArg1 = anim; if (gBattleStruct->startingStatusTimer) - *timer = gBattleTurnCounter + gBattleStruct->startingStatusTimer; + *timer = gBattleStruct->startingStatusTimer; else *timer = 0; // Infinite - return 1; + return TRUE; } - return 0; + return FALSE; } -static inline u32 SetStartingSideStatus(u32 flag, u32 side, u32 message, u32 anim, u16 *timer) +static inline bool32 SetStartingSideStatus(u32 flag, u32 side, u32 message, u32 anim, u16 *timer) { if (!(gSideStatuses[side] & flag)) { @@ -3583,20 +3612,254 @@ static inline u32 SetStartingSideStatus(u32 flag, u32 side, u32 message, u32 ani gSideStatuses[side] |= flag; gBattleScripting.animArg1 = anim; if (gBattleStruct->startingStatusTimer) - *timer = gBattleTurnCounter + gBattleStruct->startingStatusTimer; + *timer = gBattleStruct->startingStatusTimer; else *timer = 0; // Infinite - return 1; + return TRUE; } - return 0; + return FALSE; } -u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 special, u32 moveArg) +bool32 TryFieldEffects(enum FieldEffectCases caseId) +{ + bool32 effect = FALSE; + bool32 isTerrain = FALSE; + + if (gBattleTypeFlags & (BATTLE_TYPE_SAFARI | BATTLE_TYPE_OLD_MAN_TUTORIAL)) + return FALSE; + + switch (caseId) + { + case FIELD_EFFECT_TRAINER_STATUSES: // starting field/side/etc statuses with a variable + switch ((enum StartingStatus) gBattleStruct->startingStatus) + { + case STARTING_STATUS_NONE: + break; + case STARTING_STATUS_ELECTRIC_TERRAIN: + effect = SetStartingFieldStatus( + STATUS_FIELD_ELECTRIC_TERRAIN, + B_MSG_TERRAIN_SET_ELECTRIC, + 0, + &gFieldTimers.terrainTimer); + isTerrain = TRUE; + break; + case STARTING_STATUS_MISTY_TERRAIN: + effect = SetStartingFieldStatus( + STATUS_FIELD_MISTY_TERRAIN, + B_MSG_TERRAIN_SET_MISTY, + 0, + &gFieldTimers.terrainTimer); + isTerrain = TRUE; + break; + case STARTING_STATUS_GRASSY_TERRAIN: + effect = SetStartingFieldStatus( + STATUS_FIELD_GRASSY_TERRAIN, + B_MSG_TERRAIN_SET_GRASSY, + 0, + &gFieldTimers.terrainTimer); + isTerrain = TRUE; + break; + case STARTING_STATUS_PSYCHIC_TERRAIN: + effect = SetStartingFieldStatus( + STATUS_FIELD_PSYCHIC_TERRAIN, + B_MSG_TERRAIN_SET_PSYCHIC, + 0, + &gFieldTimers.terrainTimer); + isTerrain = TRUE; + break; + case STARTING_STATUS_TRICK_ROOM: + effect = SetStartingFieldStatus( + STATUS_FIELD_TRICK_ROOM, + B_MSG_SET_TRICK_ROOM, + B_ANIM_TRICK_ROOM, + &gFieldTimers.trickRoomTimer); + break; + case STARTING_STATUS_MAGIC_ROOM: + effect = SetStartingFieldStatus( + STATUS_FIELD_MAGIC_ROOM, + B_MSG_SET_MAGIC_ROOM, + B_ANIM_MAGIC_ROOM, + &gFieldTimers.magicRoomTimer); + break; + case STARTING_STATUS_WONDER_ROOM: + effect = SetStartingFieldStatus( + STATUS_FIELD_WONDER_ROOM, + B_MSG_SET_WONDER_ROOM, + B_ANIM_WONDER_ROOM, + &gFieldTimers.wonderRoomTimer); + break; + case STARTING_STATUS_TAILWIND_PLAYER: + effect = SetStartingSideStatus( + SIDE_STATUS_TAILWIND, + B_SIDE_PLAYER, + B_MSG_SET_TAILWIND, + B_ANIM_TAILWIND, + &gSideTimers[B_SIDE_PLAYER].tailwindTimer); + break; + case STARTING_STATUS_TAILWIND_OPPONENT: + effect = SetStartingSideStatus( + SIDE_STATUS_TAILWIND, + B_SIDE_OPPONENT, + B_MSG_SET_TAILWIND, + B_ANIM_TAILWIND, + &gSideTimers[B_SIDE_OPPONENT].tailwindTimer); + break; + case STARTING_STATUS_RAINBOW_PLAYER: + effect = SetStartingSideStatus( + SIDE_STATUS_RAINBOW, + B_SIDE_PLAYER, + B_MSG_SET_RAINBOW, + B_ANIM_RAINBOW, + &gSideTimers[B_SIDE_PLAYER].rainbowTimer); + break; + case STARTING_STATUS_RAINBOW_OPPONENT: + effect = SetStartingSideStatus( + SIDE_STATUS_RAINBOW, + B_SIDE_OPPONENT, + B_MSG_SET_RAINBOW, + B_ANIM_RAINBOW, + &gSideTimers[B_SIDE_OPPONENT].rainbowTimer); + break; + case STARTING_STATUS_SEA_OF_FIRE_PLAYER: + effect = SetStartingSideStatus( + SIDE_STATUS_SEA_OF_FIRE, + B_SIDE_PLAYER, + B_MSG_SET_SEA_OF_FIRE, + B_ANIM_SEA_OF_FIRE, + &gSideTimers[B_SIDE_PLAYER].seaOfFireTimer); + break; + case STARTING_STATUS_SEA_OF_FIRE_OPPONENT: + effect = SetStartingSideStatus( + SIDE_STATUS_SEA_OF_FIRE, + B_SIDE_OPPONENT, + B_MSG_SET_SEA_OF_FIRE, + B_ANIM_SEA_OF_FIRE, + &gSideTimers[B_SIDE_OPPONENT].seaOfFireTimer); + break; + case STARTING_STATUS_SWAMP_PLAYER: + effect = SetStartingSideStatus( + SIDE_STATUS_SWAMP, + B_SIDE_PLAYER, + B_MSG_SET_SWAMP, + B_ANIM_SWAMP, + &gSideTimers[B_SIDE_PLAYER].swampTimer); + break; + case STARTING_STATUS_SWAMP_OPPONENT: + effect = SetStartingSideStatus( + SIDE_STATUS_SWAMP, + B_SIDE_OPPONENT, + B_MSG_SET_SWAMP, + B_ANIM_SWAMP, + &gSideTimers[B_SIDE_OPPONENT].swampTimer); + break; + } + if (effect) + { + if (isTerrain) + BattleScriptPushCursorAndCallback(BattleScript_OverworldTerrain); + else + BattleScriptPushCursorAndCallback(BattleScript_OverworldStatusStarts); + } + break; + case FIELD_EFFECT_OVERWORLD_TERRAIN: // terrain starting from overworld weather + if (B_THUNDERSTORM_TERRAIN == TRUE + && !(gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) + && GetCurrentWeather() == WEATHER_RAIN_THUNDERSTORM) + { + // overworld weather started rain, so just do electric terrain anim + gFieldStatuses = STATUS_FIELD_ELECTRIC_TERRAIN; + gFieldTimers.terrainTimer = 0; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_ELECTRIC; + BattleScriptPushCursorAndCallback(BattleScript_OverworldTerrain); + effect = TRUE; + } + else if (B_OVERWORLD_FOG >= GEN_8 + && (GetCurrentWeather() == WEATHER_FOG_HORIZONTAL || GetCurrentWeather() == WEATHER_FOG_DIAGONAL) + && !(gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)) + { + gFieldStatuses = STATUS_FIELD_MISTY_TERRAIN; + gFieldTimers.terrainTimer = 0; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_MISTY; + BattleScriptPushCursorAndCallback(BattleScript_OverworldTerrain); + effect = TRUE; + } + break; + case FIELD_EFFECT_OVERWORLD_WEATHER: + if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED)) + { + switch (GetCurrentWeather()) + { + case WEATHER_RAIN: + case WEATHER_RAIN_THUNDERSTORM: + case WEATHER_DOWNPOUR: + if (!(gBattleWeather & B_WEATHER_RAIN)) + { + gBattleWeather = B_WEATHER_RAIN_NORMAL; + gBattleScripting.animArg1 = B_ANIM_RAIN_CONTINUES; + effect = TRUE; + } + break; + case WEATHER_SANDSTORM: + if (!(gBattleWeather & B_WEATHER_SANDSTORM)) + { + gBattleWeather = B_WEATHER_SANDSTORM; + gBattleScripting.animArg1 = B_ANIM_SANDSTORM_CONTINUES; + effect = TRUE; + } + break; + case WEATHER_DROUGHT: + if (!(gBattleWeather & B_WEATHER_SUN)) + { + gBattleWeather = B_WEATHER_SUN_NORMAL; + gBattleScripting.animArg1 = B_ANIM_SUN_CONTINUES; + effect = TRUE; + } + break; + case WEATHER_SNOW: + if (!(gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW))) + { + if (B_OVERWORLD_SNOW >= GEN_9) + { + gBattleWeather = B_WEATHER_SNOW; + gBattleScripting.animArg1 = B_ANIM_SNOW_CONTINUES; + } + else + { + gBattleWeather = B_WEATHER_HAIL; + gBattleScripting.animArg1 = B_ANIM_HAIL_CONTINUES; + } + effect = TRUE; + } + break; + case WEATHER_FOG_DIAGONAL: + case WEATHER_FOG_HORIZONTAL: + if (B_OVERWORLD_FOG == GEN_4 && !(gBattleWeather & B_WEATHER_FOG)) + { + gBattleWeather = B_WEATHER_FOG; + gBattleScripting.animArg1 = B_ANIM_FOG_CONTINUES; + effect = TRUE; + } + break; + } + } + if (effect) + { + gBattleCommunication[MULTISTRING_CHOOSER] = GetCurrentWeather(); + BattleScriptPushCursorAndCallback(BattleScript_OverworldWeatherStarts); + } + break; + } + + return effect; +} + +u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ability, u32 special, u32 moveArg) { u32 effect = 0; - u32 moveType = 0, move = 0; + enum Type moveType = 0; + u32 move = 0; u32 side = 0; u32 i = 0, j = 0; u32 partner = 0; @@ -3623,212 +3886,6 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec switch (caseID) { - case ABILITYEFFECT_SWITCH_IN_STATUSES: // starting field/side/etc statuses with a variable - { - gBattleScripting.battler = battler; - switch (gBattleStruct->startingStatus) - { - case STARTING_STATUS_ELECTRIC_TERRAIN: - effect = SetStartingFieldStatus(STATUS_FIELD_ELECTRIC_TERRAIN, - B_MSG_TERRAIN_SET_ELECTRIC, - 0, - &gFieldTimers.terrainTimer); - effect = (effect == 1) ? 2 : 0; - break; - case STARTING_STATUS_MISTY_TERRAIN: - effect = SetStartingFieldStatus(STATUS_FIELD_MISTY_TERRAIN, - B_MSG_TERRAIN_SET_MISTY, - 0, - &gFieldTimers.terrainTimer); - effect = (effect == 1) ? 2 : 0; - break; - case STARTING_STATUS_GRASSY_TERRAIN: - effect = SetStartingFieldStatus(STATUS_FIELD_GRASSY_TERRAIN, - B_MSG_TERRAIN_SET_GRASSY, - 0, - &gFieldTimers.terrainTimer); - effect = (effect == 1) ? 2 : 0; - break; - case STARTING_STATUS_PSYCHIC_TERRAIN: - effect = SetStartingFieldStatus(STATUS_FIELD_PSYCHIC_TERRAIN, - B_MSG_TERRAIN_SET_PSYCHIC, - 0, - &gFieldTimers.terrainTimer); - effect = (effect == 1) ? 2 : 0; - break; - case STARTING_STATUS_TRICK_ROOM: - effect = SetStartingFieldStatus(STATUS_FIELD_TRICK_ROOM, - B_MSG_SET_TRICK_ROOM, - B_ANIM_TRICK_ROOM, - &gFieldTimers.trickRoomTimer); - break; - case STARTING_STATUS_MAGIC_ROOM: - effect = SetStartingFieldStatus(STATUS_FIELD_MAGIC_ROOM, - B_MSG_SET_MAGIC_ROOM, - B_ANIM_MAGIC_ROOM, - &gFieldTimers.magicRoomTimer); - break; - case STARTING_STATUS_WONDER_ROOM: - effect = SetStartingFieldStatus(STATUS_FIELD_WONDER_ROOM, - B_MSG_SET_WONDER_ROOM, - B_ANIM_WONDER_ROOM, - &gFieldTimers.wonderRoomTimer); - break; - case STARTING_STATUS_TAILWIND_PLAYER: - effect = SetStartingSideStatus(SIDE_STATUS_TAILWIND, - B_SIDE_PLAYER, - B_MSG_SET_TAILWIND, - B_ANIM_TAILWIND, - &gSideTimers[B_SIDE_PLAYER].tailwindTimer); - break; - case STARTING_STATUS_TAILWIND_OPPONENT: - effect = SetStartingSideStatus(SIDE_STATUS_TAILWIND, - B_SIDE_OPPONENT, - B_MSG_SET_TAILWIND, - B_ANIM_TAILWIND, - &gSideTimers[B_SIDE_OPPONENT].tailwindTimer); - break; - case STARTING_STATUS_RAINBOW_PLAYER: - effect = SetStartingSideStatus(SIDE_STATUS_RAINBOW, - B_SIDE_PLAYER, - B_MSG_SET_RAINBOW, - B_ANIM_RAINBOW, - &gSideTimers[B_SIDE_PLAYER].rainbowTimer); - break; - case STARTING_STATUS_RAINBOW_OPPONENT: - effect = SetStartingSideStatus(SIDE_STATUS_RAINBOW, - B_SIDE_OPPONENT, - B_MSG_SET_RAINBOW, - B_ANIM_RAINBOW, - &gSideTimers[B_SIDE_OPPONENT].rainbowTimer); - break; - case STARTING_STATUS_SEA_OF_FIRE_PLAYER: - effect = SetStartingSideStatus(SIDE_STATUS_SEA_OF_FIRE, - B_SIDE_PLAYER, - B_MSG_SET_SEA_OF_FIRE, - B_ANIM_SEA_OF_FIRE, - &gSideTimers[B_SIDE_PLAYER].seaOfFireTimer); - break; - case STARTING_STATUS_SEA_OF_FIRE_OPPONENT: - effect = SetStartingSideStatus(SIDE_STATUS_SEA_OF_FIRE, - B_SIDE_OPPONENT, - B_MSG_SET_SEA_OF_FIRE, - B_ANIM_SEA_OF_FIRE, - &gSideTimers[B_SIDE_OPPONENT].seaOfFireTimer); - break; - case STARTING_STATUS_SWAMP_PLAYER: - effect = SetStartingSideStatus(SIDE_STATUS_SWAMP, - B_SIDE_PLAYER, - B_MSG_SET_SWAMP, - B_ANIM_SWAMP, - &gSideTimers[B_SIDE_PLAYER].swampTimer); - break; - case STARTING_STATUS_SWAMP_OPPONENT: - effect = SetStartingSideStatus(SIDE_STATUS_SWAMP, - B_SIDE_OPPONENT, - B_MSG_SET_SWAMP, - B_ANIM_SWAMP, - &gSideTimers[B_SIDE_OPPONENT].swampTimer); - break; - } - - if (effect == 1) - BattleScriptPushCursorAndCallback(BattleScript_OverworldStatusStarts); - else if (effect == 2) - BattleScriptPushCursorAndCallback(BattleScript_OverworldTerrain); - } - break; - case ABILITYEFFECT_SWITCH_IN_TERRAIN: // terrain starting from overworld weather - if (B_THUNDERSTORM_TERRAIN == TRUE - && !(gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) - && GetCurrentWeather() == WEATHER_RAIN_THUNDERSTORM) - { - // overworld weather started rain, so just do electric terrain anim - gFieldStatuses = STATUS_FIELD_ELECTRIC_TERRAIN; - gFieldTimers.terrainTimer = 0; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_ELECTRIC; - BattleScriptPushCursorAndCallback(BattleScript_OverworldTerrain); - effect++; - } - else if (B_OVERWORLD_FOG >= GEN_8 - && (GetCurrentWeather() == WEATHER_FOG_HORIZONTAL || GetCurrentWeather() == WEATHER_FOG_DIAGONAL) - && !(gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)) - { - gFieldStatuses = STATUS_FIELD_MISTY_TERRAIN; - gFieldTimers.terrainTimer = 0; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_MISTY; - BattleScriptPushCursorAndCallback(BattleScript_OverworldTerrain); - effect++; - } - break; - case ABILITYEFFECT_SWITCH_IN_WEATHER: - gBattleScripting.battler = battler; - if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED)) - { - switch (GetCurrentWeather()) - { - case WEATHER_RAIN: - case WEATHER_RAIN_THUNDERSTORM: - case WEATHER_DOWNPOUR: - if (!(gBattleWeather & B_WEATHER_RAIN)) - { - gBattleWeather = B_WEATHER_RAIN_NORMAL; - gBattleScripting.animArg1 = B_ANIM_RAIN_CONTINUES; - effect++; - } - break; - case WEATHER_SANDSTORM: - if (!(gBattleWeather & B_WEATHER_SANDSTORM)) - { - gBattleWeather = B_WEATHER_SANDSTORM; - gBattleScripting.animArg1 = B_ANIM_SANDSTORM_CONTINUES; - effect++; - } - break; - case WEATHER_DROUGHT: - if (!(gBattleWeather & B_WEATHER_SUN)) - { - gBattleWeather = B_WEATHER_SUN_NORMAL; - gBattleScripting.animArg1 = B_ANIM_SUN_CONTINUES; - effect++; - } - break; - case WEATHER_SNOW: - if (!(gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW))) - { - if (B_OVERWORLD_SNOW >= GEN_9) - { - gBattleWeather = B_WEATHER_SNOW; - gBattleScripting.animArg1 = B_ANIM_SNOW_CONTINUES; - } - else - { - gBattleWeather = B_WEATHER_HAIL; - gBattleScripting.animArg1 = B_ANIM_HAIL_CONTINUES; - } - effect++; - } - break; - case WEATHER_FOG_DIAGONAL: - case WEATHER_FOG_HORIZONTAL: - if (B_OVERWORLD_FOG == GEN_4) - { - if (!(gBattleWeather & B_WEATHER_FOG)) - { - gBattleWeather = B_WEATHER_FOG; - gBattleScripting.animArg1 = B_ANIM_FOG_CONTINUES; - effect++; - } - break; - } - } - } - if (effect != 0) - { - gBattleCommunication[MULTISTRING_CHOOSER] = GetCurrentWeather(); - BattleScriptPushCursorAndCallback(BattleScript_OverworldWeatherStarts); - } - break; case ABILITYEFFECT_ON_SWITCHIN: gBattleScripting.battler = battler; switch (gLastUsedAbility) @@ -3928,7 +3985,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec case ABILITY_SLOW_START: if (!gSpecialStatuses[battler].switchInAbilityDone) { - gDisableStructs[battler].slowStartTimer = gBattleTurnCounter + 5; + gDisableStructs[battler].slowStartTimer = 5; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWITCHIN_SLOWSTART; gSpecialStatuses[battler].switchInAbilityDone = TRUE; BattleScriptPushCursorAndCallback(BattleScript_SwitchInAbilityMsg); @@ -3983,8 +4040,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec case ABILITY_ANTICIPATION: if (!gSpecialStatuses[battler].switchInAbilityDone) { - u32 types[3]; - GetBattlerTypes(battler, FALSE, types); + struct DamageContext ctx = {0}; + uq4_12_t modifier = UQ_4_12(1.0); for (i = 0; i < MAX_BATTLERS_COUNT; i++) { if (IsBattlerAlive(i) && !IsBattlerAlly(i, battler)) @@ -3995,9 +4052,14 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec enum BattleMoveEffects moveEffect = GetMoveEffect(move); moveType = GetBattleMoveType(move); - if (GetTypeModifier(moveType, types[0]) >= UQ_4_12(2.0) - || (types[0] != types[1] && GetTypeModifier(moveType, types[1]) >= UQ_4_12(2.0)) - || (types[2] != TYPE_MYSTERY && GetTypeModifier(moveType, types[2]) >= UQ_4_12(2.0)) + ctx.battlerAtk = i; + ctx.battlerDef = battler; + ctx.move = ctx.chosenMove = move; + ctx.moveType = moveType; + ctx.isAnticipation = TRUE; + modifier = CalcTypeEffectivenessMultiplier(&ctx); + + if (modifier >= UQ_4_12(2.0) || moveEffect == EFFECT_OHKO || moveEffect == EFFECT_SHEER_COLD) { @@ -4037,7 +4099,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec case ABILITY_DOWNLOAD: if (!gSpecialStatuses[battler].switchInAbilityDone) { - u32 statId, opposingBattler; + enum Stat statId; + u32 opposingBattler; u32 opposingDef = 0, opposingSpDef = 0; opposingBattler = BATTLE_OPPOSITE(battler); @@ -4061,7 +4124,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec gSpecialStatuses[battler].switchInAbilityDone = TRUE; - if (CompareStat(battler, statId, MAX_STAT_STAGE, CMP_LESS_THAN)) + if (CompareStat(battler, statId, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility)) { SET_STATCHANGER(statId, 1, FALSE); SaveBattlerAttacker(gBattlerAttacker); @@ -4127,7 +4190,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec } break; case ABILITY_DRIZZLE: - if (TryChangeBattleWeather(battler, BATTLE_WEATHER_RAIN, TRUE)) + if (TryChangeBattleWeather(battler, BATTLE_WEATHER_RAIN, gLastUsedAbility)) { BattleScriptPushCursorAndCallback(BattleScript_DrizzleActivates); effect++; @@ -4140,7 +4203,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec } break; case ABILITY_SAND_STREAM: - if (TryChangeBattleWeather(battler, BATTLE_WEATHER_SANDSTORM, TRUE)) + if (TryChangeBattleWeather(battler, BATTLE_WEATHER_SANDSTORM, gLastUsedAbility)) { BattleScriptPushCursorAndCallback(BattleScript_SandstreamActivates); effect++; @@ -4152,8 +4215,9 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec effect++; } break; + case ABILITY_ORICHALCUM_PULSE: case ABILITY_DROUGHT: - if (TryChangeBattleWeather(battler, BATTLE_WEATHER_SUN, TRUE)) + if (TryChangeBattleWeather(battler, BATTLE_WEATHER_SUN, gLastUsedAbility)) { BattleScriptPushCursorAndCallback(BattleScript_DroughtActivates); effect++; @@ -4166,12 +4230,12 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec } break; case ABILITY_SNOW_WARNING: - if (GetGenConfig(GEN_SNOW_WARNING) >= GEN_9 && TryChangeBattleWeather(battler, BATTLE_WEATHER_SNOW, TRUE)) + if (GetGenConfig(GEN_SNOW_WARNING) >= GEN_9 && TryChangeBattleWeather(battler, BATTLE_WEATHER_SNOW, gLastUsedAbility)) { BattleScriptPushCursorAndCallback(BattleScript_SnowWarningActivatesSnow); effect++; } - else if (GetGenConfig(GEN_SNOW_WARNING) < GEN_9 && TryChangeBattleWeather(battler, BATTLE_WEATHER_HAIL, TRUE)) + else if (GetGenConfig(GEN_SNOW_WARNING) < GEN_9 && TryChangeBattleWeather(battler, BATTLE_WEATHER_HAIL, gLastUsedAbility)) { BattleScriptPushCursorAndCallback(BattleScript_SnowWarningActivatesHail); effect++; @@ -4185,35 +4249,35 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec break; case ABILITY_ELECTRIC_SURGE: case ABILITY_HADRON_ENGINE: - if (TryChangeBattleTerrain(battler, STATUS_FIELD_ELECTRIC_TERRAIN, &gFieldTimers.terrainTimer)) + if (TryChangeBattleTerrain(battler, STATUS_FIELD_ELECTRIC_TERRAIN)) { BattleScriptPushCursorAndCallback(BattleScript_ElectricSurgeActivates); effect++; } break; case ABILITY_GRASSY_SURGE: - if (TryChangeBattleTerrain(battler, STATUS_FIELD_GRASSY_TERRAIN, &gFieldTimers.terrainTimer)) + if (TryChangeBattleTerrain(battler, STATUS_FIELD_GRASSY_TERRAIN)) { BattleScriptPushCursorAndCallback(BattleScript_GrassySurgeActivates); effect++; } break; case ABILITY_MISTY_SURGE: - if (TryChangeBattleTerrain(battler, STATUS_FIELD_MISTY_TERRAIN, &gFieldTimers.terrainTimer)) + if (TryChangeBattleTerrain(battler, STATUS_FIELD_MISTY_TERRAIN)) { BattleScriptPushCursorAndCallback(BattleScript_MistySurgeActivates); effect++; } break; case ABILITY_PSYCHIC_SURGE: - if (TryChangeBattleTerrain(battler, STATUS_FIELD_PSYCHIC_TERRAIN, &gFieldTimers.terrainTimer)) + if (TryChangeBattleTerrain(battler, STATUS_FIELD_PSYCHIC_TERRAIN)) { BattleScriptPushCursorAndCallback(BattleScript_PsychicSurgeActivates); effect++; } break; case ABILITY_INTIMIDATE: - if (!gSpecialStatuses[battler].switchInAbilityDone) + if (!gSpecialStatuses[battler].switchInAbilityDone && !IsOpposingSideEmpty(battler)) { SaveBattlerAttacker(gBattlerAttacker); gBattlerAttacker = battler; @@ -4225,7 +4289,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec break; case ABILITY_SUPERSWEET_SYRUP: if (!gSpecialStatuses[battler].switchInAbilityDone - && !GetBattlerPartyState(battler)->supersweetSyrup) + && !GetBattlerPartyState(battler)->supersweetSyrup + && !IsOpposingSideEmpty(battler)) { SaveBattlerAttacker(gBattlerAttacker); gBattlerAttacker = battler; @@ -4272,7 +4337,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec if (GetGenConfig(GEN_INTREPID_SWORD) == GEN_9) GetBattlerPartyState(battler)->intrepidSwordBoost = TRUE; gSpecialStatuses[battler].switchInAbilityDone = TRUE; - if (CompareStat(battler, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN)) + if (CompareStat(battler, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility)) { SET_STATCHANGER(STAT_ATK, 1, FALSE); BattleScriptPushCursorAndCallback(BattleScript_BattlerAbilityStatRaiseOnSwitchIn); @@ -4287,7 +4352,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec if (GetGenConfig(GEN_DAUNTLESS_SHIELD) == GEN_9) GetBattlerPartyState(battler)->dauntlessShieldBoost = TRUE; gSpecialStatuses[battler].switchInAbilityDone = TRUE; - if (CompareStat(battler, STAT_DEF, MAX_STAT_STAGE, CMP_LESS_THAN)) + if (CompareStat(battler, STAT_DEF, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility)) { SET_STATCHANGER(STAT_DEF, 1, FALSE); BattleScriptPushCursorAndCallback(BattleScript_BattlerAbilityStatRaiseOnSwitchIn); @@ -4297,7 +4362,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec break; case ABILITY_WIND_RIDER: if (!gSpecialStatuses[battler].switchInAbilityDone - && CompareStat(battler, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN) + && CompareStat(battler, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility) && gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_TAILWIND) { gSpecialStatuses[battler].switchInAbilityDone = TRUE; @@ -4307,21 +4372,21 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec } break; case ABILITY_DESOLATE_LAND: - if (TryChangeBattleWeather(battler, BATTLE_WEATHER_SUN_PRIMAL, TRUE)) + if (TryChangeBattleWeather(battler, BATTLE_WEATHER_SUN_PRIMAL, gLastUsedAbility)) { BattleScriptPushCursorAndCallback(BattleScript_DesolateLandActivates); effect++; } break; case ABILITY_PRIMORDIAL_SEA: - if (TryChangeBattleWeather(battler, BATTLE_WEATHER_RAIN_PRIMAL, TRUE)) + if (TryChangeBattleWeather(battler, BATTLE_WEATHER_RAIN_PRIMAL, gLastUsedAbility)) { BattleScriptPushCursorAndCallback(BattleScript_PrimordialSeaActivates); effect++; } break; case ABILITY_DELTA_STREAM: - if (TryChangeBattleWeather(battler, BATTLE_WEATHER_STRONG_WINDS, TRUE)) + if (TryChangeBattleWeather(battler, BATTLE_WEATHER_STRONG_WINDS, gLastUsedAbility)) { BattleScriptPushCursorAndCallback(BattleScript_DeltaStreamActivates); effect++; @@ -4367,13 +4432,6 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec effect++; } break; - case ABILITY_ORICHALCUM_PULSE: - if (TryChangeBattleWeather(battler, BATTLE_WEATHER_SUN, TRUE)) - { - BattleScriptPushCursorAndCallback(BattleScript_DroughtActivates); - effect++; - } - break; case ABILITY_SUPREME_OVERLORD: if (!gSpecialStatuses[battler].switchInAbilityDone) { @@ -4422,7 +4480,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec { gEffectBattler = partner; gSpecialStatuses[battler].switchInAbilityDone = TRUE; - gBattleStruct->moveDamage[partner] = (GetNonDynamaxMaxHP(partner) / 4) * -1; + SetHealAmount(partner, GetNonDynamaxMaxHP(partner) / 4); BattleScriptPushCursorAndCallback(BattleScript_HospitalityActivates); effect++; } @@ -4433,7 +4491,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec case ABILITY_EMBODY_ASPECT_CORNERSTONE_MASK: if (!gSpecialStatuses[battler].switchInAbilityDone) { - u32 stat; + enum Stat stat; if (gLastUsedAbility == ABILITY_EMBODY_ASPECT_HEARTHFLAME_MASK) stat = STAT_ATK; @@ -4444,7 +4502,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec else //ABILITY_EMBODY_ASPECT_TEAL_MASK stat = STAT_SPEED; - if (CompareStat(battler, stat, MAX_STAT_STAGE, CMP_EQUAL)) + if (CompareStat(battler, stat, MAX_STAT_STAGE, CMP_EQUAL, gLastUsedAbility)) break; gSpecialStatuses[battler].switchInAbilityDone = TRUE; @@ -4464,17 +4522,6 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec effect++; } break; - case ABILITY_ICE_FACE: - if (IsBattlerWeatherAffected(battler, B_WEATHER_HAIL | B_WEATHER_SNOW) - && gBattleMons[battler].species == SPECIES_EISCUE_NOICE - && !(gBattleMons[battler].volatiles.transformed)) - { - // TODO: Convert this to a proper FORM_CHANGE type. - gBattleMons[battler].species = SPECIES_EISCUE_ICE; - BattleScriptPushCursorAndCallback(BattleScript_BattlerFormChangeWithStringEnd3); - effect++; - } - break; case ABILITY_COMMANDER: partner = BATTLE_PARTNER(battler); if (!gSpecialStatuses[battler].switchInAbilityDone @@ -4514,7 +4561,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec && PickupHasValidTarget(battler)) { gBattlerTarget = RandomUniformExcept(RNG_PICKUP, 0, gBattlersCount - 1, CantPickupItem); - gLastUsedItem = GetUsedHeldItem(gBattlerTarget); + gLastUsedItem = GetBattlerPartyState(gBattlerTarget)->usedHeldItem; BattleScriptExecute(BattleScript_PickupActivates); effect++; } @@ -4523,9 +4570,9 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec if ((IsBattlerWeatherAffected(battler, B_WEATHER_SUN) || RandomPercentage(RNG_HARVEST, 50)) && gBattleMons[battler].item == ITEM_NONE && gBattleStruct->changedItems[battler] == ITEM_NONE // Will not inherit an item - && GetItemPocket(GetUsedHeldItem(battler)) == POCKET_BERRIES) + && GetItemPocket(GetBattlerPartyState(battler)->usedHeldItem) == POCKET_BERRIES) { - gLastUsedItem = GetUsedHeldItem(battler); + gLastUsedItem = GetBattlerPartyState(battler)->usedHeldItem; BattleScriptExecute(BattleScript_HarvestActivates); effect++; } @@ -4538,10 +4585,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec && !gBattleMons[battler].volatiles.healBlock) { BattleScriptExecute(BattleScript_IceBodyHeal); - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 16; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; - gBattleStruct->moveDamage[battler] *= -1; + SetHealAmount(battler, GetNonDynamaxMaxHP(battler) / 16); effect++; } break; @@ -4554,11 +4598,9 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec && !IsBattlerAtMaxHp(battler) && !gBattleMons[battler].volatiles.healBlock) { + s32 healAmount = gLastUsedAbility == ABILITY_RAIN_DISH ? 16 : 8; + SetHealAmount(battler, GetNonDynamaxMaxHP(battler) / healAmount); BattleScriptExecute(BattleScript_RainDishActivates); - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / (gLastUsedAbility == ABILITY_RAIN_DISH ? 16 : 8); - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; - gBattleStruct->moveDamage[battler] *= -1; effect++; } break; @@ -4599,7 +4641,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec } break; case ABILITY_SPEED_BOOST: - if (CompareStat(battler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN) && gDisableStructs[battler].isFirstTurn != 2) + if (CompareStat(battler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility) && gDisableStructs[battler].isFirstTurn != 2) { SaveBattlerAttacker(gBattlerAttacker); SET_STATCHANGER(STAT_SPEED, 1, FALSE); @@ -4616,9 +4658,9 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec for (i = STAT_ATK; i < statsNum; i++) { - if (CompareStat(battler, i, MIN_STAT_STAGE, CMP_GREATER_THAN)) + if (CompareStat(battler, i, MIN_STAT_STAGE, CMP_GREATER_THAN, gLastUsedAbility)) validToLower |= 1u << i; - if (CompareStat(battler, i, MAX_STAT_STAGE, CMP_LESS_THAN)) + if (CompareStat(battler, i, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility)) validToRaise |= 1u << i; } @@ -4643,7 +4685,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec gDisableStructs[gBattlerAttacker].truantCounter ^= 1; break; case ABILITY_SLOW_START: - if (gDisableStructs[battler].slowStartTimer == gBattleTurnCounter) + if (gDisableStructs[battler].slowStartTimer > 0 && --gDisableStructs[battler].slowStartTimer == 0) { BattleScriptExecute(BattleScript_SlowStartEnds); effect++; @@ -4657,10 +4699,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec if (IsBattlerWeatherAffected(battler, B_WEATHER_SUN)) { SOLAR_POWER_HP_DROP: + SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / 8); BattleScriptExecute(BattleScript_SolarPowerActivates); - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 8; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; effect++; } break; @@ -4725,12 +4765,12 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec { gBattleScripting.battler = battler; gDisableStructs[battler].cudChew = FALSE; - gLastUsedItem = gBattleStruct->usedHeldItems[gBattlerPartyIndexes[battler]][GetBattlerSide(battler)]; - gBattleStruct->usedHeldItems[gBattlerPartyIndexes[battler]][GetBattlerSide(battler)] = ITEM_NONE; + gLastUsedItem = GetBattlerPartyState(battler)->usedHeldItem; + GetBattlerPartyState(battler)->usedHeldItem = ITEM_NONE; BattleScriptExecute(BattleScript_CudChewActivates); effect++; } - else if (!gDisableStructs[battler].cudChew && GetItemPocket(GetUsedHeldItem(battler)) == POCKET_BERRIES) + else if (!gDisableStructs[battler].cudChew && GetItemPocket(GetBattlerPartyState(battler)->usedHeldItem) == POCKET_BERRIES) { gDisableStructs[battler].cudChew = TRUE; } @@ -4762,7 +4802,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec if (IsBattlerTurnDamaged(battler) && IsBattlerAlive(battler) && HadMoreThanHalfHpNowDoesnt(battler) - && CompareStat(battler, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN)) + && CompareStat(battler, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility)) { gEffectBattler = gBattlerAbility = battler; SET_STATCHANGER(STAT_SPATK, 1, FALSE); @@ -4787,21 +4827,11 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec case ABILITYEFFECT_MOVE_END: // Think contact abilities. switch (gLastUsedAbility) { - case ABILITY_STICKY_HOLD: - if (gBattleStruct->battlerState[gBattlerTarget].itemCanBeKnockedOff && IsBattlerAlive(gBattlerTarget)) - { - gBattleStruct->battlerState[gBattlerTarget].itemCanBeKnockedOff = FALSE; - gBattlerAbility = gBattlerTarget; - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_StickyHoldActivates; - effect++; - } - break; case ABILITY_JUSTIFIED: if (IsBattlerTurnDamaged(battler) && IsBattlerAlive(battler) && moveType == TYPE_DARK - && CompareStat(battler, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN)) + && CompareStat(battler, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility)) { gEffectBattler = gBattlerAbility = battler; SET_STATCHANGER(STAT_ATK, 1, FALSE); @@ -4813,7 +4843,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec if (IsBattlerTurnDamaged(battler) && IsBattlerAlive(battler) && (moveType == TYPE_DARK || moveType == TYPE_BUG || moveType == TYPE_GHOST) - && CompareStat(battler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN)) + && CompareStat(battler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility)) { gEffectBattler = gBattlerAbility = battler; SET_STATCHANGER(STAT_SPEED, 1, FALSE); @@ -4825,7 +4855,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec if (IsBattlerTurnDamaged(battler) && IsBattlerAlive(battler) && moveType == TYPE_WATER - && CompareStat(battler, STAT_DEF, MAX_STAT_STAGE, CMP_LESS_THAN)) + && CompareStat(battler, STAT_DEF, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility)) { gEffectBattler = gBattlerAbility = battler; SET_STATCHANGER(STAT_DEF, 2, FALSE); @@ -4837,7 +4867,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec if (gBattlerAttacker != gBattlerTarget && IsBattlerTurnDamaged(gBattlerTarget) && IsBattlerAlive(battler) - && CompareStat(battler, STAT_DEF, MAX_STAT_STAGE, CMP_LESS_THAN)) + && CompareStat(battler, STAT_DEF, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility)) { gEffectBattler = gBattlerAbility = battler; SET_STATCHANGER(STAT_DEF, 1, FALSE); @@ -4849,8 +4879,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec if (IsBattlerTurnDamaged(battler) && IsBattlerAlive(battler) && IsBattleMovePhysical(gCurrentMove) - && (CompareStat(battler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN) // Don't activate if both Speed and Defense cannot be raised. - || CompareStat(battler, STAT_DEF, MIN_STAT_STAGE, CMP_GREATER_THAN))) + && (CompareStat(battler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility) // Don't activate if both Speed and Defense cannot be raised. + || CompareStat(battler, STAT_DEF, MIN_STAT_STAGE, CMP_GREATER_THAN, gLastUsedAbility))) { if (GetMoveEffect(gCurrentMove) == EFFECT_HIT_ESCAPE && CanBattlerSwitch(gBattlerAttacker)) gProtectStructs[battler].disableEjectPack = TRUE; // Set flag for target @@ -4864,8 +4894,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec && gDisableStructs[gBattlerAttacker].disabledMove == MOVE_NONE && IsBattlerAlive(gBattlerAttacker) && !IsAbilityOnSide(gBattlerAttacker, ABILITY_AROMA_VEIL) - && gBattleMons[gBattlerAttacker].pp[gChosenMovePos] != 0 - && !(GetActiveGimmick(gBattlerAttacker) == GIMMICK_DYNAMAX) // TODO: Max Moves don't make contact, useless? + && gChosenMove != MOVE_STRUGGLE && RandomPercentage(RNG_CURSED_BODY, 30)) { gDisableStructs[gBattlerAttacker].disabledMove = gChosenMove; @@ -4930,7 +4959,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec if (gSpecialStatuses[battler].criticalHit && IsBattlerTurnDamaged(battler) && IsBattlerAlive(battler) - && CompareStat(battler, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN)) + && CompareStat(battler, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility)) { SET_STATCHANGER(STAT_ATK, MAX_STAT_STAGE - gBattleMons[battler].statStages[STAT_ATK], FALSE); BattleScriptCall(BattleScript_TargetsStatWasMaxedOut); @@ -4940,7 +4969,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec case ABILITY_GOOEY: case ABILITY_TANGLING_HAIR: if (IsBattlerAlive(gBattlerAttacker) - && (CompareStat(gBattlerAttacker, STAT_SPEED, MIN_STAT_STAGE, CMP_GREATER_THAN) || GetBattlerAbility(gBattlerAttacker) == ABILITY_MIRROR_ARMOR) + && (CompareStat(gBattlerAttacker, STAT_SPEED, MIN_STAT_STAGE, CMP_GREATER_THAN, gLastUsedAbility) || GetBattlerAbility(gBattlerAttacker) == ABILITY_MIRROR_ARMOR) && !gProtectStructs[gBattlerAttacker].confusionSelfDmg && IsBattlerTurnDamaged(gBattlerTarget) && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), move)) @@ -4948,7 +4977,6 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec SET_STATCHANGER(STAT_SPEED, 1, TRUE); PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility); BattleScriptCall(BattleScript_GooeyActivates); - gHitMarker |= HITMARKER_STATUS_ABILITY_EFFECT; effect++; } break; @@ -4959,9 +4987,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec && IsBattlerTurnDamaged(gBattlerTarget) && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), move)) { - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / (B_ROUGH_SKIN_DMG >= GEN_4 ? 8 : 16); - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; + SetPassiveDamageAmount(gBattlerAttacker, GetNonDynamaxMaxHP(gBattlerAttacker) / (B_ROUGH_SKIN_DMG >= GEN_4 ? 8 : 16)); PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility); BattleScriptCall(BattleScript_RoughSkinActivates); effect++; @@ -4981,9 +5007,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec else { gBattleScripting.battler = gBattlerTarget; - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 4; - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; + SetPassiveDamageAmount(gBattlerAttacker, GetNonDynamaxMaxHP(gBattlerAttacker) / 4); BattleScriptCall(BattleScript_AftermathDmg); } effect++; @@ -4999,7 +5023,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec break; gBattleScripting.battler = gBattlerTarget; - gBattleStruct->moveDamage[gBattlerAttacker] = gBattleStruct->moveDamage[gBattlerTarget]; + SetPassiveDamageAmount(gBattlerAttacker, gBattleStruct->moveDamage[gBattlerTarget]); BattleScriptCall(BattleScript_AftermathDmg); effect++; } @@ -5007,9 +5031,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec case ABILITY_EFFECT_SPORE: { enum Ability abilityAtk = GetBattlerAbility(gBattlerAttacker); - if ((!IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GRASS) || B_POWDER_GRASS < GEN_6) - && abilityAtk != ABILITY_OVERCOAT - && GetBattlerHoldEffect(gBattlerAttacker) != HOLD_EFFECT_SAFETY_GOGGLES) + enum HoldEffect holdEffectAtk = GetBattlerHoldEffect(gBattlerAttacker); + if (IsAffectedByPowderMove(gBattlerAttacker, abilityAtk, holdEffectAtk)) { u32 poison, paralysis, sleep; @@ -5036,7 +5059,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec && !gProtectStructs[gBattlerAttacker].confusionSelfDmg && IsBattlerTurnDamaged(gBattlerTarget) && CanBeSlept(gBattlerTarget, gBattlerAttacker, abilityAtk, NOT_BLOCKED_BY_SLEEP_CLAUSE) - && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), move)) + && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, abilityAtk, holdEffectAtk, move)) { if (IsSleepClauseEnabled()) gBattleStruct->battlerState[gBattlerAttacker].sleepClauseEffectExempt = TRUE; @@ -5148,7 +5171,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec case ABILITY_STEAM_ENGINE: if (IsBattlerTurnDamaged(gBattlerTarget) && IsBattlerAlive(battler) - && CompareStat(battler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN) + && CompareStat(battler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility) && (moveType == TYPE_FIRE || moveType == TYPE_WATER)) { gEffectBattler = gBattlerAbility = battler; @@ -5167,7 +5190,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec BattleScriptCall(BattleScript_BlockedByPrimalWeatherRet); effect++; } - else if (TryChangeBattleWeather(battler, BATTLE_WEATHER_SANDSTORM, TRUE)) + else if (TryChangeBattleWeather(battler, BATTLE_WEATHER_SANDSTORM, gLastUsedAbility)) { gBattleScripting.battler = battler; BattleScriptCall(BattleScript_SandSpitActivates); @@ -5199,12 +5222,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec && IsBattlerAlive(gBattlerAttacker) && gBattleMons[gBattlerTarget].species != SPECIES_CRAMORANT) { - if (GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD) - { - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 4; - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; - } + if (!IsAbilityAndRecord(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), ABILITY_MAGIC_GUARD)) + SetPassiveDamageAmount(gBattlerAttacker, GetNonDynamaxMaxHP(gBattlerAttacker) / 4); switch(gBattleMons[gBattlerTarget].species) { @@ -5225,7 +5244,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec if (!gProtectStructs[gBattlerAttacker].confusionSelfDmg && IsBattlerTurnDamaged(gBattlerTarget) && IsBattlerAlive(gBattlerTarget) - && TryChangeBattleTerrain(gBattlerTarget, STATUS_FIELD_GRASSY_TERRAIN, &gFieldTimers.terrainTimer)) + && TryChangeBattleTerrain(gBattlerTarget, STATUS_FIELD_GRASSY_TERRAIN)) { BattleScriptCall(BattleScript_SeedSowerActivates); effect++; @@ -5234,7 +5253,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec case ABILITY_THERMAL_EXCHANGE: if (IsBattlerTurnDamaged(gBattlerTarget) && IsBattlerAlive(gBattlerTarget) - && CompareStat(gBattlerTarget, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN) + && CompareStat(gBattlerTarget, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility) && moveType == TYPE_FIRE) { gEffectBattler = gBattlerAbility = gBattlerTarget; @@ -5263,7 +5282,10 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec && IsBattlerTurnDamaged(gBattlerTarget) && (gSideTimers[GetBattlerSide(gBattlerAttacker)].toxicSpikesAmount != 2)) { - SWAP(gBattlerAttacker, gBattlerTarget, i); + SaveBattlerTarget(gBattlerTarget); + SaveBattlerAttacker(gBattlerAttacker); + gBattlerAttacker = gBattlerTarget; + gBattlerTarget = BATTLE_OPPOSITE(gBattlerAttacker); BattleScriptCall(BattleScript_ToxicDebrisActivates); effect++; } @@ -5310,10 +5332,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec && IsBattlerTurnDamaged(gBattlerTarget) && !MoveHasAdditionalEffect(gCurrentMove, MOVE_EFFECT_FLINCH)) { - gBattleScripting.moveEffect = MOVE_EFFECT_FLINCH; - BattleScriptPushCursor(); - SetMoveEffect(gBattlerAttacker, gBattlerTarget, FALSE, FALSE); - BattleScriptPop(); + SetMoveEffect(gBattlerAttacker, gBattlerTarget, MOVE_EFFECT_FLINCH, gBattlescriptCurrInstr, EFFECT_PRIMARY); effect++; } break; @@ -5336,7 +5355,6 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec gBattleScripting.moveEffect = MOVE_EFFECT_CONFUSION; PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility); BattleScriptCall(BattleScript_AbilityStatusEffect); - gHitMarker |= HITMARKER_STATUS_ABILITY_EFFECT; effect++; } break; @@ -5395,96 +5413,12 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec } break; case ABILITYEFFECT_IMMUNITY: - for (battler = 0; battler < gBattlersCount; battler++) - { - switch (GetBattlerAbilityIgnoreMoldBreaker(battler)) - { - case ABILITY_IMMUNITY: - case ABILITY_PASTEL_VEIL: - if (gBattleMons[battler].status1 & (STATUS1_POISON | STATUS1_TOXIC_POISON | STATUS1_TOXIC_COUNTER)) - { - StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn); - effect = 1; - } - break; - case ABILITY_OWN_TEMPO: - if (gBattleMons[battler].volatiles.confusionTurns > 0) - { - StringCopy(gBattleTextBuff1, gStatusConditionString_ConfusionJpn); - effect = 2; - } - break; - case ABILITY_LIMBER: - if (gBattleMons[battler].status1 & STATUS1_PARALYSIS) - { - StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn); - effect = 1; - } - break; - case ABILITY_INSOMNIA: - case ABILITY_VITAL_SPIRIT: - if (gBattleMons[battler].status1 & STATUS1_SLEEP) - { - TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]); - gBattleMons[battler].volatiles.nightmare = FALSE; - StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn); - effect = 1; - } - break; - case ABILITY_WATER_VEIL: - case ABILITY_WATER_BUBBLE: - case ABILITY_THERMAL_EXCHANGE: - if (gBattleMons[battler].status1 & STATUS1_BURN) - { - StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn); - effect = 1; - } - break; - case ABILITY_MAGMA_ARMOR: - if (gBattleMons[battler].status1 & (STATUS1_FREEZE | STATUS1_FROSTBITE)) - { - StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn); - effect = 1; - } - break; - case ABILITY_OBLIVIOUS: - if (gBattleMons[battler].volatiles.infatuation) - effect = 3; - else if (gDisableStructs[battler].tauntTimer != 0) - effect = 4; - break; - default: - break; - } - - if (effect != 0) - { - switch (effect) - { - case 1: // status cleared - gBattleMons[battler].status1 = 0; - BattleScriptCall(BattleScript_AbilityCuredStatus); - break; - case 2: // get rid of confusion - RemoveConfusionStatus(battler); - BattleScriptCall(BattleScript_AbilityCuredStatus); - break; - case 3: // get rid of infatuation - gBattleMons[battler].volatiles.infatuation = 0; - BattleScriptCall(BattleScript_BattlerGotOverItsInfatuation); - break; - case 4: // get rid of taunt - gDisableStructs[battler].tauntTimer = 0; - BattleScriptCall(BattleScript_BattlerShookOffTaunt); - break; - } - - gBattleScripting.battler = gBattlerAbility = battler; - BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battler].status1); - MarkBattlerForControllerExec(battler); - return effect; - } - } + effect = TryImmunityAbilityHealStatus(battler, caseID); + if (effect) + return effect; + break; + case ABILITYEFFECT_ON_SWITCHIN_IMMUNITIES: + effect = TryImmunityAbilityHealStatus(battler, caseID); break; case ABILITYEFFECT_SYNCHRONIZE: if (gLastUsedAbility == ABILITY_SYNCHRONIZE && gBattleStruct->synchronizeMoveEffect != MOVE_EFFECT_NONE) @@ -5571,33 +5505,22 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec { case ABILITY_FORECAST: case ABILITY_FLOWER_GIFT: - if ((IsBattlerWeatherAffected(battler, gBattleWeather) + case ABILITY_ICE_FACE: + { + u32 battlerWeatherAffected = IsBattlerWeatherAffected(battler, gBattleWeather); + if (battlerWeatherAffected && !CanBattlerFormChange(battler, FORM_CHANGE_BATTLE_WEATHER)) + { + // If Hail/Snow activates when in Eiscue is in base, prevent reversion when Eiscue Noice gets broken + gDisableStructs[battler].weatherAbilityDone = TRUE; + } + + if (((!gDisableStructs[battler].weatherAbilityDone && battlerWeatherAffected) || gBattleWeather == B_WEATHER_NONE || !HasWeatherEffect()) // Air Lock active && TryBattleFormChange(battler, FORM_CHANGE_BATTLE_WEATHER)) { gBattleScripting.battler = battler; - BattleScriptPushCursorAndCallback(BattleScript_BattlerFormChangeWithStringEnd3); - effect++; - } - break; - case ABILITY_ICE_FACE: - { - u32 battlerWeatherAffected = IsBattlerWeatherAffected(battler, B_WEATHER_HAIL | B_WEATHER_SNOW); - if (battlerWeatherAffected && gBattleMons[battler].species == SPECIES_EISCUE) - { - // If Hail/Snow activates when in Eiscue is in base, prevent reversion when Eiscue Noice gets broken gDisableStructs[battler].weatherAbilityDone = TRUE; - } - if (!gDisableStructs[battler].weatherAbilityDone - && battlerWeatherAffected - && gBattleMons[battler].species == SPECIES_EISCUE_NOICE - && !(gBattleMons[battler].volatiles.transformed)) - { - // TODO: Convert this to a proper FORM_CHANGE type. - gBattleScripting.battler = battler; - gDisableStructs[battler].weatherAbilityDone = TRUE; - gBattleMons[battler].species = SPECIES_EISCUE_ICE; BattleScriptPushCursorAndCallback(BattleScript_BattlerFormChangeWithStringEnd3); effect++; } @@ -5868,7 +5791,7 @@ void BattleScriptPushCursorAndCallback(const u8 *BS_ptr) gBattleMainFunc = RunBattleScriptCommands; } -bool32 IsBattlerTerrainAffected(u32 battler, enum Ability ability, enum ItemHoldEffect holdEffect, u32 terrainFlag) +bool32 IsBattlerTerrainAffected(u32 battler, enum Ability ability, enum HoldEffect holdEffect, u32 terrainFlag) { if (!(gFieldStatuses & terrainFlag)) return FALSE; @@ -6003,7 +5926,7 @@ bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, enum Ability abil { battleScript = BattleScript_AlreadyParalyzed; } - else if (B_PARALYZE_ELECTRIC >= GEN_6 && IS_BATTLER_OF_TYPE(battlerDef, TYPE_ELECTRIC)) + else if (GetGenConfig(GEN_CONFIG_PARALYZE_ELECTRIC) >= GEN_6 && IS_BATTLER_OF_TYPE(battlerDef, TYPE_ELECTRIC)) { battleScript = BattleScript_NotAffected; } @@ -6094,7 +6017,6 @@ bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, enum Ability abil // Checks that apply to all non volatile statuses if (abilityDef == ABILITY_COMATOSE - || abilityDef == ABILITY_SHIELDS_DOWN || abilityDef == ABILITY_PURIFYING_SALT) { abilityAffected = TRUE; @@ -6109,6 +6031,11 @@ bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, enum Ability abil abilityAffected = TRUE; battleScript = BattleScript_AbilityProtectsDoesntAffect; } + else if (IsShieldsDownProtected(battlerDef, abilityDef)) + { + abilityAffected = TRUE; + battleScript = BattleScript_AbilityProtectsDoesntAffect; + } else if ((sideBattler = IsFlowerVeilProtected(battlerDef))) { abilityAffected = TRUE; @@ -6186,21 +6113,16 @@ bool32 CanBeConfused(u32 battler) } // second argument is 1/X of current hp compared to max hp -bool32 HasEnoughHpToEatBerry(u32 battler, u32 hpFraction, u32 itemId) +bool32 HasEnoughHpToEatBerry(u32 battler, enum Ability ability, u32 hpFraction, u32 itemId) { - bool32 isBerry = (GetItemPocket(itemId) == POCKET_BERRIES); - if (!IsBattlerAlive(battler)) return FALSE; if (gBattleScripting.overrideBerryRequirements) return TRUE; - // Unnerve prevents consumption of opponents' berries. - if (isBerry && IsUnnerveAbilityOnOpposingSide(battler)) - return FALSE; if (gBattleMons[battler].hp <= gBattleMons[battler].maxHP / hpFraction) return TRUE; - if (hpFraction <= 4 && isBerry + if (hpFraction <= 4 && GetItemPocket(itemId) == POCKET_BERRIES && gBattleMons[battler].hp <= gBattleMons[battler].maxHP / 2 && IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_GLUTTONY)) return TRUE; @@ -6208,1451 +6130,6 @@ bool32 HasEnoughHpToEatBerry(u32 battler, u32 hpFraction, u32 itemId) return FALSE; } -static enum ItemEffect HealConfuseBerry(u32 battler, u32 itemId, u32 flavorId, enum ItemCaseId caseID) -{ - if (HasEnoughHpToEatBerry(battler, (B_CONFUSE_BERRIES_HEAL >= GEN_7 ? 4 : 2), itemId) - && (B_HEAL_BLOCKING < GEN_5 || !gBattleMons[battler].volatiles.healBlock)) - { - PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, flavorId); - - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / GetBattlerItemHoldEffectParam(battler, itemId); - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; - gBattleStruct->moveDamage[battler] *= -1; - - if (GetBattlerAbility(battler) == ABILITY_RIPEN) - { - gBattleStruct->moveDamage[battler] *= 2; - gBattlerAbility = battler; - } - gBattleScripting.battler = battler; - if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN || caseID == ITEMEFFECT_NORMAL) - { - if (GetFlavorRelationByPersonality(gBattleMons[battler].personality, flavorId) < 0) - BattleScriptExecute(BattleScript_BerryConfuseHealEnd2); - else - BattleScriptExecute(BattleScript_ItemHealHP_RemoveItemEnd2); - } - else - { - if (GetFlavorRelationByPersonality(gBattleMons[battler].personality, flavorId) < 0) - BattleScriptCall(BattleScript_BerryConfuseHealRet); - else - BattleScriptCall(BattleScript_ItemHealHP_RemoveItemRet); - } - - return ITEM_HP_CHANGE; - } - return ITEM_NO_EFFECT; -} - -static enum ItemEffect StatRaiseBerry(u32 battler, u32 itemId, u32 statId, enum ItemCaseId caseID) -{ - if (CompareStat(battler, statId, MAX_STAT_STAGE, CMP_LESS_THAN) && HasEnoughHpToEatBerry(battler, GetBattlerItemHoldEffectParam(battler, itemId), itemId)) - { - gEffectBattler = gBattleScripting.battler = battler; - if (GetBattlerAbility(battler) == ABILITY_RIPEN) - SET_STATCHANGER(statId, 2, FALSE); - else - SET_STATCHANGER(statId, 1, FALSE); - - gBattleScripting.animArg1 = STAT_ANIM_PLUS1 + statId; - gBattleScripting.animArg2 = 0; - - if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN || caseID == ITEMEFFECT_NORMAL) - BattleScriptExecute(BattleScript_ConsumableStatRaiseEnd2); - else - BattleScriptCall(BattleScript_ConsumableStatRaiseRet); - return ITEM_STATS_CHANGE; - } - return ITEM_NO_EFFECT; -} - -static enum ItemEffect RandomStatRaiseBerry(u32 battler, u32 itemId, enum ItemCaseId caseID) -{ - s32 stat; - - for (stat = STAT_ATK; stat < NUM_STATS; stat++) - { - if (CompareStat(battler, stat, MAX_STAT_STAGE, CMP_LESS_THAN)) - break; - } - if (stat != NUM_STATS && HasEnoughHpToEatBerry(battler, GetBattlerItemHoldEffectParam(battler, itemId), itemId)) - { - enum Ability battlerAbility = GetBattlerAbility(battler); - u32 savedAttacker = gBattlerAttacker; - // MoodyCantRaiseStat requires that the battler is set to gBattlerAttacker - gBattlerAttacker = gBattleScripting.battler = battler; - gBattleScripting.statChanger = 0; - if (battlerAbility != ABILITY_CONTRARY) - stat = RandomUniformExcept(RNG_RANDOM_STAT_UP, STAT_ATK, NUM_STATS - 1, MoodyCantRaiseStat); - else - stat = RandomUniformExcept(RNG_RANDOM_STAT_UP, STAT_ATK, NUM_STATS - 1, MoodyCantLowerStat); - gBattlerAttacker = savedAttacker; - - PREPARE_STAT_BUFFER(gBattleTextBuff1, stat); - gEffectBattler = battler; - if (battlerAbility == ABILITY_RIPEN) - SET_STATCHANGER(stat, 4, FALSE); - else - SET_STATCHANGER(stat, 2, FALSE); - - gBattleScripting.animArg1 = STAT_ANIM_PLUS2 + stat; - gBattleScripting.animArg2 = 0; - if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN || caseID == ITEMEFFECT_NORMAL) - BattleScriptExecute(BattleScript_ConsumableStatRaiseEnd2); - else - BattleScriptCall(BattleScript_ConsumableStatRaiseRet); - return ITEM_STATS_CHANGE; - } - return ITEM_NO_EFFECT; -} - -static enum ItemEffect TrySetMicleBerry(u32 battler, u32 itemId, enum ItemCaseId caseID) -{ - if (HasEnoughHpToEatBerry(battler, 4, itemId)) - { - gBattleStruct->battlerState[battler].usedMicleBerry = TRUE; - if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN || caseID == ITEMEFFECT_NORMAL) - { - BattleScriptExecute(BattleScript_MicleBerryActivateEnd2); - } - else - { - BattleScriptCall(BattleScript_MicleBerryActivateRet); - } - return ITEM_EFFECT_OTHER; - } - return ITEM_NO_EFFECT; -} - -static enum ItemEffect TrySetEnigmaBerry(u32 battler) -{ - if (IsBattlerAlive(battler) - && !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) - && ((IsBattlerTurnDamaged(battler) && gBattleStruct->moveResultFlags[battler] & MOVE_RESULT_SUPER_EFFECTIVE) || gBattleScripting.overrideBerryRequirements) - && !(gBattleScripting.overrideBerryRequirements && gBattleMons[battler].hp == gBattleMons[battler].maxHP) - && (B_HEAL_BLOCKING < GEN_5 || !gBattleMons[battler].volatiles.healBlock)) - { - gBattleScripting.battler = battler; - gBattleStruct->moveDamage[battler] = (gBattleMons[battler].maxHP * 25 / 100) * -1; - if (GetBattlerAbility(battler) == ABILITY_RIPEN) - gBattleStruct->moveDamage[battler] *= 2; - - BattleScriptCall(BattleScript_ItemHealHP_RemoveItemRet); - return ITEM_HP_CHANGE; - } - return ITEM_NO_EFFECT; -} - -static enum ItemEffect DamagedStatBoostBerryEffect(u32 battler, u8 statId, enum DamageCategory category) -{ - if (IsBattlerAlive(battler) - && CompareStat(battler, statId, MAX_STAT_STAGE, CMP_LESS_THAN) - && (gBattleScripting.overrideBerryRequirements - || (!DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) - && GetBattleMoveCategory(gCurrentMove) == category - && battler != gBattlerAttacker - && IsBattlerTurnDamaged(battler))) - ) - { - gEffectBattler = battler; - if (GetBattlerAbility(battler) == ABILITY_RIPEN) - SET_STATCHANGER(statId, 2, FALSE); - else - SET_STATCHANGER(statId, 1, FALSE); - - gBattleScripting.battler = battler; - gBattleScripting.animArg1 = STAT_ANIM_PLUS1 + statId; - gBattleScripting.animArg2 = 0; - BattleScriptCall(BattleScript_ConsumableStatRaiseRet); - return ITEM_STATS_CHANGE; - } - return ITEM_NO_EFFECT; -} - -enum ItemEffect TryHandleSeed(u32 battler, u32 terrainFlag, u32 statId, u32 itemId, enum ItemCaseId caseID) -{ - if (gFieldStatuses & terrainFlag && CompareStat(battler, statId, MAX_STAT_STAGE, CMP_LESS_THAN)) - { - gLastUsedItem = itemId; // For surge abilities - gEffectBattler = gBattleScripting.battler = battler; - SET_STATCHANGER(statId, 1, FALSE); - gBattleScripting.animArg1 = STAT_ANIM_PLUS1 + statId; - gBattleScripting.animArg2 = 0; - if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN) - BattleScriptExecute(BattleScript_ConsumableStatRaiseEnd2); - else - BattleScriptCall(BattleScript_ConsumableStatRaiseRet); - return ITEM_STATS_CHANGE; - } - return ITEM_NO_EFFECT; -} - -static enum ItemEffect ConsumeBerserkGene(u32 battler, enum ItemCaseId caseID) -{ - if (CanBeInfinitelyConfused(battler)) - gBattleMons[battler].volatiles.infiniteConfusion = TRUE; - - gBattlerAttacker = gEffectBattler = battler; - SET_STATCHANGER(STAT_ATK, 2, FALSE); - gBattleScripting.animArg1 = STAT_ANIM_PLUS1 + STAT_ATK; - gBattleScripting.animArg2 = 0; - if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN || caseID == ITEMEFFECT_NORMAL) - BattleScriptExecute(BattleScript_BerserkGeneRetEnd2); - else - BattleScriptCall(BattleScript_BerserkGeneRet); - return ITEM_STATS_CHANGE; -} - -static u32 ItemRestorePp(u32 battler, u32 itemId, enum ItemCaseId caseID) -{ - struct Pokemon *mon = GetBattlerMon(battler); - u32 i, changedPP = 0; - - for (i = 0; i < MAX_MON_MOVES; i++) - { - u32 move = GetMonData(mon, MON_DATA_MOVE1 + i); - u32 currentPP = GetMonData(mon, MON_DATA_PP1 + i); - u32 ppBonuses = GetMonData(mon, MON_DATA_PP_BONUSES); - u32 maxPP = CalculatePPWithBonus(move, ppBonuses, i); - if (move && (currentPP == 0 || (gBattleScripting.overrideBerryRequirements && currentPP != maxPP))) - { - u32 ppRestored = GetBattlerItemHoldEffectParam(battler, itemId); - - if (GetBattlerAbility(battler) == ABILITY_RIPEN) - { - ppRestored *= 2; - gBattlerAbility = battler; - } - if (currentPP + ppRestored > maxPP) - changedPP = maxPP; - else - changedPP = currentPP + ppRestored; - - PREPARE_MOVE_BUFFER(gBattleTextBuff1, move); - - if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN || caseID == ITEMEFFECT_NORMAL) - BattleScriptExecute(BattleScript_BerryPPHealEnd2); - else - BattleScriptCall(BattleScript_BerryPPHealRet); - - gBattleScripting.battler = battler; - BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, i + REQUEST_PPMOVE1_BATTLE, 0, 1, &changedPP); - MarkBattlerForControllerExec(battler); - if (MOVE_IS_PERMANENT(battler, i)) - gBattleMons[battler].pp[i] = changedPP; - return ITEM_PP_CHANGE; - } - } - return 0; -} - -static u32 ItemHealHp(u32 battler, u32 itemId, enum ItemCaseId caseID, bool32 percentHeal) -{ - if (!(gBattleScripting.overrideBerryRequirements && gBattleMons[battler].hp == gBattleMons[battler].maxHP) - && (B_HEAL_BLOCKING < GEN_5 || !gBattleMons[battler].volatiles.healBlock) - && HasEnoughHpToEatBerry(battler, 2, itemId)) - { - if (percentHeal) - gBattleStruct->moveDamage[battler] = (GetNonDynamaxMaxHP(battler) * GetBattlerItemHoldEffectParam(battler, itemId) / 100) * -1; - else - gBattleStruct->moveDamage[battler] = GetBattlerItemHoldEffectParam(battler, itemId) * -1; - - // check ripen - if (GetItemPocket(itemId) == POCKET_BERRIES && GetBattlerAbility(battler) == ABILITY_RIPEN) - gBattleStruct->moveDamage[battler] *= 2; - - gBattlerAbility = battler; // in SWSH, berry juice shows ability pop up but has no effect. This is mimicked here - if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN || caseID == ITEMEFFECT_NORMAL) - BattleScriptExecute(BattleScript_ItemHealHP_RemoveItemEnd2); - else - BattleScriptCall(BattleScript_ItemHealHP_RemoveItemRet); - - return ITEM_HP_CHANGE; - } - return 0; -} - -static bool32 UnnerveOn(u32 battler, u32 itemId) -{ - if (gBattleScripting.overrideBerryRequirements > 0) // Berries that aren't eaten naturally ignore unnerve - return FALSE; - - if (GetItemPocket(itemId) == POCKET_BERRIES && IsUnnerveAbilityOnOpposingSide(battler)) - return TRUE; - return FALSE; -} - -static bool32 GetMentalHerbEffect(u32 battler) -{ - bool32 ret = FALSE; - - // Check infatuation - if (gBattleMons[battler].volatiles.infatuation) - { - gBattleMons[battler].volatiles.infatuation = 0; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_INFATUATION; // STRINGID_TARGETGOTOVERINFATUATION - StringCopy(gBattleTextBuff1, gStatusConditionString_LoveJpn); - ret = TRUE; - } - if (B_MENTAL_HERB >= GEN_5) - { - // Check taunt - if (gDisableStructs[battler].tauntTimer != 0) - { - gDisableStructs[battler].tauntTimer = 0; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_TAUNT; - PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_TAUNT); - ret = TRUE; - } - // Check encore - if (gDisableStructs[battler].encoreTimer != 0) - { - gDisableStructs[battler].encoredMove = 0; - gDisableStructs[battler].encoreTimer = 0; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_ENCORE; // STRINGID_PKMNENCOREENDED - ret = TRUE; - } - // Check torment - if (gBattleMons[battler].volatiles.torment == TRUE) - { - gBattleMons[battler].volatiles.torment = FALSE; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_TORMENT; - ret = TRUE; - } - // Check heal block - if (gBattleMons[battler].volatiles.healBlock) - { - gBattleMons[battler].volatiles.healBlock = FALSE; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_HEALBLOCK; - ret = TRUE; - } - // Check disable - if (gDisableStructs[battler].disableTimer != 0) - { - gDisableStructs[battler].disableTimer = 0; - gDisableStructs[battler].disabledMove = 0; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_DISABLE; - ret = TRUE; - } - } - return ret; -} - -static u32 TryConsumeMirrorHerb(u32 battler, enum ItemCaseId caseID) -{ - u32 effect = 0; - - if (gProtectStructs[battler].eatMirrorHerb) - { - gLastUsedItem = gBattleMons[battler].item; - gBattleScripting.battler = battler; - gProtectStructs[battler].eatMirrorHerb = 0; - ChooseStatBoostAnimation(battler); - if (caseID == ITEMEFFECT_MIRROR_HERB_FIRST_TURN) - BattleScriptExecute(BattleScript_MirrorHerbCopyStatChangeEnd2); - else - BattleScriptCall(BattleScript_MirrorHerbCopyStatChange); - effect = ITEM_STATS_CHANGE; - } - return effect; -} - -u32 TryBoosterEnergy(u32 battler, enum Ability ability, enum ItemCaseId caseID) -{ - if (gDisableStructs[battler].boosterEnergyActivated || gBattleMons[battler].volatiles.transformed) - return ITEM_NO_EFFECT; - - if (((ability == ABILITY_PROTOSYNTHESIS) && !((gBattleWeather & B_WEATHER_SUN) && HasWeatherEffect())) - || ((ability == ABILITY_QUARK_DRIVE) && !(gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN))) - { - PREPARE_STAT_BUFFER(gBattleTextBuff1, GetHighestStatId(battler)); - gBattlerAbility = gBattleScripting.battler = battler; - gDisableStructs[battler].boosterEnergyActivated = TRUE; - gLastUsedItem = ITEM_BOOSTER_ENERGY; - RecordAbilityBattle(battler, ability); - if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN || caseID == ITEMEFFECT_NORMAL) - BattleScriptExecute(BattleScript_BoosterEnergyEnd2); - else - BattleScriptCall(BattleScript_BoosterEnergyRet); - return ITEM_EFFECT_OTHER; - } - - return ITEM_NO_EFFECT; -} - -static u32 RestoreWhiteHerbStats(u32 battler, enum ItemCaseId caseID) -{ - u32 i, effect = 0; - - for (i = 0; i < NUM_BATTLE_STATS; i++) - { - if (gBattleMons[battler].statStages[i] < DEFAULT_STAT_STAGE) - { - gBattleMons[battler].statStages[i] = DEFAULT_STAT_STAGE; - effect = ITEM_STATS_CHANGE; - } - } - if (effect != 0) - { - gLastUsedItem = gBattleMons[battler].item; - gBattleScripting.battler = battler; - gPotentialItemEffectBattler = battler; - if (caseID == ITEMEFFECT_WHITE_HERB) - BattleScriptCall(BattleScript_WhiteHerbRet); - else - BattleScriptExecute(BattleScript_WhiteHerbEnd2); -} - - return effect; -} - -static u8 ItemEffectMoveEnd(u32 battler, enum ItemHoldEffect holdEffect) -{ - u8 effect = 0; - - switch (holdEffect) - { - case HOLD_EFFECT_MICLE_BERRY: - if (B_HP_BERRIES >= GEN_4) - effect = TrySetMicleBerry(battler, gLastUsedItem, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_RESTORE_HP: - if (B_HP_BERRIES >= GEN_4) - effect = ItemHealHp(battler, gLastUsedItem, ITEMEFFECT_NONE, FALSE); - break; - case HOLD_EFFECT_RESTORE_PCT_HP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = ItemHealHp(battler, gLastUsedItem, ITEMEFFECT_NONE, TRUE); - break; - case HOLD_EFFECT_RESTORE_PP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = ItemRestorePp(battler, gLastUsedItem, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_CONFUSE_SPICY: - if (B_BERRIES_INSTANT >= GEN_4) - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_SPICY, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_CONFUSE_DRY: - if (B_BERRIES_INSTANT >= GEN_4) - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_DRY, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_CONFUSE_SWEET: - if (B_BERRIES_INSTANT >= GEN_4) - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_SWEET, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_CONFUSE_BITTER: - if (B_BERRIES_INSTANT >= GEN_4) - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_BITTER, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_CONFUSE_SOUR: - if (B_BERRIES_INSTANT >= GEN_4) - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_SOUR, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_ATTACK_UP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_ATK, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_DEFENSE_UP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_DEF, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_SPEED_UP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_SPEED, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_SP_ATTACK_UP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_SPATK, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_SP_DEFENSE_UP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_SPDEF, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_ENIGMA_BERRY: // consume and heal if hit by super effective move - effect = TrySetEnigmaBerry(battler); - break; - case HOLD_EFFECT_KEE_BERRY: // consume and boost defense if used physical move - effect = DamagedStatBoostBerryEffect(battler, STAT_DEF, DAMAGE_CATEGORY_PHYSICAL); - break; - case HOLD_EFFECT_MARANGA_BERRY: // consume and boost sp. defense if used special move - effect = DamagedStatBoostBerryEffect(battler, STAT_SPDEF, DAMAGE_CATEGORY_SPECIAL); - break; - case HOLD_EFFECT_RANDOM_STAT_UP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = RandomStatRaiseBerry(battler, gLastUsedItem, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_CURE_PAR: - if (gBattleMons[battler].status1 & STATUS1_PARALYSIS && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_PARALYSIS; - BattleScriptCall(BattleScript_BerryCureParRet); - effect = ITEM_STATUS_CHANGE; - } - break; - case HOLD_EFFECT_CURE_PSN: - if (gBattleMons[battler].status1 & STATUS1_PSN_ANY && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~(STATUS1_PSN_ANY | STATUS1_TOXIC_COUNTER); - BattleScriptCall(BattleScript_BerryCurePsnRet); - effect = ITEM_STATUS_CHANGE; - } - break; - case HOLD_EFFECT_CURE_BRN: - if (gBattleMons[battler].status1 & STATUS1_BURN && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_BURN; - BattleScriptCall(BattleScript_BerryCureBrnRet); - effect = ITEM_STATUS_CHANGE; - } - break; - case HOLD_EFFECT_CURE_FRZ: - if (gBattleMons[battler].status1 & STATUS1_FREEZE && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_FREEZE; - BattleScriptCall(BattleScript_BerryCureFrzRet); - effect = ITEM_STATUS_CHANGE; - } - if (gBattleMons[battler].status1 & STATUS1_FROSTBITE && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_FROSTBITE; - BattleScriptCall(BattleScript_BerryCureFrbRet); - effect = ITEM_STATUS_CHANGE; - } - break; - case HOLD_EFFECT_CURE_SLP: - if (gBattleMons[battler].status1 & STATUS1_SLEEP && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_SLEEP; - gBattleMons[battler].volatiles.nightmare = FALSE; - BattleScriptCall(BattleScript_BerryCureSlpRet); - effect = ITEM_STATUS_CHANGE; - TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]); - } - break; - case HOLD_EFFECT_CURE_CONFUSION: - if (gBattleMons[battler].volatiles.confusionTurns > 0 && !UnnerveOn(battler, gLastUsedItem)) - { - RemoveConfusionStatus(battler); - BattleScriptCall(BattleScript_BerryCureConfusionRet); - effect = ITEM_EFFECT_OTHER; - } - break; - case HOLD_EFFECT_MENTAL_HERB: - if (GetMentalHerbEffect(battler)) - { - gBattleScripting.savedBattler = gBattlerAttacker; - gBattlerAttacker = battler; - BattleScriptCall(BattleScript_MentalHerbCureRet); - effect = ITEM_EFFECT_OTHER; - } - break; - case HOLD_EFFECT_CURE_STATUS: - if ((gBattleMons[battler].status1 & STATUS1_ANY || gBattleMons[battler].volatiles.confusionTurns > 0) && !UnnerveOn(battler, gLastUsedItem)) - { - if (gBattleMons[battler].status1 & STATUS1_PSN_ANY) - StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn); - - if (gBattleMons[battler].status1 & STATUS1_SLEEP) - { - gBattleMons[battler].volatiles.nightmare = FALSE; - StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn); - TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]); - } - - if (gBattleMons[battler].status1 & STATUS1_PARALYSIS) - StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn); - - if (gBattleMons[battler].status1 & STATUS1_BURN) - StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn); - - if (gBattleMons[battler].status1 & STATUS1_FREEZE || gBattleMons[battler].status1 & STATUS1_FROSTBITE) - StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn); - - if (gBattleMons[battler].volatiles.confusionTurns > 0) - StringCopy(gBattleTextBuff1, gStatusConditionString_ConfusionJpn); - - gBattleMons[battler].status1 = 0; - RemoveConfusionStatus(battler); - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_CURED_PROBLEM; - BattleScriptCall(BattleScript_BerryCureChosenStatusRet); - effect = ITEM_STATUS_CHANGE; - } - break; - case HOLD_EFFECT_CRITICAL_UP: // lansat berry - if (B_BERRIES_INSTANT >= GEN_4 - && !(gBattleMons[battler].volatiles.dragonCheer || gBattleMons[battler].volatiles.focusEnergy) - && HasEnoughHpToEatBerry(battler, GetBattlerItemHoldEffectParam(battler, gLastUsedItem), gLastUsedItem)) - { - gBattleMons[battler].volatiles.focusEnergy = TRUE; - gBattleScripting.battler = battler; - gPotentialItemEffectBattler = battler; - BattleScriptCall(BattleScript_BerryFocusEnergyRet); - effect = ITEM_EFFECT_OTHER; - } - break; - case HOLD_EFFECT_BERSERK_GENE: - effect = ConsumeBerserkGene(battler, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_THROAT_SPRAY: - if (IsSoundMove(gCurrentMove) - && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) - && IsBattlerAlive(gBattlerAttacker) - && IsAnyTargetAffected(gBattlerAttacker) - && CompareStat(gBattlerAttacker, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN) - && !NoAliveMonsForEitherParty()) // Don't activate if battle will end - { - gLastUsedItem = gBattleMons[gBattlerAttacker].item; - gBattleScripting.battler = gBattlerAttacker; - SET_STATCHANGER(STAT_SPATK, 1, FALSE); - effect = ITEM_STATS_CHANGE; - BattleScriptCall(BattleScript_AttackerItemStatRaise); - } - break; - default: - break; - } - - return effect; -} - -static inline bool32 TryCureStatus(u32 battler, enum ItemCaseId caseId) -{ - u32 effect = ITEM_NO_EFFECT; - u32 string = 0; - - if ((gBattleMons[battler].status1 & STATUS1_ANY || gBattleMons[battler].volatiles.confusionTurns > 0) && !UnnerveOn(battler, gLastUsedItem)) - { - if (gBattleMons[battler].status1 & STATUS1_PSN_ANY) - { - StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn); - string++; - } - if (gBattleMons[battler].status1 & STATUS1_SLEEP) - { - gBattleMons[battler].volatiles.nightmare = FALSE; - StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn); - string++; - TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]); - } - if (gBattleMons[battler].status1 & STATUS1_PARALYSIS) - { - StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn); - string++; - } - if (gBattleMons[battler].status1 & STATUS1_BURN) - { - StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn); - string++; - } - if (gBattleMons[battler].status1 & STATUS1_FREEZE || gBattleMons[battler].status1 & STATUS1_FROSTBITE) - { - StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn); - string++; - } - if (gBattleMons[battler].volatiles.confusionTurns > 0) - { - StringCopy(gBattleTextBuff1, gStatusConditionString_ConfusionJpn); - string++; - } - if (string <= 1) - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_CURED_PROBLEM; - else - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_NORMALIZED_STATUS; - gBattleMons[battler].status1 = 0; - RemoveConfusionStatus(battler); - if (caseId == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN || caseId == ITEMEFFECT_NORMAL) - BattleScriptExecute(BattleScript_BerryCureChosenStatusEnd2); - else - BattleScriptCall(BattleScript_BerryCureChosenStatusRet); - effect = ITEM_STATUS_CHANGE; - } - - return effect; -} - -// This is hacky and could potentially be improved because ideally this function wouldn't exist but there is some inconsitency with timings. -static bool32 ShouldWaitWithActivation(u32 battler, enum ItemHoldEffect holdEffect) -{ - if (holdEffect != HOLD_EFFECT_RESTORE_HP - && holdEffect != HOLD_EFFECT_RESTORE_PCT_HP - && holdEffect != HOLD_EFFECT_RESTORE_PP - && holdEffect != HOLD_EFFECT_CONFUSE_SPICY - && holdEffect != HOLD_EFFECT_CONFUSE_DRY - && holdEffect != HOLD_EFFECT_CONFUSE_SWEET - && holdEffect != HOLD_EFFECT_CONFUSE_BITTER - && holdEffect != HOLD_EFFECT_CONFUSE_SOUR) - return FALSE; - - // Restore HP berries can be knocked off - if (gBattleStruct->battlerState[battler].itemCanBeKnockedOff) - return TRUE; - - if (IsBattlerTurnDamaged(battler) - && gMultiHitCounter == 0 // Non multi hit moves don't wait for Berserk / Anger Shell activation - && IsBattlerAlive(battler) - && !TestIfSheerForceAffected(battler, gCurrentMove) - && HadMoreThanHalfHpNowDoesnt(battler)) - { - switch (GetBattlerAbility(battler)) - { - case ABILITY_BERSERK: - return CompareStat(battler, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN); - case ABILITY_ANGER_SHELL: - return TRUE; - default: - return FALSE; - } - } - - return FALSE; -} - -u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler) -{ - u32 moveType = 0; - enum ItemEffect effect = ITEM_NO_EFFECT; - enum ItemHoldEffect battlerHoldEffect = 0, atkHoldEffect = 0; - u32 atkHoldEffectParam = 0; - u32 atkItem = 0; - - if (caseID != ITEMEFFECT_USE_LAST_ITEM) - { - gLastUsedItem = gBattleMons[battler].item; - battlerHoldEffect = GetBattlerHoldEffect(battler); - } - - atkItem = gBattleMons[gBattlerAttacker].item; - atkHoldEffect = GetBattlerHoldEffect(gBattlerAttacker); - atkHoldEffectParam = GetBattlerHoldEffectParam(gBattlerAttacker); - - switch (caseID) - { - case ITEMEFFECT_NONE: - break; - case ITEMEFFECT_ON_SWITCH_IN: - case ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN: - if (!gSpecialStatuses[battler].switchInItemDone) - { - switch (battlerHoldEffect) - { - case HOLD_EFFECT_DOUBLE_PRIZE: - if (IsOnPlayerSide(battler) && !gBattleStruct->moneyMultiplierItem) - { - gBattleStruct->moneyMultiplier *= 2; - gBattleStruct->moneyMultiplierItem = 1; - } - break; - case HOLD_EFFECT_CONFUSE_SPICY: - if (B_BERRIES_INSTANT >= GEN_4) - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_SPICY, caseID); - break; - case HOLD_EFFECT_CONFUSE_DRY: - if (B_BERRIES_INSTANT >= GEN_4) - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_DRY, caseID); - break; - case HOLD_EFFECT_CONFUSE_SWEET: - if (B_BERRIES_INSTANT >= GEN_4) - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_SWEET, caseID); - break; - case HOLD_EFFECT_CONFUSE_BITTER: - if (B_BERRIES_INSTANT >= GEN_4) - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_BITTER, caseID); - break; - case HOLD_EFFECT_CONFUSE_SOUR: - if (B_BERRIES_INSTANT >= GEN_4) - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_SOUR, caseID); - break; - case HOLD_EFFECT_ATTACK_UP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_ATK, caseID); - break; - case HOLD_EFFECT_DEFENSE_UP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_DEF, caseID); - break; - case HOLD_EFFECT_SPEED_UP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_SPEED, caseID); - break; - case HOLD_EFFECT_SP_ATTACK_UP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_SPATK, caseID); - break; - case HOLD_EFFECT_SP_DEFENSE_UP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_SPDEF, caseID); - break; - case HOLD_EFFECT_CRITICAL_UP: - if (B_BERRIES_INSTANT >= GEN_4 - && !(gBattleMons[battler].volatiles.dragonCheer || gBattleMons[battler].volatiles.focusEnergy) - && HasEnoughHpToEatBerry(battler, GetBattlerItemHoldEffectParam(battler, gLastUsedItem), gLastUsedItem)) - { - gBattleMons[battler].volatiles.focusEnergy = TRUE; - gBattleScripting.battler = battler; - BattleScriptExecute(BattleScript_BerryFocusEnergyEnd2); - effect = ITEM_EFFECT_OTHER; - } - break; - case HOLD_EFFECT_RANDOM_STAT_UP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = RandomStatRaiseBerry(battler, gLastUsedItem, caseID); - break; - case HOLD_EFFECT_CURE_PAR: - if (B_BERRIES_INSTANT >= GEN_4 - && gBattleMons[battler].status1 & STATUS1_PARALYSIS - && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_PARALYSIS; - BattleScriptExecute(BattleScript_BerryCurePrlzEnd2); - effect = ITEM_STATUS_CHANGE; - } - break; - case HOLD_EFFECT_CURE_PSN: - if (B_BERRIES_INSTANT >= GEN_4 - && (gBattleMons[battler].status1 & STATUS1_PSN_ANY) - && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~(STATUS1_PSN_ANY | STATUS1_TOXIC_COUNTER); - BattleScriptExecute(BattleScript_BerryCurePsnEnd2); - effect = ITEM_STATUS_CHANGE; - } - break; - case HOLD_EFFECT_CURE_BRN: - if (B_BERRIES_INSTANT >= GEN_4 - && (gBattleMons[battler].status1 & STATUS1_BURN) - && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_BURN; - BattleScriptExecute(BattleScript_BerryCureBrnEnd2); - effect = ITEM_STATUS_CHANGE; - } - break; - case HOLD_EFFECT_CURE_FRZ: - if (B_BERRIES_INSTANT >= GEN_4 - && (gBattleMons[battler].status1 & STATUS1_FREEZE) - && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_FREEZE; - BattleScriptExecute(BattleScript_BerryCureFrzEnd2); - effect = ITEM_STATUS_CHANGE; - } - if (B_BERRIES_INSTANT >= GEN_4 - && (gBattleMons[battler].status1 & STATUS1_FROSTBITE) - && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_FROSTBITE; - BattleScriptExecute(BattleScript_BerryCureFrbEnd2); - effect = ITEM_STATUS_CHANGE; - } - break; - case HOLD_EFFECT_CURE_SLP: - if (B_BERRIES_INSTANT >= GEN_4 - && (gBattleMons[battler].status1 & STATUS1_SLEEP) - && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_SLEEP; - gBattleMons[battler].volatiles.nightmare = FALSE; - BattleScriptExecute(BattleScript_BerryCureSlpEnd2); - effect = ITEM_STATUS_CHANGE; - TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]); - } - break; - case HOLD_EFFECT_CURE_STATUS: - if (B_BERRIES_INSTANT >= GEN_4) - effect = TryCureStatus(battler, caseID); - break; - case HOLD_EFFECT_RESTORE_HP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = ItemHealHp(battler, gLastUsedItem, caseID, FALSE); - break; - case HOLD_EFFECT_RESTORE_PCT_HP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = ItemHealHp(battler, gLastUsedItem, caseID, TRUE); - break; - case HOLD_EFFECT_RESTORE_PP: - effect = ItemRestorePp(battler, gLastUsedItem, caseID); - break; - case HOLD_EFFECT_AIR_BALLOON: - effect = ITEM_EFFECT_OTHER; - gBattleScripting.battler = battler; - BattleScriptPushCursorAndCallback(BattleScript_AirBaloonMsgIn); - RecordItemEffectBattle(battler, HOLD_EFFECT_AIR_BALLOON); - break; - case HOLD_EFFECT_ROOM_SERVICE: - if (TryRoomService(battler)) - { - BattleScriptExecute(BattleScript_ConsumableStatRaiseEnd2); - effect = ITEM_STATS_CHANGE; - } - break; - case HOLD_EFFECT_SEEDS: - switch (GetBattlerHoldEffectParam(battler)) - { - case HOLD_EFFECT_PARAM_ELECTRIC_TERRAIN: - effect = TryHandleSeed(battler, STATUS_FIELD_ELECTRIC_TERRAIN, STAT_DEF, gLastUsedItem, caseID); - break; - case HOLD_EFFECT_PARAM_GRASSY_TERRAIN: - effect = TryHandleSeed(battler, STATUS_FIELD_GRASSY_TERRAIN, STAT_DEF, gLastUsedItem, caseID); - break; - case HOLD_EFFECT_PARAM_MISTY_TERRAIN: - effect = TryHandleSeed(battler, STATUS_FIELD_MISTY_TERRAIN, STAT_SPDEF, gLastUsedItem, caseID); - break; - case HOLD_EFFECT_PARAM_PSYCHIC_TERRAIN: - effect = TryHandleSeed(battler, STATUS_FIELD_PSYCHIC_TERRAIN, STAT_SPDEF, gLastUsedItem, caseID); - break; - } - break; - case HOLD_EFFECT_BERSERK_GENE: - effect = ConsumeBerserkGene(battler, caseID); - break; - case HOLD_EFFECT_BOOSTER_ENERGY: - effect = TryBoosterEnergy(battler, GetBattlerAbility(battler), caseID); - break; - default: - break; - } - if (effect != 0) - { - gSpecialStatuses[battler].switchInItemDone = TRUE; - gBattlerAttacker = gPotentialItemEffectBattler = gBattleScripting.battler = battler; - if (effect == ITEM_STATUS_CHANGE) - { - BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battler].status1); - MarkBattlerForControllerExec(battler); - } - } - } - break; - case ITEMEFFECT_LEFTOVERS: - switch (battlerHoldEffect) - { - case HOLD_EFFECT_BLACK_SLUDGE: - if (IS_BATTLER_OF_TYPE(battler, TYPE_POISON)) - { - goto LEFTOVERS; - } - else if (!IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD)) - { - gBattleScripting.battler = battler; - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 8; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; - BattleScriptExecute(BattleScript_ItemHurtEnd2); - effect = ITEM_HP_CHANGE; - RecordItemEffectBattle(battler, battlerHoldEffect); - PREPARE_ITEM_BUFFER(gBattleTextBuff1, gLastUsedItem); - } - break; - case HOLD_EFFECT_LEFTOVERS: - LEFTOVERS: - if (gBattleMons[battler].hp < gBattleMons[battler].maxHP - && (B_HEAL_BLOCKING < GEN_5 || !gBattleMons[battler].volatiles.healBlock)) - { - gBattleScripting.battler = battler; - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 16; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; - gBattleStruct->moveDamage[battler] *= -1; - BattleScriptExecute(BattleScript_ItemHealHP_End2); - effect = ITEM_HP_CHANGE; - RecordItemEffectBattle(battler, battlerHoldEffect); - } - break; - default: - break; - } - break; - case ITEMEFFECT_NORMAL: - case ITEMEFFECT_TRY_HEALING: - if (IsBattlerAlive(battler)) - { - switch (battlerHoldEffect) - { - case HOLD_EFFECT_RESTORE_HP: - effect = ItemHealHp(battler, gLastUsedItem, caseID, FALSE); - break; - case HOLD_EFFECT_RESTORE_PCT_HP: - effect = ItemHealHp(battler, gLastUsedItem, caseID, TRUE); - break; - case HOLD_EFFECT_RESTORE_PP: - effect = ItemRestorePp(battler, gLastUsedItem, caseID); - break; - case HOLD_EFFECT_CONFUSE_SPICY: - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_SPICY, caseID); - break; - case HOLD_EFFECT_CONFUSE_DRY: - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_DRY, caseID); - break; - case HOLD_EFFECT_CONFUSE_SWEET: - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_SWEET, caseID); - break; - case HOLD_EFFECT_CONFUSE_BITTER: - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_BITTER, caseID); - break; - case HOLD_EFFECT_CONFUSE_SOUR: - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_SOUR, caseID); - break; - case HOLD_EFFECT_ATTACK_UP: - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_ATK, caseID); - break; - case HOLD_EFFECT_DEFENSE_UP: - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_DEF, caseID); - break; - case HOLD_EFFECT_SPEED_UP: - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_SPEED, caseID); - break; - case HOLD_EFFECT_SP_ATTACK_UP: - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_SPATK, caseID); - break; - case HOLD_EFFECT_SP_DEFENSE_UP: - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_SPDEF, caseID); - break; - case HOLD_EFFECT_CRITICAL_UP: - if (!(gBattleMons[battler].volatiles.dragonCheer || gBattleMons[battler].volatiles.focusEnergy) - && HasEnoughHpToEatBerry(battler, GetBattlerItemHoldEffectParam(battler, gLastUsedItem), gLastUsedItem)) - { - gBattleMons[battler].volatiles.focusEnergy = TRUE; - gBattleScripting.battler = battler; - BattleScriptExecute(BattleScript_BerryFocusEnergyEnd2); - effect = ITEM_EFFECT_OTHER; - } - break; - case HOLD_EFFECT_RANDOM_STAT_UP: - effect = RandomStatRaiseBerry(battler, gLastUsedItem, caseID); - break; - case HOLD_EFFECT_CURE_PAR: - if (gBattleMons[battler].status1 & STATUS1_PARALYSIS && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_PARALYSIS; - BattleScriptExecute(BattleScript_BerryCurePrlzEnd2); - effect = ITEM_STATUS_CHANGE; - } - break; - case HOLD_EFFECT_CURE_PSN: - if (gBattleMons[battler].status1 & STATUS1_PSN_ANY && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~(STATUS1_PSN_ANY | STATUS1_TOXIC_COUNTER); - BattleScriptExecute(BattleScript_BerryCurePsnEnd2); - effect = ITEM_STATUS_CHANGE; - } - break; - case HOLD_EFFECT_CURE_BRN: - if (gBattleMons[battler].status1 & STATUS1_BURN && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_BURN; - BattleScriptExecute(BattleScript_BerryCureBrnEnd2); - effect = ITEM_STATUS_CHANGE; - } - break; - case HOLD_EFFECT_CURE_FRZ: - if (gBattleMons[battler].status1 & STATUS1_FREEZE && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_FREEZE; - BattleScriptExecute(BattleScript_BerryCureFrzEnd2); - effect = ITEM_STATUS_CHANGE; - } - if (gBattleMons[battler].status1 & STATUS1_FROSTBITE && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_FROSTBITE; - BattleScriptExecute(BattleScript_BerryCureFrbEnd2); - effect = ITEM_STATUS_CHANGE; - } - break; - case HOLD_EFFECT_CURE_SLP: - if (gBattleMons[battler].status1 & STATUS1_SLEEP && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_SLEEP; - gBattleMons[battler].volatiles.nightmare = FALSE; - BattleScriptExecute(BattleScript_BerryCureSlpEnd2); - effect = ITEM_STATUS_CHANGE; - TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]); - } - break; - case HOLD_EFFECT_CURE_CONFUSION: - if (gBattleMons[battler].volatiles.confusionTurns > 0 && !UnnerveOn(battler, gLastUsedItem)) - { - RemoveConfusionStatus(battler); - BattleScriptExecute(BattleScript_BerryCureConfusionEnd2); - effect = ITEM_EFFECT_OTHER; - } - break; - case HOLD_EFFECT_CURE_STATUS: - effect = TryCureStatus(battler, caseID); - break; - case HOLD_EFFECT_MENTAL_HERB: - if (GetMentalHerbEffect(battler)) - { - gBattleScripting.savedBattler = gBattlerAttacker; - gBattlerAttacker = battler; - BattleScriptExecute(BattleScript_MentalHerbCureEnd2); - effect = ITEM_EFFECT_OTHER; - } - break; - case HOLD_EFFECT_MICLE_BERRY: - effect = TrySetMicleBerry(battler, gLastUsedItem, caseID); - break; - case HOLD_EFFECT_BERSERK_GENE: - effect = ConsumeBerserkGene(battler, caseID); - break; - default: - break; - } - - if (effect != 0) - { - gBattlerAttacker = gPotentialItemEffectBattler = gBattleScripting.battler = battler; - if (effect == ITEM_STATUS_CHANGE) - { - BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battler].status1); - MarkBattlerForControllerExec(battler); - } - } - } - break; - case ITEMEFFECT_USE_LAST_ITEM: - effect = ItemEffectMoveEnd(battler, GetItemHoldEffect(gLastUsedItem)); - gBattleScripting.overrideBerryRequirements = 2; // to exit VARIOUS_CONSUME_BERRIES - if (effect) - { - gPotentialItemEffectBattler = gBattleScripting.battler = battler; - if (effect == ITEM_STATUS_CHANGE) - { - BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battler].status1); - MarkBattlerForControllerExec(battler); - } - break; - } - break; - case ITEMEFFECT_MOVE_END: - for (battler = 0; battler < gBattlersCount; battler++) - { - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler); - if (ShouldWaitWithActivation(battler, holdEffect)) - continue; - - gLastUsedItem = gBattleMons[battler].item; - effect = ItemEffectMoveEnd(battler, holdEffect); - if (effect) - { - gPotentialItemEffectBattler = gBattleScripting.battler = battler; - if (effect == ITEM_STATUS_CHANGE) - { - BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battler].status1); - MarkBattlerForControllerExec(battler); - } - break; - } - } - break; - case ITEMEFFECT_KINGSROCK: - // Occur on each hit of a multi-strike move - switch (atkHoldEffect) - { - case HOLD_EFFECT_FLINCH: - { - enum Ability ability = GetBattlerAbility(gBattlerAttacker); - if (B_SERENE_GRACE_BOOST >= GEN_5 && ability == ABILITY_SERENE_GRACE) - atkHoldEffectParam *= 2; - if (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_RAINBOW && gCurrentMove != MOVE_SECRET_POWER) - atkHoldEffectParam *= 2; - if (IsBattlerTurnDamaged(gBattlerTarget) - && !MoveIgnoresKingsRock(gCurrentMove) - && gBattleMons[gBattlerTarget].hp - && RandomPercentage(RNG_HOLD_EFFECT_FLINCH, atkHoldEffectParam) - && ability != ABILITY_STENCH) - { - gBattleScripting.moveEffect = MOVE_EFFECT_FLINCH; - BattleScriptPushCursor(); - SetMoveEffect(gBattlerAttacker, gBattlerTarget, FALSE, FALSE); - BattleScriptPop(); - } - } - break; - case HOLD_EFFECT_BLUNDER_POLICY: - if (gBattleStruct->blunderPolicy - && IsBattlerAlive(gBattlerAttacker) - && CompareStat(gBattlerAttacker, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN)) - { - gBattleStruct->blunderPolicy = FALSE; - gLastUsedItem = atkItem; - SET_STATCHANGER(STAT_SPEED, 2, FALSE); - effect = ITEM_STATS_CHANGE; - BattleScriptCall(BattleScript_AttackerItemStatRaise); - } - break; - default: - break; - } - break; - case ITEMEFFECT_LIFEORB_SHELLBELL: - // Occur after the final hit of a multi-strike move - switch (atkHoldEffect) - { - case HOLD_EFFECT_SHELL_BELL: - if (gBattleScripting.savedDmg > 0 - && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) - && !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT) - && gBattlerAttacker != gBattlerTarget - && !IsBattlerAtMaxHp(gBattlerAttacker) - && IsBattlerAlive(gBattlerAttacker) - && GetMoveEffect(gCurrentMove) != EFFECT_FUTURE_SIGHT - && GetMoveEffect(gCurrentMove) != EFFECT_PAIN_SPLIT - && (B_HEAL_BLOCKING < GEN_5 || !gBattleMons[battler].volatiles.healBlock)) - { - gLastUsedItem = atkItem; - gPotentialItemEffectBattler = gBattlerAttacker; - gBattleScripting.battler = gBattlerAttacker; - gBattleStruct->moveDamage[gBattlerAttacker] = (gBattleScripting.savedDmg / atkHoldEffectParam) * -1; - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = -1; - BattleScriptCall(BattleScript_ItemHealHP_Ret); - effect = ITEM_HP_CHANGE; - } - break; - case HOLD_EFFECT_LIFE_ORB: - if (IsBattlerAlive(gBattlerAttacker) - && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) - && (IsBattlerTurnDamaged(gBattlerTarget) || gBattleScripting.savedDmg > 0) - && !IsAbilityAndRecord(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), ABILITY_MAGIC_GUARD) - && !IsFutureSightAttackerInParty(gBattlerAttacker, gBattlerTarget, gCurrentMove)) - { - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 10; - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; - effect = ITEM_HP_CHANGE; - BattleScriptCall(BattleScript_ItemHurtRet); - gLastUsedItem = atkItem; - } - break; - default: - break; - } - break; - case ITEMEFFECT_TARGET: - if (!(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)) - { - moveType = GetBattleMoveType(gCurrentMove); - switch (battlerHoldEffect) - { - case HOLD_EFFECT_AIR_BALLOON: - if (IsBattlerTurnDamaged(gBattlerTarget)) - { - effect = ITEM_EFFECT_OTHER; - BattleScriptCall(BattleScript_AirBaloonMsgPop); - } - break; - case HOLD_EFFECT_ROCKY_HELMET: - if (IsBattlerTurnDamaged(gBattlerTarget) - && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), gCurrentMove) - && IsBattlerAlive(gBattlerAttacker) - && GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD) - { - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 6; - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; - effect = ITEM_HP_CHANGE; - BattleScriptCall(BattleScript_RockyHelmetActivates); - PREPARE_ITEM_BUFFER(gBattleTextBuff1, gLastUsedItem); - RecordItemEffectBattle(battler, HOLD_EFFECT_ROCKY_HELMET); - } - break; - case HOLD_EFFECT_WEAKNESS_POLICY: - if (IsBattlerAlive(battler) - && IsBattlerTurnDamaged(gBattlerTarget) - && gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_SUPER_EFFECTIVE) - { - effect = ITEM_STATS_CHANGE; - BattleScriptCall(BattleScript_WeaknessPolicy); - } - break; - case HOLD_EFFECT_SNOWBALL: - if (IsBattlerAlive(battler) - && IsBattlerTurnDamaged(gBattlerTarget) - && moveType == TYPE_ICE) - { - effect = ITEM_STATS_CHANGE; - BattleScriptCall(BattleScript_TargetItemStatRaise); - SET_STATCHANGER(STAT_ATK, 1, FALSE); - } - break; - case HOLD_EFFECT_LUMINOUS_MOSS: - if (IsBattlerAlive(battler) - && IsBattlerTurnDamaged(gBattlerTarget) - && moveType == TYPE_WATER) - { - effect = ITEM_STATS_CHANGE; - BattleScriptCall(BattleScript_TargetItemStatRaise); - SET_STATCHANGER(STAT_SPDEF, 1, FALSE); - } - break; - case HOLD_EFFECT_CELL_BATTERY: - if (IsBattlerAlive(battler) - && IsBattlerTurnDamaged(gBattlerTarget) - && moveType == TYPE_ELECTRIC) - { - effect = ITEM_STATS_CHANGE; - BattleScriptCall(BattleScript_TargetItemStatRaise); - SET_STATCHANGER(STAT_ATK, 1, FALSE); - } - break; - case HOLD_EFFECT_ABSORB_BULB: - if (IsBattlerAlive(battler) - && IsBattlerTurnDamaged(gBattlerTarget) - && moveType == TYPE_WATER) - { - effect = ITEM_STATS_CHANGE; - BattleScriptCall(BattleScript_TargetItemStatRaise); - SET_STATCHANGER(STAT_SPATK, 1, FALSE); - } - break; - case HOLD_EFFECT_ENIGMA_BERRY: // consume and heal if hit by super effective move - effect = TrySetEnigmaBerry(battler); - break; - case HOLD_EFFECT_JABOCA_BERRY: // consume and damage attacker if used physical move - if (IsBattlerAlive(gBattlerAttacker) - && IsBattlerTurnDamaged(gBattlerTarget) - && !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) - && IsBattleMovePhysical(gCurrentMove) - && GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD) - { - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 8; - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; - if (GetBattlerAbility(battler) == ABILITY_RIPEN) - gBattleStruct->moveDamage[gBattlerAttacker] *= 2; - - effect = ITEM_HP_CHANGE; - BattleScriptCall(BattleScript_JabocaRowapBerryActivates); - PREPARE_ITEM_BUFFER(gBattleTextBuff1, gLastUsedItem); - RecordItemEffectBattle(battler, HOLD_EFFECT_JABOCA_BERRY); - } - break; - case HOLD_EFFECT_ROWAP_BERRY: // consume and damage attacker if used special move - if (IsBattlerAlive(gBattlerAttacker) - && IsBattlerTurnDamaged(gBattlerTarget) - && !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) - && IsBattleMoveSpecial(gCurrentMove) - && GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD) - { - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 8; - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; - if (GetBattlerAbility(battler) == ABILITY_RIPEN) - gBattleStruct->moveDamage[gBattlerAttacker] *= 2; - - effect = ITEM_HP_CHANGE; - BattleScriptCall(BattleScript_JabocaRowapBerryActivates); - PREPARE_ITEM_BUFFER(gBattleTextBuff1, gLastUsedItem); - RecordItemEffectBattle(battler, HOLD_EFFECT_ROWAP_BERRY); - } - break; - case HOLD_EFFECT_KEE_BERRY: // consume and boost defense if used physical move - effect = DamagedStatBoostBerryEffect(battler, STAT_DEF, DAMAGE_CATEGORY_PHYSICAL); - break; - case HOLD_EFFECT_MARANGA_BERRY: // consume and boost sp. defense if used special move - effect = DamagedStatBoostBerryEffect(battler, STAT_SPDEF, DAMAGE_CATEGORY_SPECIAL); - break; - case HOLD_EFFECT_CURE_STATUS: // only Toxic Chain's interaction with Knock Off - case HOLD_EFFECT_CURE_PSN: - if (gBattleMons[battler].status1 & STATUS1_PSN_ANY && !UnnerveOn(battler, gLastUsedItem) && GetBattlerAbility(gBattlerAttacker) == ABILITY_TOXIC_CHAIN && GetMoveEffect(gCurrentMove) == EFFECT_KNOCK_OFF) - { - gBattleScripting.battler = battler; - gBattleMons[battler].status1 &= ~(STATUS1_PSN_ANY | STATUS1_TOXIC_COUNTER); - BattleScriptExecute(BattleScript_BerryCurePsnEnd2); - BtlController_EmitSetMonData(battler, 0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battler].status1); - MarkBattlerForControllerExec(battler); - effect = ITEM_STATUS_CHANGE; - } - break; - case HOLD_EFFECT_STICKY_BARB: - if (IsBattlerTurnDamaged(gBattlerTarget) - && !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT) - && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), gCurrentMove) - && !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) - && IsBattlerAlive(gBattlerAttacker) - && CanStealItem(gBattlerAttacker, gBattlerTarget, gBattleMons[gBattlerTarget].item) - && gBattleMons[gBattlerAttacker].item == ITEM_NONE) - { - // No sticky hold checks. - gEffectBattler = battler; // gEffectBattler = target - StealTargetItem(gBattlerAttacker, gBattlerTarget); // Attacker takes target's barb - BattleScriptCall(BattleScript_StickyBarbTransfer); - effect = ITEM_EFFECT_OTHER; - } - break; - default: - break; - } - } - break; - case ITEMEFFECT_ORBS: - { - enum Ability battlerAbility = GetBattlerAbility(battler); - switch (battlerHoldEffect) - { - case HOLD_EFFECT_TOXIC_ORB: - if (CanBePoisoned(battler, battler, battlerAbility, battlerAbility)) // Can corrosion trigger toxic orb on itself? - { - effect = ITEM_STATUS_CHANGE; - gBattleMons[battler].status1 = STATUS1_TOXIC_POISON; - BattleScriptExecute(BattleScript_ToxicOrb); - RecordItemEffectBattle(battler, battlerHoldEffect); - } - break; - case HOLD_EFFECT_FLAME_ORB: - if (CanBeBurned(battler, battler, battlerAbility)) - { - effect = ITEM_STATUS_CHANGE; - gBattleMons[battler].status1 = STATUS1_BURN; - BattleScriptExecute(BattleScript_FlameOrb); - RecordItemEffectBattle(battler, battlerHoldEffect); - } - break; - case HOLD_EFFECT_STICKY_BARB: // Not an orb per se, but similar effect, and needs to NOT activate with pickpocket - if (battlerAbility != ABILITY_MAGIC_GUARD) - { - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 8; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; - BattleScriptExecute(BattleScript_ItemHurtEnd2); - effect = ITEM_HP_CHANGE; - RecordItemEffectBattle(battler, battlerHoldEffect); - PREPARE_ITEM_BUFFER(gBattleTextBuff1, gLastUsedItem); - } - break; - default: - break; - } - - if (effect == ITEM_STATUS_CHANGE) - { - BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battler].status1); - MarkBattlerForControllerExec(battler); - } - } - break; - case ITEMEFFECT_WHITE_HERB: - case ITEMEFFECT_WHITE_HERB_ENDTURN: - case ITEMEFFECT_WHITE_HERB_FIRST_TURN: - if (battlerHoldEffect == HOLD_EFFECT_WHITE_HERB) - effect = RestoreWhiteHerbStats(battler, caseID); - break; - case ITEMEFFECT_MIRROR_HERB: - case ITEMEFFECT_MIRROR_HERB_FIRST_TURN: - if (battlerHoldEffect == HOLD_EFFECT_MIRROR_HERB) - effect = TryConsumeMirrorHerb(battler, caseID); - break; - } - - // Berry was successfully used on a Pokemon. - if (effect && (gLastUsedItem >= FIRST_BERRY_INDEX && gLastUsedItem <= LAST_BERRY_INDEX)) - GetBattlerPartyState(battler)->ateBerry = TRUE; - - return effect; -} - void ClearVariousBattlerFlags(u32 battler) { gDisableStructs[battler].furyCutterCounter = 0; @@ -7694,7 +6171,7 @@ u32 GetBattleMoveTarget(u16 move, u8 setTarget) { u8 targetBattler = 0; u32 moveTarget, side; - u32 moveType = GetBattleMoveType(move); + enum Type moveType = GetBattleMoveType(move); if (setTarget != NO_TARGET_OVERRIDE) moveTarget = setTarget - 1; @@ -7749,7 +6226,7 @@ u32 GetBattleMoveTarget(u16 move, u8 setTarget) case MOVE_TARGET_BOTH: case MOVE_TARGET_FOES_AND_ALLY: targetBattler = GetOpposingSideBattler(gBattlerAttacker); - if (!IsBattlerAlive(targetBattler)) + if (IsDoubleBattle() && !IsBattlerAlive(targetBattler)) targetBattler ^= BIT_FLANK; break; case MOVE_TARGET_OPPONENTS_FIELD: @@ -7878,17 +6355,17 @@ u8 GetAttackerObedienceForAction() } } -enum ItemHoldEffect GetBattlerHoldEffect(u32 battler) +enum HoldEffect GetBattlerHoldEffect(u32 battler) { return GetBattlerHoldEffectInternal(battler, GetBattlerAbility(battler)); } -enum ItemHoldEffect GetBattlerHoldEffectIgnoreAbility(u32 battler) +enum HoldEffect GetBattlerHoldEffectIgnoreAbility(u32 battler) { return GetBattlerHoldEffectInternal(battler, ABILITY_NONE); } -enum ItemHoldEffect GetBattlerHoldEffectInternal(u32 battler, u32 ability) +enum HoldEffect GetBattlerHoldEffectInternal(u32 battler, u32 ability) { if (gBattleMons[battler].volatiles.embargo) return HOLD_EFFECT_NONE; @@ -7905,7 +6382,7 @@ enum ItemHoldEffect GetBattlerHoldEffectInternal(u32 battler, u32 ability) return GetItemHoldEffect(gBattleMons[battler].item); } -enum ItemHoldEffect GetBattlerHoldEffectIgnoreNegation(u32 battler) +enum HoldEffect GetBattlerHoldEffectIgnoreNegation(u32 battler) { gPotentialItemEffectBattler = battler; if (gBattleMons[battler].item == ITEM_ENIGMA_BERRY_E_READER) @@ -7914,14 +6391,6 @@ enum ItemHoldEffect GetBattlerHoldEffectIgnoreNegation(u32 battler) return GetItemHoldEffect(gBattleMons[battler].item); } -static u32 GetBattlerItemHoldEffectParam(u32 battler, u32 item) -{ - if (item == ITEM_ENIGMA_BERRY_E_READER) - return gEnigmaBerries[battler].holdEffectParam; - else - return GetItemHoldEffectParam(item); -} - u32 GetBattlerHoldEffectParam(u32 battler) { if (gBattleMons[battler].item == ITEM_ENIGMA_BERRY_E_READER) @@ -7930,7 +6399,7 @@ u32 GetBattlerHoldEffectParam(u32 battler) return GetItemHoldEffectParam(gBattleMons[battler].item); } -bool32 CanBattlerAvoidContactEffects(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum ItemHoldEffect holdEffectAtk, u32 move) +bool32 CanBattlerAvoidContactEffects(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum HoldEffect holdEffectAtk, u32 move) { if (holdEffectAtk == HOLD_EFFECT_PROTECTIVE_PADS) { @@ -7941,7 +6410,7 @@ bool32 CanBattlerAvoidContactEffects(u32 battlerAtk, u32 battlerDef, enum Abilit return !IsMoveMakingContact(battlerAtk, battlerDef, abilityAtk, holdEffectAtk, move); } -bool32 IsMoveMakingContact(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum ItemHoldEffect holdEffectAtk, u32 move) +bool32 IsMoveMakingContact(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum HoldEffect holdEffectAtk, u32 move) { if (!(MoveMakesContact(move) || (GetMoveEffect(move) == EFFECT_SHELL_SIDE_ARM && gBattleStruct->shellSideArmCategory[battlerAtk][battlerDef] == DAMAGE_CATEGORY_PHYSICAL))) @@ -8059,11 +6528,11 @@ enum IronBallCheck }; // Only called directly when calculating damage type effectiveness, and Iron Ball's type effectiveness mechanics -bool32 IsBattlerGroundedInverseCheck(u32 battler, enum Ability ability, enum ItemHoldEffect holdEffect, enum InverseBattleCheck checkInverse) +static bool32 IsBattlerGroundedInverseCheck(u32 battler, enum Ability ability, enum HoldEffect holdEffect, enum InverseBattleCheck checkInverse, bool32 isAnticipation) { if (holdEffect == HOLD_EFFECT_IRON_BALL) return TRUE; - if (gFieldStatuses & STATUS_FIELD_GRAVITY) + if (gFieldStatuses & STATUS_FIELD_GRAVITY && isAnticipation == FALSE) return TRUE; if (B_ROOTED_GROUNDING >= GEN_4 && gBattleMons[battler].volatiles.root) return TRUE; @@ -8082,9 +6551,9 @@ bool32 IsBattlerGroundedInverseCheck(u32 battler, enum Ability ability, enum Ite return TRUE; } -bool32 IsBattlerGrounded(u32 battler, enum Ability ability, enum ItemHoldEffect holdEffect) +bool32 IsBattlerGrounded(u32 battler, enum Ability ability, enum HoldEffect holdEffect) { - return IsBattlerGroundedInverseCheck(battler, ability, holdEffect, NOT_INVERSE_BATTLE); + return IsBattlerGroundedInverseCheck(battler, ability, holdEffect, NOT_INVERSE_BATTLE, FALSE); } u32 GetMoveSlot(u16 *moves, u32 move) @@ -8104,7 +6573,7 @@ u32 GetBattlerWeight(u32 battler) u32 i; u32 weight = GetSpeciesWeight(gBattleMons[battler].species); enum Ability ability = GetBattlerAbility(battler); - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler); + enum HoldEffect holdEffect = GetBattlerHoldEffect(battler); if (ability == ABILITY_HEAVY_METAL) weight *= 2; @@ -8135,7 +6604,7 @@ u32 GetBattlerWeight(u32 battler) u32 CountBattlerStatIncreases(u32 battler, bool32 countEvasionAcc) { - u32 i; + enum Stat i; u32 count = 0; for (i = 0; i < NUM_BATTLE_STATS; i++) @@ -8292,7 +6761,7 @@ u32 CalcFuryCutterBasePower(u32 basePower, u32 furyCutterCounter) return basePower; } -static inline u32 IsFieldMudSportAffected(u32 moveType) +static inline u32 IsFieldMudSportAffected(enum Type moveType) { if (moveType == TYPE_ELECTRIC && (gFieldStatuses & STATUS_FIELD_MUDSPORT)) return TRUE; @@ -8309,7 +6778,7 @@ static inline u32 IsFieldMudSportAffected(u32 moveType) return FALSE; } -static inline u32 IsFieldWaterSportAffected(u32 moveType) +static inline u32 IsFieldWaterSportAffected(enum Type moveType) { if (moveType == TYPE_FIRE && (gFieldStatuses & STATUS_FIELD_WATERSPORT)) return TRUE; @@ -8463,31 +6932,31 @@ static inline u32 CalcMoveBasePower(struct DamageContext *ctx) basePower += (CountBattlerStatIncreases(battlerAtk, TRUE) * 20); break; case EFFECT_ELECTRO_BALL: - speed = GetBattlerTotalSpeedStat(battlerAtk) / GetBattlerTotalSpeedStat(battlerDef); + speed = GetBattlerTotalSpeedStat(battlerAtk, ctx->abilityAtk, ctx->holdEffectAtk) / GetBattlerTotalSpeedStat(battlerDef, ctx->abilityDef, ctx->holdEffectDef); if (speed >= ARRAY_COUNT(sSpeedDiffPowerTable)) speed = ARRAY_COUNT(sSpeedDiffPowerTable) - 1; basePower = sSpeedDiffPowerTable[speed]; break; case EFFECT_GYRO_BALL: { - u32 attackerSpeed = GetBattlerTotalSpeedStat(battlerAtk); + u32 attackerSpeed = GetBattlerTotalSpeedStat(battlerAtk, ctx->abilityAtk, ctx->holdEffectAtk); if (attackerSpeed == 0) { basePower = 1; } else { - basePower = ((25 * GetBattlerTotalSpeedStat(battlerDef)) / attackerSpeed) + 1; + basePower = ((25 * GetBattlerTotalSpeedStat(battlerDef, ctx->abilityDef, ctx->holdEffectDef)) / attackerSpeed) + 1; if (basePower > 150) basePower = 150; } break; } case EFFECT_ECHOED_VOICE: - // gBattleStruct->sameMoveTurns incremented in ppreduce - if (gBattleStruct->sameMoveTurns[battlerAtk] != 0 && GetMoveEffect(gLastResultingMoves[battlerAtk]) == EFFECT_ECHOED_VOICE) + // gBattleStruct->echoedVoiceCounter incremented in EndTurnVarious called by DoEndTurnEffects + if (gBattleStruct->echoedVoiceCounter != 0) { - basePower += (basePower * gBattleStruct->sameMoveTurns[battlerAtk]); + basePower += (basePower * gBattleStruct->echoedVoiceCounter); if (basePower > 200) basePower = 200; } @@ -8607,7 +7076,7 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageContext *ctx) u32 battlerAtk = ctx->battlerAtk; u32 battlerDef = ctx->battlerDef; u32 move = ctx->move; - u32 moveType = ctx->moveType; + enum Type moveType = ctx->moveType; enum BattleMoveEffects moveEffect = GetMoveEffect(move); uq4_12_t holdEffectModifier; @@ -8660,7 +7129,7 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageContext *ctx) modifier = uq4_12_multiply(modifier, uq4_12_add(UQ_4_12(1.0), PercentToUQ4_12(gSpecialStatuses[battlerAtk].gemParam))); if (gBattleMons[battlerAtk].volatiles.charge && moveType == TYPE_ELECTRIC) modifier = uq4_12_multiply(modifier, UQ_4_12(2.0)); - if (GetMoveEffect(gChosenMove) == EFFECT_ME_FIRST) + if (GetMoveEffect(ctx->chosenMove) == EFFECT_ME_FIRST) modifier = uq4_12_multiply(modifier, UQ_4_12(1.5)); if (IsBattlerTerrainAffected(battlerAtk, ctx->abilityAtk, ctx->holdEffectAtk, STATUS_FIELD_GRASSY_TERRAIN) && moveType == TYPE_GRASS) modifier = uq4_12_multiply(modifier, (B_TERRAIN_TYPE_BOOST >= GEN_8 ? UQ_4_12(1.3) : UQ_4_12(1.5))); @@ -8825,7 +7294,7 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageContext *ctx) break; case ABILITY_PROTOSYNTHESIS: { - u8 defHighestStat = GetHighestStatId(battlerDef); + enum Stat defHighestStat = GetHighestStatId(battlerDef); if (((ctx->weather & B_WEATHER_SUN && HasWeatherEffect()) || gDisableStructs[battlerDef].boosterEnergyActivated) && ((IsBattleMovePhysical(move) && defHighestStat == STAT_DEF) || (IsBattleMoveSpecial(move) && defHighestStat == STAT_SPDEF)) && !(gBattleMons[battlerDef].volatiles.transformed)) @@ -8917,11 +7386,17 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageContext *ctx) static bool32 IsRuinStatusActive(u32 fieldEffect) { - if (IsNeutralizingGasOnField()) // Neutralizing Gas still blocks Ruin field statuses - return FALSE; - + bool32 isNeutralizingGasOnField = IsNeutralizingGasOnField(); for (u32 battler = 0; battler < gBattlersCount; battler++) { + // Mold Breaker doesn't ignore Ruin field status but Gastro Acid and Neutralizing Gas do + if (gBattleMons[battler].volatiles.gastroAcid) + continue; + if (GetBattlerHoldEffectIgnoreAbility(battler) != HOLD_EFFECT_ABILITY_SHIELD + && isNeutralizingGasOnField + && gBattleMons[battler].ability != ABILITY_NEUTRALIZING_GAS) + continue; + if (GetBattlerVolatile(battler, fieldEffect)) return TRUE; } @@ -8938,7 +7413,7 @@ static inline u32 CalcAttackStat(struct DamageContext *ctx) u32 battlerAtk = ctx->battlerAtk; u32 battlerDef = ctx->battlerDef; u32 move = ctx->move; - u32 moveType = ctx->moveType; + enum Type moveType = ctx->moveType; enum BattleMoveEffects moveEffect = GetMoveEffect(move); atkBaseSpeciesId = GET_BASE_SPECIES_ID(gBattleMons[battlerAtk].species); @@ -9009,7 +7484,7 @@ static inline u32 CalcAttackStat(struct DamageContext *ctx) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(2.0)); break; case ABILITY_SLOW_START: - if (gDisableStructs[battlerAtk].slowStartTimer > gBattleTurnCounter) + if (gDisableStructs[battlerAtk].slowStartTimer > 0) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(0.5)); break; case ABILITY_SOLAR_POWER: @@ -9098,7 +7573,7 @@ static inline u32 CalcAttackStat(struct DamageContext *ctx) case ABILITY_PROTOSYNTHESIS: if (!(gBattleMons[battlerAtk].volatiles.transformed)) { - u32 atkHighestStat = GetHighestStatId(battlerAtk); + enum Stat atkHighestStat = GetHighestStatId(battlerAtk); if (((ctx->weather & B_WEATHER_SUN) && HasWeatherEffect()) || gDisableStructs[battlerAtk].boosterEnergyActivated) { if ((IsBattleMovePhysical(move) && atkHighestStat == STAT_ATK) || (IsBattleMoveSpecial(move) && atkHighestStat == STAT_SPATK)) @@ -9109,7 +7584,7 @@ static inline u32 CalcAttackStat(struct DamageContext *ctx) case ABILITY_QUARK_DRIVE: if (!(gBattleMons[battlerAtk].volatiles.transformed)) { - u32 atkHighestStat = GetHighestStatId(battlerAtk); + enum Stat atkHighestStat = GetHighestStatId(battlerAtk); if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gDisableStructs[battlerAtk].boosterEnergyActivated) { if ((IsBattleMovePhysical(move) && atkHighestStat == STAT_ATK) || (IsBattleMoveSpecial(move) && atkHighestStat == STAT_SPATK)) @@ -9202,9 +7677,9 @@ static inline u32 CalcAttackStat(struct DamageContext *ctx) // The offensive stats of a Player's Pokémon are boosted by x1.1 (+10%) if they have the corresponding flags set (eg. Badges) if (ShouldGetStatBadgeBoost(B_FLAG_BADGE_BOOST_ATTACK, battlerAtk) && IsBattleMovePhysical(move)) - modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.1)); + modifier = uq4_12_multiply_half_down(modifier, GetBadgeBoostModifier()); if (ShouldGetStatBadgeBoost(B_FLAG_BADGE_BOOST_SPATK, battlerAtk) && IsBattleMoveSpecial(move)) - modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.1)); + modifier = uq4_12_multiply_half_down(modifier, GetBadgeBoostModifier()); return uq4_12_multiply_by_int_half_down(modifier, atkStat); } @@ -9382,11 +7857,11 @@ static inline u32 CalcDefenseStat(struct DamageContext *ctx) if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_ICE) && IsBattlerWeatherAffected(battlerDef, B_WEATHER_SNOW) && usesDefStat) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.5)); - // The offensive stats of a Player's Pokémon are boosted by x1.1 (+10%) if they have the corresponding flags set (eg. Badges) + // The defensive stats of a Player's Pokémon are boosted by x1.1 (+10%) if they have the corresponding flags set (eg. Badges) if (ShouldGetStatBadgeBoost(B_FLAG_BADGE_BOOST_DEFENSE, battlerDef) && IsBattleMovePhysical(move)) - modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.1)); + modifier = uq4_12_multiply_half_down(modifier, GetBadgeBoostModifier()); if (ShouldGetStatBadgeBoost(B_FLAG_BADGE_BOOST_SPDEF, battlerDef) && IsBattleMoveSpecial(move)) - modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.1)); + modifier = uq4_12_multiply_half_down(modifier, GetBadgeBoostModifier()); return uq4_12_multiply_by_int_half_down(modifier, defStat); } @@ -9645,7 +8120,7 @@ static inline uq4_12_t GetDefenderPartnerAbilitiesModifier(u32 battlerPartnerDef return UQ_4_12(1.0); } -static inline uq4_12_t GetAttackerItemsModifier(u32 battlerAtk, uq4_12_t typeEffectivenessModifier, enum ItemHoldEffect holdEffectAtk) +static inline uq4_12_t GetAttackerItemsModifier(u32 battlerAtk, uq4_12_t typeEffectivenessModifier, enum HoldEffect holdEffectAtk) { u32 metronomeTurns; uq4_12_t metronomeBoostBase; @@ -9653,7 +8128,7 @@ static inline uq4_12_t GetAttackerItemsModifier(u32 battlerAtk, uq4_12_t typeEff { case HOLD_EFFECT_METRONOME: metronomeBoostBase = PercentToUQ4_12(GetBattlerHoldEffectParam(battlerAtk)); - metronomeTurns = min(gBattleStruct->sameMoveTurns[battlerAtk], 5); + metronomeTurns = min(gBattleStruct->metronomeItemCounter[battlerAtk], 5); // according to bulbapedia this is the "correct" way to calculate the metronome boost // due to the limited domain of damage numbers it will never really matter whether this is off by one return uq4_12_add(UQ_4_12(1.0), metronomeBoostBase * metronomeTurns); @@ -9676,7 +8151,7 @@ static inline uq4_12_t GetDefenderItemsModifier(struct DamageContext *ctx) switch (ctx->holdEffectDef) { case HOLD_EFFECT_RESIST_BERRY: - if (UnnerveOn(ctx->battlerDef, gBattleMons[ctx->battlerDef].item)) + if (IsUnnerveBlocked(ctx->battlerDef, gBattleMons[ctx->battlerDef].item)) return UQ_4_12(1.0); if (ctx->moveType == GetBattlerHoldEffectParam(ctx->battlerDef) && (ctx->moveType == TYPE_NORMAL || ctx->typeEffectivenessModifier >= UQ_4_12(2.0))) { @@ -9855,7 +8330,7 @@ static inline s32 DoFutureSightAttackDamageCalcVars(struct DamageContext *ctx) u32 battlerAtk = ctx->battlerAtk; u32 battlerDef = ctx->battlerDef; u32 move = ctx->move; - u32 moveType = ctx->moveType; + enum Type moveType = ctx->moveType; struct Pokemon *party = GetBattlerParty(battlerAtk); struct Pokemon *partyMon = &party[gWishFutureKnock.futureSightPartyIndex[battlerDef]]; @@ -9951,7 +8426,7 @@ s32 CalculateMoveDamageVars(struct DamageContext *ctx) return DoMoveDamageCalcVars(ctx); } -static inline void MulByTypeEffectiveness(struct DamageContext *ctx, uq4_12_t *modifier, u32 defType) +static inline void MulByTypeEffectiveness(struct DamageContext *ctx, uq4_12_t *modifier, enum Type defType) { uq4_12_t mod = GetTypeModifier(ctx->moveType, defType); @@ -9976,7 +8451,7 @@ static inline void MulByTypeEffectiveness(struct DamageContext *ctx, uq4_12_t *m if (ctx->moveType == TYPE_PSYCHIC && defType == TYPE_DARK && gBattleMons[ctx->battlerDef].volatiles.miracleEye && mod == UQ_4_12(0.0)) mod = UQ_4_12(1.0); - if (GetMoveEffect(ctx->move) == EFFECT_SUPER_EFFECTIVE_ON_ARG && defType == GetMoveArgType(ctx->move)) + if (GetMoveEffect(ctx->move) == EFFECT_SUPER_EFFECTIVE_ON_ARG && defType == GetMoveArgType(ctx->move) && !ctx->isAnticipation) mod = UQ_4_12(2.0); if (ctx->moveType == TYPE_GROUND && defType == TYPE_FLYING && IsBattlerGrounded(ctx->battlerDef, ctx->abilityDef, ctx->holdEffectDef) && mod == UQ_4_12(0.0)) mod = UQ_4_12(1.0); @@ -9984,7 +8459,7 @@ static inline void MulByTypeEffectiveness(struct DamageContext *ctx, uq4_12_t *m mod = UQ_4_12(2.0); // B_WEATHER_STRONG_WINDS weakens Super Effective moves against Flying-type Pokémon - if (gBattleWeather & B_WEATHER_STRONG_WINDS && HasWeatherEffect()) + if (gBattleWeather & B_WEATHER_STRONG_WINDS && HasWeatherEffect() && !ctx->isAnticipation) { if (defType == TYPE_FLYING && mod >= UQ_4_12(2.0)) mod = UQ_4_12(1.0); @@ -10004,7 +8479,7 @@ static inline void MulByTypeEffectiveness(struct DamageContext *ctx, uq4_12_t *m *modifier = uq4_12_multiply(*modifier, mod); } -static inline void TryNoticeIllusionInTypeEffectiveness(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, uq4_12_t resultingModifier, u32 illusionSpecies) +static inline void TryNoticeIllusionInTypeEffectiveness(u32 move, enum Type moveType, u32 battlerAtk, u32 battlerDef, uq4_12_t resultingModifier, u32 illusionSpecies) { // Check if the type effectiveness would've been different if the pokemon really had the types as the disguise. uq4_12_t presumedModifier = UQ_4_12(1.0); @@ -10012,7 +8487,7 @@ static inline void TryNoticeIllusionInTypeEffectiveness(u32 move, u32 moveType, struct DamageContext ctx = {0}; ctx.battlerAtk = battlerAtk; ctx.battlerDef = battlerDef; - ctx.move = move; + ctx.move = ctx.chosenMove = move; ctx.moveType = moveType; ctx.updateFlags = FALSE; ctx.abilityAtk = GetBattlerAbility(battlerAtk); @@ -10055,7 +8530,7 @@ void UpdateMoveResultFlags(uq4_12_t modifier, u16 *resultFlags) static inline uq4_12_t CalcTypeEffectivenessMultiplierInternal(struct DamageContext *ctx, uq4_12_t modifier) { u32 illusionSpecies; - u32 types[3]; + enum Type types[3]; GetBattlerTypes(ctx->battlerDef, FALSE, types); MulByTypeEffectiveness(ctx, &modifier, types[0]); @@ -10075,7 +8550,7 @@ static inline uq4_12_t CalcTypeEffectivenessMultiplierInternal(struct DamageCont if (B_GLARE_GHOST < GEN_4 && ctx->move == MOVE_GLARE && IS_BATTLER_OF_TYPE(ctx->battlerDef, TYPE_GHOST)) modifier = UQ_4_12(0.0); } - else if (ctx->moveType == TYPE_GROUND && !IsBattlerGroundedInverseCheck(ctx->battlerDef, ctx->abilityDef, ctx->holdEffectDef, INVERSE_BATTLE) && !(MoveIgnoresTypeIfFlyingAndUngrounded(ctx->move))) + else if (ctx->moveType == TYPE_GROUND && !IsBattlerGroundedInverseCheck(ctx->battlerDef, ctx->abilityDef, ctx->holdEffectDef, INVERSE_BATTLE, ctx->isAnticipation) && !(MoveIgnoresTypeIfFlyingAndUngrounded(ctx->move))) { modifier = UQ_4_12(0.0); if (ctx->updateFlags && ctx->abilityDef == ABILITY_LEVITATE) @@ -10139,7 +8614,7 @@ uq4_12_t CalcTypeEffectivenessMultiplier(struct DamageContext *ctx) if (ctx->move != MOVE_STRUGGLE && ctx->moveType != TYPE_MYSTERY) { modifier = CalcTypeEffectivenessMultiplierInternal(ctx, modifier); - if (GetMoveEffect(ctx->move) == EFFECT_TWO_TYPED_MOVE) + if (GetMoveEffect(ctx->move) == EFFECT_TWO_TYPED_MOVE && !ctx->isAnticipation) { ctx->moveType = GetMoveArgType(ctx->move); modifier = CalcTypeEffectivenessMultiplierInternal(ctx, modifier); @@ -10154,12 +8629,12 @@ uq4_12_t CalcTypeEffectivenessMultiplier(struct DamageContext *ctx) uq4_12_t CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, enum Ability abilityDef) { uq4_12_t modifier = UQ_4_12(1.0); - u32 moveType = GetBattleMoveType(move); + enum Type moveType = GetBattleMoveType(move); if (move != MOVE_STRUGGLE && moveType != TYPE_MYSTERY) { struct DamageContext ctx = {0}; - ctx.move = move; + ctx.move = ctx.chosenMove = move; ctx.moveType = moveType; ctx.updateFlags = FALSE; ctx.abilityDef = abilityDef; @@ -10192,19 +8667,19 @@ static uq4_12_t GetInverseTypeMultiplier(uq4_12_t multiplier) } } -uq4_12_t GetOverworldTypeEffectiveness(struct Pokemon *mon, u8 moveType) +uq4_12_t GetOverworldTypeEffectiveness(struct Pokemon *mon, enum Type moveType) { uq4_12_t modifier = UQ_4_12(1.0); enum Ability abilityDef = GetMonAbility(mon); u16 speciesDef = GetMonData(mon, MON_DATA_SPECIES); - u8 type1 = GetSpeciesType(speciesDef, 0); - u8 type2 = GetSpeciesType(speciesDef, 1); + enum Type type1 = GetSpeciesType(speciesDef, 0); + enum Type type2 = GetSpeciesType(speciesDef, 1); if (moveType == TYPE_MYSTERY) return modifier; struct DamageContext ctx = {0}; - ctx.move = MOVE_POUND; + ctx.move = ctx.chosenMove = MOVE_POUND; ctx.moveType = moveType; ctx.updateFlags = FALSE; @@ -10219,14 +8694,14 @@ uq4_12_t GetOverworldTypeEffectiveness(struct Pokemon *mon, u8 moveType) return modifier; } -uq4_12_t GetTypeModifier(u32 atkType, u32 defType) +uq4_12_t GetTypeModifier(enum Type atkType, enum Type defType) { if (B_FLAG_INVERSE_BATTLE != 0 && FlagGet(B_FLAG_INVERSE_BATTLE)) return GetInverseTypeMultiplier(gTypeEffectivenessTable[atkType][defType]); return gTypeEffectivenessTable[atkType][defType]; } -s32 GetStealthHazardDamageByTypesAndHP(enum TypeSideHazard hazardType, u8 type1, u8 type2, u32 maxHp) +s32 GetStealthHazardDamageByTypesAndHP(enum TypeSideHazard hazardType, enum Type type1, enum Type type2, u32 maxHp) { s32 dmg = 0; uq4_12_t modifier = UQ_4_12(1.0); @@ -10272,7 +8747,7 @@ s32 GetStealthHazardDamageByTypesAndHP(enum TypeSideHazard hazardType, u8 type1, s32 GetStealthHazardDamage(enum TypeSideHazard hazardType, u32 battler) { - u32 types[3]; + enum Type types[3]; GetBattlerTypes(battler, FALSE, types); u32 maxHp = gBattleMons[battler].maxHP; @@ -10318,7 +8793,7 @@ bool32 DoesSpeciesUseHoldItemToChangeForm(u16 species, u16 heldItemId) bool32 CanMegaEvolve(u32 battler) { - enum ItemHoldEffect holdEffect = GetBattlerHoldEffectIgnoreNegation(battler); + enum HoldEffect holdEffect = GetBattlerHoldEffectIgnoreNegation(battler); // Check if Player has a Mega Ring. if (!TESTING @@ -10356,7 +8831,7 @@ bool32 CanMegaEvolve(u32 battler) bool32 CanUltraBurst(u32 battler) { - enum ItemHoldEffect holdEffect = GetBattlerHoldEffectIgnoreNegation(battler); + enum HoldEffect holdEffect = GetBattlerHoldEffectIgnoreNegation(battler); // Check if Player has a Z-Ring if (!TESTING && (GetBattlerPosition(battler) == B_POSITION_PLAYER_LEFT @@ -10543,23 +9018,52 @@ u16 GetBattleFormChangeTargetSpecies(u32 battler, enum FormChanges method) return targetSpecies; } -bool32 CanBattlerFormChange(u32 battler, enum FormChanges method) +static bool32 CanBattlerFormChange(u32 battler, enum FormChanges method) { // Can't change form if transformed. if (gBattleMons[battler].volatiles.transformed && B_TRANSFORM_FORM_CHANGES >= GEN_5) return FALSE; - // Mega Evolved and Ultra Bursted Pokémon should always revert to normal upon fainting or ending the battle. - if ((IsBattlerMegaEvolved(battler) || IsBattlerUltraBursted(battler) || IsBattlerInTeraForm(battler)) && (method == FORM_CHANGE_FAINT || method == FORM_CHANGE_END_BATTLE)) - return TRUE; - else if (IsBattlerPrimalReverted(battler) && (method == FORM_CHANGE_END_BATTLE)) - return TRUE; - // Gigantamaxed Pokemon should revert upon fainting, switching, or ending the battle. - else if (IsGigantamaxed(battler) && (method == FORM_CHANGE_FAINT || method == FORM_CHANGE_BATTLE_SWITCH || method == FORM_CHANGE_END_BATTLE)) - return TRUE; + + switch (method) + { + case FORM_CHANGE_END_BATTLE: + if (IsBattlerPrimalReverted(battler)) + return TRUE; + // Fallthrough + case FORM_CHANGE_FAINT: + if (IsBattlerMegaEvolved(battler) || IsBattlerUltraBursted(battler) || IsBattlerInTeraForm(battler) || IsGigantamaxed(battler)) + return TRUE; + break; + case FORM_CHANGE_BATTLE_SWITCH: + if (IsGigantamaxed(battler)) + return TRUE; + else if (GetActiveGimmick(battler) == GIMMICK_TERA && GetBattlerAbility(battler) == ABILITY_HUNGER_SWITCH) + return FALSE; + break; + default: + break; + } return DoesSpeciesHaveFormChangeMethod(gBattleMons[battler].species, method); } +bool32 TryRevertPartyMonFormChange(u32 partyIndex) +{ + bool32 changedForm = FALSE; + + // Appeared in battle and didn't faint + if (gBattleStruct->partyState[B_SIDE_PLAYER][partyIndex].sentOut && GetMonData(&gPlayerParty[partyIndex], MON_DATA_HP, NULL) != 0) + changedForm = TryFormChange(partyIndex, B_SIDE_PLAYER, FORM_CHANGE_END_BATTLE_ENVIRONMENT); + + if (!changedForm) + changedForm = TryFormChange(partyIndex, B_SIDE_PLAYER, FORM_CHANGE_END_BATTLE); + + // Clear original species field + gBattleStruct->partyState[B_SIDE_PLAYER][partyIndex].changedSpecies = SPECIES_NONE; + + return changedForm; +} + bool32 TryBattleFormChange(u32 battler, enum FormChanges method) { u32 monId = gBattlerPartyIndexes[battler]; @@ -10573,7 +9077,7 @@ bool32 TryBattleFormChange(u32 battler, enum FormChanges method) targetSpecies = GetBattleFormChangeTargetSpecies(battler, method); if (targetSpecies == currentSpecies) targetSpecies = GetFormChangeTargetSpecies(&party[monId], method, 0); - if (targetSpecies != currentSpecies) + if (targetSpecies != currentSpecies && targetSpecies != SPECIES_NONE) { // Saves the original species on the first form change. @@ -10590,17 +9094,22 @@ bool32 TryBattleFormChange(u32 battler, enum FormChanges method) { bool32 restoreSpecies = FALSE; - // Mega Evolved and Ultra Bursted Pokémon should always revert to normal upon fainting or ending the battle, so no need to add it to the form change tables. - if ((IsBattlerMegaEvolved(battler) || IsBattlerUltraBursted(battler) || IsBattlerInTeraForm(battler)) && (method == FORM_CHANGE_FAINT || method == FORM_CHANGE_END_BATTLE)) - restoreSpecies = TRUE; - - // Unlike Megas, Primal Reversion isn't canceled on fainting. - else if (IsBattlerPrimalReverted(battler) && (method == FORM_CHANGE_END_BATTLE)) - restoreSpecies = TRUE; - - // Gigantamax Pokemon have their forms reverted after fainting, switching, or ending the battle. - else if (IsGigantamaxed(battler) && (method == FORM_CHANGE_FAINT || method == FORM_CHANGE_BATTLE_SWITCH || method == FORM_CHANGE_END_BATTLE)) + switch (method) + { + case FORM_CHANGE_END_BATTLE: restoreSpecies = TRUE; + break; + case FORM_CHANGE_FAINT: + if (IsBattlerMegaEvolved(battler) || IsBattlerUltraBursted(battler) || IsBattlerInTeraForm(battler) || IsGigantamaxed(battler)) + restoreSpecies = TRUE; + break; + case FORM_CHANGE_BATTLE_SWITCH: + if (IsGigantamaxed(battler)) + restoreSpecies = TRUE; + break; + default: + break; + } if (restoreSpecies) { @@ -10623,7 +9132,7 @@ bool32 TryBattleFormChange(u32 battler, enum FormChanges method) bool32 DoBattlersShareType(u32 battler1, u32 battler2) { s32 i; - u32 types1[3], types2[3]; + enum Type types1[3], types2[3]; GetBattlerTypes(battler1, FALSE, types1); GetBattlerTypes(battler2, FALSE, types2); @@ -10644,7 +9153,7 @@ bool32 DoBattlersShareType(u32 battler1, u32 battler2) bool32 CanBattlerGetOrLoseItem(u32 battler, u16 itemId) { u16 species = gBattleMons[battler].species; - enum ItemHoldEffect holdEffect = GetItemHoldEffect(itemId); + enum HoldEffect holdEffect = GetItemHoldEffect(itemId); if (ItemIsMail(itemId)) return FALSE; @@ -10669,7 +9178,7 @@ u32 GetBattlerVisualSpecies(u32 battler) return gBattleMons[battler].species; } -bool32 TryClearIllusion(u32 battler, u32 caseID) +bool32 TryClearIllusion(u32 battler, enum AbilityEffect caseID) { if (gBattleStruct->illusion[battler].state != ILLUSION_ON) return FALSE; @@ -10713,10 +9222,10 @@ u32 GetIllusionMonPartyId(struct Pokemon *party, struct Pokemon *mon, struct Pok s32 partyStart=0; // Adjust party search range for Multibattles and Player vs two-trainers - if((GetBattlerSide(battler) == B_SIDE_PLAYER && (gBattleTypeFlags & BATTLE_TYPE_MULTI)) + if ((GetBattlerSide(battler) == B_SIDE_PLAYER && (gBattleTypeFlags & BATTLE_TYPE_MULTI)) || (GetBattlerSide(battler) == B_SIDE_OPPONENT && (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS))) { - if((GetBattlerPosition(battler) == B_POSITION_PLAYER_LEFT) || (GetBattlerPosition(battler) == B_POSITION_OPPONENT_LEFT)) + if ((GetBattlerPosition(battler) == B_POSITION_PLAYER_LEFT) || (GetBattlerPosition(battler) == B_POSITION_OPPONENT_LEFT)) { partyEnd = 3; partyStart = 0; @@ -10774,9 +9283,121 @@ bool32 SetIllusionMon(struct Pokemon *mon, u32 battler) return FALSE; } +u32 TryImmunityAbilityHealStatus(u32 battler, enum AbilityEffect caseID) +{ + u32 effect = 0; + switch (GetBattlerAbilityIgnoreMoldBreaker(battler)) + { + case ABILITY_IMMUNITY: + case ABILITY_PASTEL_VEIL: + if (gBattleMons[battler].status1 & (STATUS1_POISON | STATUS1_TOXIC_POISON | STATUS1_TOXIC_COUNTER)) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn); + effect = 1; + } + break; + case ABILITY_OWN_TEMPO: + if (gBattleMons[battler].volatiles.confusionTurns > 0) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_ConfusionJpn); + effect = 2; + } + break; + case ABILITY_LIMBER: + if (gBattleMons[battler].status1 & STATUS1_PARALYSIS) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn); + effect = 1; + } + break; + case ABILITY_INSOMNIA: + case ABILITY_VITAL_SPIRIT: + if (gBattleMons[battler].status1 & STATUS1_SLEEP) + { + TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]); + gBattleMons[battler].volatiles.nightmare = FALSE; + StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn); + effect = 1; + } + break; + case ABILITY_WATER_VEIL: + case ABILITY_WATER_BUBBLE: + case ABILITY_THERMAL_EXCHANGE: + if (gBattleMons[battler].status1 & STATUS1_BURN) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn); + effect = 1; + } + break; + case ABILITY_MAGMA_ARMOR: + if (gBattleMons[battler].status1 & (STATUS1_FREEZE | STATUS1_FROSTBITE)) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn); + effect = 1; + } + break; + case ABILITY_OBLIVIOUS: + if (gBattleMons[battler].volatiles.infatuation) + effect = 3; + else if (GetGenConfig(GEN_CONFIG_OBLIVIOUS_TAUNT) >= GEN_6 && gDisableStructs[battler].tauntTimer != 0) + effect = 4; + break; + } + + if (effect != 0) + { + switch (effect) + { + case 1: // status cleared + gBattleMons[battler].status1 = 0; + if (caseID == ABILITYEFFECT_ON_SWITCHIN_IMMUNITIES) + BattleScriptExecute(BattleScript_AbilityCuredStatusEnd3); + else + BattleScriptCall(BattleScript_AbilityCuredStatus); + break; + case 2: // get rid of confusion + RemoveConfusionStatus(battler); + if (caseID == ABILITYEFFECT_ON_SWITCHIN_IMMUNITIES) + BattleScriptExecute(BattleScript_AbilityCuredStatusEnd3); + else + BattleScriptCall(BattleScript_AbilityCuredStatus); + break; + case 3: // get rid of infatuation + gBattleMons[battler].volatiles.infatuation = 0; + if (caseID == ABILITYEFFECT_ON_SWITCHIN_IMMUNITIES) + BattleScriptExecute(BattleScript_AbilityCuredStatusEnd3); + else + BattleScriptCall(BattleScript_AbilityCuredStatus); + break; + case 4: // get rid of taunt + gDisableStructs[battler].tauntTimer = 0; + if (caseID == ABILITYEFFECT_ON_SWITCHIN_IMMUNITIES) + BattleScriptExecute(BattleScript_AbilityCuredStatusEnd3); + else + BattleScriptCall(BattleScript_AbilityCuredStatus); + break; + } + + gBattleScripting.battler = gBattlerAbility = battler; + BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battler].status1); + MarkBattlerForControllerExec(battler); + return effect; + } + + return 0; +} + +uq4_12_t GetBadgeBoostModifier(void) +{ + if (GetGenConfig(GEN_CONFIG_BADGE_BOOST) < GEN_3) + return UQ_4_12(1.125); + else + return UQ_4_12(1.1); +} + bool32 ShouldGetStatBadgeBoost(u16 badgeFlag, u32 battler) { - if (B_BADGE_BOOST == GEN_3 && badgeFlag != 0) + if (GetGenConfig(GEN_CONFIG_BADGE_BOOST) <= GEN_3 && badgeFlag != 0) { if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_FRONTIER)) return FALSE; @@ -10868,31 +9489,6 @@ static bool32 TryRemoveScreens(u32 battler) return removed; } -static bool32 IsUnnerveAbilityOnOpposingSide(u32 battler) -{ - for (u32 battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) - { - if (battler == battlerDef || IsBattlerAlly(battler, battlerDef)) - continue; - - if (!IsBattlerAlive(battlerDef)) - continue; - - enum Ability ability = GetBattlerAbility(battlerDef); - switch (ability) - { - case ABILITY_UNNERVE: - case ABILITY_AS_ONE_ICE_RIDER: - case ABILITY_AS_ONE_SHADOW_RIDER: - return TRUE; - default: - break; - } - } - - return FALSE; -} - // Photon Geyser, Light That Burns the Sky, Tera Blast enum DamageCategory GetCategoryBasedOnStats(u32 battler) { @@ -10947,7 +9543,10 @@ void SortBattlersBySpeed(u8 *battlers, bool32 slowToFast) u16 speeds[MAX_BATTLERS_COUNT] = {0}; for (i = 0; i < gBattlersCount; i++) - speeds[i] = GetBattlerTotalSpeedStat(battlers[i]); + { + u32 battler = battlers[i]; + speeds[i] = GetBattlerTotalSpeedStat(battler, GetBattlerAbility(battler), GetBattlerHoldEffect(battler)); + } for (i = 1; i < gBattlersCount; i++) { @@ -11004,7 +9603,7 @@ void TryRestoreHeldItems(void) bool32 CanStealItem(u32 battlerStealing, u32 battlerItem, u16 item) { - u8 stealerSide = GetBattlerSide(battlerStealing); + enum BattleSide stealerSide = GetBattlerSide(battlerStealing); if (gBattleTypeFlags & BATTLE_TYPE_TRAINER_HILL) return FALSE; @@ -11061,7 +9660,7 @@ void TrySaveExchangedItem(u32 battler, u16 stolenItem) bool32 IsBattlerAffectedByHazards(u32 battler, bool32 toxicSpikes) { bool32 ret = TRUE; - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler); + enum HoldEffect holdEffect = GetBattlerHoldEffect(battler); if (toxicSpikes && holdEffect == HOLD_EFFECT_HEAVY_DUTY_BOOTS && !IS_BATTLER_OF_TYPE(battler, TYPE_POISON)) { ret = FALSE; @@ -11081,14 +9680,14 @@ bool32 TestIfSheerForceAffected(u32 battler, u16 move) } // This function is the body of "jumpifstat", but can be used dynamically in a function -bool32 CompareStat(u32 battler, u8 statId, u8 cmpTo, u8 cmpKind) +bool32 CompareStat(u32 battler, enum Stat statId, u8 cmpTo, u8 cmpKind, enum Ability ability) { bool32 ret = FALSE; u8 statValue = gBattleMons[battler].statStages[statId]; // Because this command is used as a way of checking if a stat can be lowered/raised, // we need to do some modification at run-time. - if (GetBattlerAbility(battler) == ABILITY_CONTRARY) + if (ability == ABILITY_CONTRARY) { if (cmpKind == CMP_GREATER_THAN) cmpKind = CMP_LESS_THAN; @@ -11132,23 +9731,6 @@ bool32 CompareStat(u32 battler, u8 statId, u8 cmpTo, u8 cmpKind) return ret; } -bool32 TryRoomService(u32 battler) -{ - if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && CompareStat(battler, STAT_SPEED, MIN_STAT_STAGE, CMP_GREATER_THAN)) - { - gEffectBattler = gBattleScripting.battler = battler; - SET_STATCHANGER(STAT_SPEED, 1, TRUE); - gBattleScripting.animArg1 = STAT_ANIM_PLUS1 + STAT_SPEED; - gBattleScripting.animArg2 = 0; - gLastUsedItem = gBattleMons[battler].item; - return TRUE; - } - else - { - return FALSE; - } -} - bool32 BlocksPrankster(u16 move, u32 battlerPrankster, u32 battlerDef, bool32 checkTarget) { if (GetGenConfig(GEN_CONFIG_PRANKSTER_DARK_TYPES) < GEN_7) @@ -11167,17 +9749,12 @@ bool32 BlocksPrankster(u16 move, u32 battlerPrankster, u32 battlerDef, bool32 ch return TRUE; } -u16 GetUsedHeldItem(u32 battler) -{ - return gBattleStruct->usedHeldItems[gBattlerPartyIndexes[battler]][GetBattlerSide(battler)]; -} - bool32 CantPickupItem(u32 battler) { // Used by RandomUniformExcept() for RNG_PICKUP if (battler == gBattlerAttacker && (GetGenConfig(GEN_PICKUP_WILD) < GEN_9 || gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_LINK))) return TRUE; - return !(IsBattlerAlive(battler) && GetUsedHeldItem(battler) && gBattleStruct->battlerState[battler].canPickupItem); + return !(IsBattlerAlive(battler) && GetBattlerPartyState(battler)->usedHeldItem && gBattleStruct->battlerState[battler].canPickupItem); } bool32 PickupHasValidTarget(u32 battler) @@ -11191,7 +9768,6 @@ bool32 PickupHasValidTarget(u32 battler) return FALSE; } -// TODO: Pass down weather as an arg bool32 IsBattlerWeatherAffected(u32 battler, u32 weatherFlags) { if (gBattleWeather & weatherFlags && HasWeatherEffect()) @@ -11296,16 +9872,6 @@ void RemoveConfusionStatus(u32 battler) gBattleMons[battler].volatiles.infiniteConfusion = FALSE; } -static bool32 CanBeInfinitelyConfused(u32 battler) -{ - enum Ability ability = GetBattlerAbility(battler); - if (ability == ABILITY_OWN_TEMPO - || IsBattlerTerrainAffected(battler, ability, GetBattlerHoldEffect(battler), STATUS_FIELD_MISTY_TERRAIN) - || gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD) - return FALSE; - return TRUE; -} - u8 GetBattlerGender(u32 battler) { return GetGenderFromSpeciesAndPersonality(gBattleMons[battler].species, @@ -11479,13 +10045,13 @@ bool8 IsMonBannedFromSkyBattles(u16 species) } } -void GetBattlerTypes(u32 battler, bool32 ignoreTera, u32 types[static 3]) +void GetBattlerTypes(u32 battler, bool32 ignoreTera, enum Type types[static 3]) { // Terastallization. bool32 isTera = GetActiveGimmick(battler) == GIMMICK_TERA; if (!ignoreTera && isTera) { - u32 teraType = GetBattlerTeraType(battler); + enum Type teraType = GetBattlerTeraType(battler); if (teraType != TYPE_STELLAR) { types[0] = types[1] = types[2] = teraType; @@ -11509,14 +10075,14 @@ void GetBattlerTypes(u32 battler, bool32 ignoreTera, u32 types[static 3]) } } -u32 GetBattlerType(u32 battler, u32 typeIndex, bool32 ignoreTera) +enum Type GetBattlerType(u32 battler, u32 typeIndex, bool32 ignoreTera) { - u32 types[3]; + enum Type types[3]; GetBattlerTypes(battler, ignoreTera, types); return types[typeIndex]; } -void RemoveBattlerType(u32 battler, u8 type) +void RemoveBattlerType(u32 battler, enum Type type) { u32 i; if (GetActiveGimmick(battler) == GIMMICK_TERA) // don't remove type if Terastallized @@ -11565,6 +10131,8 @@ void SetShellSideArmCategory(void) statStage = gBattleMons[battlerDef].statStages[STAT_DEF]; targetDefStat *= gStatStageRatios[statStage][0]; targetDefStat /= gStatStageRatios[statStage][1]; + if (targetDefStat == 0) + targetDefStat = 1; physical = ((((2 * gBattleMons[battlerAtk].level / 5 + 2) * power * attackerAtkStat) / targetDefStat) / 50); @@ -11572,6 +10140,8 @@ void SetShellSideArmCategory(void) statStage = gBattleMons[battlerDef].statStages[STAT_SPDEF]; targetSpDefStat *= gStatStageRatios[statStage][0]; targetSpDefStat /= gStatStageRatios[statStage][1]; + if (targetSpDefStat == 0) + targetSpDefStat = 1; special = ((((2 * gBattleMons[battlerAtk].level / 5 + 2) * power * attackerSpAtkStat) / targetSpDefStat) / 50); @@ -11590,7 +10160,7 @@ bool32 CanTargetPartner(u32 battlerAtk, u32 battlerDef) && battlerDef != BATTLE_PARTNER(battlerAtk)); } -static inline bool32 DoesBattlerHaveAbilityImmunity(u32 battlerAtk, u32 battlerDef, u32 moveType) +static inline bool32 DoesBattlerHaveAbilityImmunity(u32 battlerAtk, u32 battlerDef, enum Type moveType) { enum Ability abilityDef = GetBattlerAbility(battlerDef); @@ -11600,14 +10170,14 @@ static inline bool32 DoesBattlerHaveAbilityImmunity(u32 battlerAtk, u32 battlerD bool32 TargetFullyImmuneToCurrMove(u32 battlerAtk, u32 battlerDef) { - u32 moveType = GetBattleMoveType(gCurrentMove); + enum Type moveType = GetBattleMoveType(gCurrentMove); return ((CalcTypeEffectivenessMultiplierHelper(gCurrentMove, moveType, battlerAtk, battlerDef, GetBattlerAbility(battlerAtk), GetBattlerAbility(battlerDef), FALSE) == UQ_4_12(0.0)) || IsBattlerProtected(battlerAtk, battlerDef, gCurrentMove) || !BreaksThroughSemiInvulnerablity(battlerDef, gCurrentMove) || DoesBattlerHaveAbilityImmunity(battlerAtk, battlerDef, moveType)); } -u32 GetBattleMoveType(u32 move) +enum Type GetBattleMoveType(u32 move) { if (gMain.inBattle && gBattleStruct->dynamicMoveType) return gBattleStruct->dynamicMoveType & DYNAMIC_TYPE_MASK; @@ -11741,26 +10311,13 @@ bool32 HasWeatherEffect(void) return TRUE; } -static bool32 IsAnyTargetAffected(u32 battlerAtk) -{ - for (u32 battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) - { - if (battlerAtk == battlerDef) - continue; - - if (!(gBattleStruct->moveResultFlags[battlerDef] & MOVE_RESULT_NO_EFFECT)) - return TRUE; - } - return FALSE; -} - void UpdateStallMons(void) { if (IsBattlerTurnDamaged(gBattlerTarget) || IsBattlerProtected(gBattlerAttacker, gBattlerTarget, gCurrentMove) || gMovesInfo[gCurrentMove].category == DAMAGE_CATEGORY_STATUS) return; if (!IsDoubleBattle() || gMovesInfo[gCurrentMove].target == MOVE_TARGET_SELECTED) { - u32 moveType = GetBattleMoveType(gCurrentMove); // Probably doesn't handle dynamic move types right now + enum Type moveType = GetBattleMoveType(gCurrentMove); // Probably doesn't handle dynamic move types right now enum Ability abilityAtk = GetBattlerAbility(gBattlerAttacker); enum Ability abilityDef = GetBattlerAbility(gBattlerTarget); if (CanAbilityAbsorbMove(gBattlerAttacker, gBattlerTarget, abilityDef, gCurrentMove, moveType, CHECK_TRIGGER)) @@ -11779,18 +10336,7 @@ void UpdateStallMons(void) // Handling for moves that target multiple opponents in doubles not handled currently } -bool32 TryRestoreHPBerries(u32 battler, enum ItemCaseId caseId) -{ - if (gItemsInfo[gBattleMons[battler].item].pocket == POCKET_BERRIES - || GetBattlerHoldEffect(battler) == HOLD_EFFECT_RESTORE_HP) // Edge case for Berry Juice - { - if (ItemBattleEffects(caseId, battler)) - return TRUE; - } - return FALSE; -} - -bool32 TrySwitchInEjectPack(enum ItemCaseId caseID) +bool32 TrySwitchInEjectPack(enum EjectPackTiming timing) { // 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. u32 ejectPackBattlers = 0; @@ -11827,15 +10373,12 @@ bool32 TrySwitchInEjectPack(enum ItemCaseId caseID) gBattleScripting.battler = battler; gLastUsedItem = gBattleMons[battler].item; - if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN) - { + if (timing == FIRST_TURN) BattleScriptPushCursorAndCallback(BattleScript_EjectPackActivate_End3); - } + else if (timing == END_TURN) + BattleScriptExecute(BattleScript_EjectPackActivate_End2); else - { - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_EjectPackActivate_Ret; - } + BattleScriptCall(BattleScript_EjectPackActivate_Ret); gAiLogicData->ejectPackSwitch = TRUE; return TRUE; } @@ -11988,7 +10531,7 @@ bool32 CanMoveSkipAccuracyCalc(u32 battlerAtk, u32 battlerDef, enum Ability abil u32 nonVolatileStatus = GetMoveNonVolatileStatus(move); if ((gBattleMons[battlerDef].volatiles.lockOn && gDisableStructs[battlerDef].battlerWithSureHit == battlerAtk) - || (B_TOXIC_NEVER_MISS >= GEN_6 && nonVolatileStatus == MOVE_EFFECT_TOXIC && IS_BATTLER_OF_TYPE(battlerAtk, TYPE_POISON)) + || (GetGenConfig(GEN_CONFIG_TOXIC_NEVER_MISS) >= GEN_6 && nonVolatileStatus == MOVE_EFFECT_TOXIC && IS_BATTLER_OF_TYPE(battlerAtk, TYPE_POISON)) || gBattleMons[battlerDef].volatiles.glaiveRush) { effect = TRUE; @@ -12064,7 +10607,7 @@ bool32 CanMoveSkipAccuracyCalc(u32 battlerAtk, u32 battlerDef, enum Ability abil return effect; } -u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, enum Ability atkAbility, enum Ability defAbility, u32 atkHoldEffect, u32 defHoldEffect) +u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, enum Ability atkAbility, enum Ability defAbility, enum HoldEffect atkHoldEffect, enum HoldEffect defHoldEffect) { u32 calc, moveAcc; s8 buff, accStage, evasionStage; @@ -12161,6 +10704,8 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, enum Ability atkA if (HasBattlerActedThisTurn(battlerDef)) calc = (calc * (100 + atkParam)) / 100; break; + default: + break; } // Target's hold effect @@ -12169,10 +10714,13 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, enum Ability atkA case HOLD_EFFECT_EVASION_UP: calc = (calc * (100 - defParam)) / 100; break; + default: + break; } if (gBattleStruct->battlerState[battlerAtk].usedMicleBerry) { + // TODO: Is this true? if (atkAbility == ABILITY_RIPEN) calc = (calc * 140) / 100; // ripen gives 40% acc boost else @@ -12220,6 +10768,39 @@ bool32 BreaksThroughSemiInvulnerablity(u32 battler, u32 move) return FALSE; } +bool32 HasPartnerTrainer(u32 battler) +{ + if ((GetBattlerSide(battler) == B_SIDE_PLAYER && gBattleTypeFlags & BATTLE_TYPE_PLAYER_HAS_PARTNER) + || (GetBattlerSide(battler) == B_SIDE_OPPONENT && gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)) + return TRUE; + else + return FALSE; +} + +static bool32 IsOpposingSideEmpty(u32 battler) +{ + u32 oppositeBattler = BATTLE_OPPOSITE(battler); + + if (IsBattlerAlive(oppositeBattler)) + return FALSE; + + if (!IsDoubleBattle()) + return TRUE; + + if (IsBattlerAlive(BATTLE_PARTNER(oppositeBattler))) + return FALSE; + return TRUE; +} + +bool32 IsAffectedByPowderMove(u32 battler, u32 ability, enum HoldEffect holdEffect) +{ + if ((GetGenConfig(GEN_CONFIG_POWDER_OVERCOAT) >= GEN_6 && ability == ABILITY_OVERCOAT) + || (GetGenConfig(GEN_CONFIG_POWDER_GRASS) >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GRASS)) + || holdEffect == HOLD_EFFECT_SAFETY_GOGGLES) + return FALSE; + return TRUE; +} + static u32 GetMirrorMoveMove(void) { s32 i, validMovesCount; @@ -12421,6 +11002,18 @@ void RemoveAbilityFlags(u32 battler) } } +bool32 IsAnyTargetTurnDamaged(u32 battlerAtk) +{ + for (u32 battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) + { + if (battlerDef == battlerAtk) + continue; + if (IsBattlerTurnDamaged(battlerDef)) + return TRUE; + } + return FALSE; +} + bool32 IsAllowedToUseBag(void) { switch(VarGet(B_VAR_NO_BAG_USE)) @@ -12435,3 +11028,9 @@ bool32 IsAllowedToUseBag(void) return TRUE; // Undefined Behavior } } + +bool32 IsMimikyuDisguised(u32 battler) +{ + return gBattleMons[battler].species == SPECIES_MIMIKYU_DISGUISED + || gBattleMons[battler].species == SPECIES_MIMIKYU_TOTEM_DISGUISED; +} diff --git a/src/battle_z_move.c b/src/battle_z_move.c index 8125c8b55..2ec4678a2 100644 --- a/src/battle_z_move.c +++ b/src/battle_z_move.c @@ -36,7 +36,6 @@ #include "constants/songs.h" #include "constants/items.h" #include "constants/species.h" -#include "constants/hold_effects.h" #include "constants/battle_string_ids.h" #include "constants/battle_move_effects.h" #include "constants/abilities.h" @@ -113,7 +112,7 @@ bool32 IsZMove(u32 move) bool32 CanUseZMove(u32 battler) { - enum ItemHoldEffect holdEffect = GetBattlerHoldEffectIgnoreNegation(battler); + enum HoldEffect holdEffect = GetBattlerHoldEffectIgnoreNegation(battler); // Check if Player has Z-Power Ring. if (!TESTING && (battler == B_POSITION_PLAYER_LEFT @@ -144,7 +143,7 @@ bool32 CanUseZMove(u32 battler) u32 GetUsableZMove(u32 battler, u32 move) { u32 item = gBattleMons[battler].item; - enum ItemHoldEffect holdEffect = GetBattlerHoldEffectIgnoreNegation(battler); + enum HoldEffect holdEffect = GetBattlerHoldEffectIgnoreNegation(battler); if (holdEffect == HOLD_EFFECT_Z_CRYSTAL) { @@ -167,7 +166,7 @@ void ActivateZMove(u32 battler) bool32 IsViableZMove(u32 battler, u32 move) { u32 item; - enum ItemHoldEffect holdEffect = GetBattlerHoldEffectIgnoreNegation(battler); + enum HoldEffect holdEffect = GetBattlerHoldEffectIgnoreNegation(battler); int moveSlotIndex; item = gBattleMons[battler].item; @@ -419,7 +418,7 @@ static void ZMoveSelectionDisplayPpNumber(u32 battler) static void ZMoveSelectionDisplayMoveType(u16 zMove, u32 battler) { u8 *txtPtr, *end; - u32 zMoveType = GetBattleMoveType(zMove); + enum Type zMoveType = GetBattleMoveType(zMove); txtPtr = StringCopy(gDisplayedStringBattle, gText_MoveInterfaceType); *(txtPtr)++ = EXT_CTRL_CODE_BEGIN; @@ -507,7 +506,7 @@ void SetZEffect(void) case Z_EFFECT_RECOVER_HP: if (gBattleMons[gBattlerAttacker].hp != gBattleMons[gBattlerAttacker].maxHP) { - gBattleStruct->moveDamage[gBattlerAttacker] = (-1) * gBattleMons[gBattlerAttacker].maxHP; + SetHealAmount(gBattlerAttacker, gBattleMons[gBattlerAttacker].maxHP); gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_Z_RECOVER_HP; BattleScriptPush(gBattlescriptCurrInstr + Z_EFFECT_BS_LENGTH); gBattlescriptCurrInstr = BattleScript_RecoverHPZMove; diff --git a/src/data/battle_move_effects.h b/src/data/battle_move_effects.h index 094f2c7df..22d90f474 100644 --- a/src/data/battle_move_effects.h +++ b/src/data/battle_move_effects.h @@ -851,9 +851,9 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = .encourageEncore = TRUE, }, - [EFFECT_WORRY_SEED] = + [EFFECT_OVERWRITE_ABILITY] = { - .battleScript = BattleScript_EffectWorrySeed, + .battleScript = BattleScript_EffectOverwriteAbility, .battleTvScore = 0, // TODO: Assign points .encourageEncore = TRUE, }, @@ -1395,13 +1395,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = .battleScript = BattleScript_EffectHit, .battleTvScore = 0, // TODO: Assign points }, - - [EFFECT_SIMPLE_BEAM] = - { - .battleScript = BattleScript_EffectSimpleBeam, - .battleTvScore = 0, // TODO: Assign points - }, - + [EFFECT_ENTRAINMENT] = { .battleScript = BattleScript_EffectEntrainment, @@ -1984,12 +1978,6 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = .battleTvScore = 0, // TODO: Assign points }, - [EFFECT_HIT_SET_TERRAIN] = - { - .battleScript = BattleScript_EffectHitSetTerrain, - .battleTvScore = 0, // TODO: Assign points - }, - [EFFECT_DARK_VOID] = { .battleScript = BattleScript_EffectDarkVoid, diff --git a/src/data/hold_effects.h b/src/data/hold_effects.h new file mode 100644 index 000000000..221c9e166 --- /dev/null +++ b/src/data/hold_effects.h @@ -0,0 +1,649 @@ +const struct HoldEffectInfo gHoldEffectsInfo[HOLD_EFFECT_COUNT] = +{ + [HOLD_EFFECT_NONE] = + { + }, + + [HOLD_EFFECT_RESTORE_HP] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_CURE_PAR] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onStatusChange = TRUE, + }, + + [HOLD_EFFECT_CURE_SLP] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onStatusChange = TRUE, + }, + + [HOLD_EFFECT_CURE_PSN] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onStatusChange = TRUE, + }, + + [HOLD_EFFECT_CURE_BRN] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onStatusChange = TRUE, + }, + + [HOLD_EFFECT_CURE_FRZ] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onStatusChange = TRUE, + }, + + [HOLD_EFFECT_RESTORE_PP] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onAttackerAfterHit = TRUE, + }, + + [HOLD_EFFECT_CURE_CONFUSION] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onStatusChange = TRUE, + }, + + [HOLD_EFFECT_CURE_STATUS] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onStatusChange = TRUE, + }, + + [HOLD_EFFECT_CONFUSE_SPICY] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_CONFUSE_DRY] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_CONFUSE_SWEET] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_CONFUSE_BITTER] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_CONFUSE_SOUR] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_ATTACK_UP] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_DEFENSE_UP] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_SPEED_UP] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_SP_ATTACK_UP] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_SP_DEFENSE_UP] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_CRITICAL_UP] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_RANDOM_STAT_UP] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_EVASION_UP] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_WHITE_HERB] = + { + .whiteHerb = TRUE, + .whiteHerbFirstTurn = TRUE, + .whiteHerbEndTurn = TRUE, + .onFling = TRUE, + }, + + [HOLD_EFFECT_MACHO_BRACE] = + { + }, + + [HOLD_EFFECT_EXP_SHARE] = + { + }, + + [HOLD_EFFECT_QUICK_CLAW] = + { + }, + + [HOLD_EFFECT_FRIENDSHIP_UP] = + { + }, + + [HOLD_EFFECT_MENTAL_HERB] = + { + .onTargetAfterHit = TRUE, + .onAttackerAfterHit = TRUE, + .onFling = TRUE, + }, + + [HOLD_EFFECT_CHOICE_BAND] = + { + }, + + [HOLD_EFFECT_FLINCH] = + { + .onAttackerAfterHit = TRUE, + }, + + [HOLD_EFFECT_DOUBLE_PRIZE] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + }, + + [HOLD_EFFECT_REPEL] = + { + }, + + [HOLD_EFFECT_SOUL_DEW] = + { + }, + + [HOLD_EFFECT_DEEP_SEA_TOOTH] = + { + }, + + [HOLD_EFFECT_DEEP_SEA_SCALE] = + { + }, + + [HOLD_EFFECT_CAN_ALWAYS_RUN] = + { + }, + + [HOLD_EFFECT_PREVENT_EVOLVE] = + { + }, + + [HOLD_EFFECT_FOCUS_BAND] = + { + }, + + [HOLD_EFFECT_LUCKY_EGG] = + { + }, + + [HOLD_EFFECT_SCOPE_LENS] = + { + }, + + [HOLD_EFFECT_LEFTOVERS] = + { + .leftovers = TRUE, + }, + + [HOLD_EFFECT_DRAGON_SCALE] = + { + }, + + [HOLD_EFFECT_LIGHT_BALL] = + { + }, + + [HOLD_EFFECT_TYPE_POWER] = + { + }, + + [HOLD_EFFECT_UPGRADE] = + { + }, + + [HOLD_EFFECT_SHELL_BELL] = + { + .lifeOrbShellBell = TRUE, + }, + + [HOLD_EFFECT_LUCKY_PUNCH] = + { + }, + + [HOLD_EFFECT_METAL_POWDER] = + { + }, + + [HOLD_EFFECT_THICK_CLUB] = + { + }, + + [HOLD_EFFECT_LEEK] = + { + }, + + [HOLD_EFFECT_CHOICE_SCARF] = + { + }, + + [HOLD_EFFECT_CHOICE_SPECS] = + { + }, + + [HOLD_EFFECT_DAMP_ROCK] = + { + }, + + [HOLD_EFFECT_GRIP_CLAW] = + { + }, + + [HOLD_EFFECT_HEAT_ROCK] = + { + }, + + [HOLD_EFFECT_ICY_ROCK] = + { + }, + + [HOLD_EFFECT_LIGHT_CLAY] = + { + }, + + [HOLD_EFFECT_SMOOTH_ROCK] = + { + }, + + [HOLD_EFFECT_POWER_HERB] = + { + }, + + [HOLD_EFFECT_BIG_ROOT] = + { + }, + + [HOLD_EFFECT_EXPERT_BELT] = + { + }, + + [HOLD_EFFECT_LIFE_ORB] = + { + .lifeOrbShellBell = TRUE, + }, + + [HOLD_EFFECT_METRONOME] = + { + }, + + [HOLD_EFFECT_MUSCLE_BAND] = + { + }, + + [HOLD_EFFECT_WIDE_LENS] = + { + }, + + [HOLD_EFFECT_WISE_GLASSES] = + { + }, + + [HOLD_EFFECT_ZOOM_LENS] = + { + }, + + [HOLD_EFFECT_LAGGING_TAIL] = + { + }, + + [HOLD_EFFECT_FOCUS_SASH] = + { + }, + + [HOLD_EFFECT_FLAME_ORB] = + { + .orbs = TRUE, + }, + + [HOLD_EFFECT_TOXIC_ORB] = + { + .orbs = TRUE, + }, + + [HOLD_EFFECT_STICKY_BARB] = + { + .onTargetAfterHit = TRUE, + .orbs = TRUE, + }, + + [HOLD_EFFECT_IRON_BALL] = + { + }, + + [HOLD_EFFECT_BLACK_SLUDGE] = + { + .leftovers = TRUE, + }, + + [HOLD_EFFECT_DESTINY_KNOT] = + { + }, + + [HOLD_EFFECT_SHED_SHELL] = + { + }, + + [HOLD_EFFECT_QUICK_POWDER] = + { + }, + + [HOLD_EFFECT_ADAMANT_ORB] = + { + }, + + [HOLD_EFFECT_LUSTROUS_ORB] = + { + }, + + [HOLD_EFFECT_GRISEOUS_ORB] = + { + }, + + [HOLD_EFFECT_ENIGMA_BERRY] = + { + .onTargetAfterHit = TRUE, + }, + + [HOLD_EFFECT_RESIST_BERRY] = + { + }, + + [HOLD_EFFECT_POWER_ITEM] = + { + }, + + [HOLD_EFFECT_RESTORE_PCT_HP] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_MICLE_BERRY] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_CUSTAP_BERRY] = + { + }, + + [HOLD_EFFECT_JABOCA_BERRY] = + { + .onTargetAfterHit = TRUE, + }, + + [HOLD_EFFECT_ROWAP_BERRY] = + { + .onTargetAfterHit = TRUE, + }, + + [HOLD_EFFECT_KEE_BERRY] = + { + .keeMarangaBerry = TRUE, + }, + + [HOLD_EFFECT_MARANGA_BERRY] = + { + .keeMarangaBerry = TRUE, + }, + + [HOLD_EFFECT_PLATE] = + { + }, + + [HOLD_EFFECT_FLOAT_STONE] = + { + }, + + [HOLD_EFFECT_EVIOLITE] = + { + }, + + [HOLD_EFFECT_ASSAULT_VEST] = + { + }, + + [HOLD_EFFECT_DRIVE] = + { + }, + + [HOLD_EFFECT_GEMS] = + { + }, + + [HOLD_EFFECT_ROCKY_HELMET] = + { + .onTargetAfterHit = TRUE, + }, + + [HOLD_EFFECT_AIR_BALLOON] = + { + .onTargetAfterHit = TRUE, + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + }, + + [HOLD_EFFECT_RED_CARD] = + { + }, + + [HOLD_EFFECT_RING_TARGET] = + { + }, + + [HOLD_EFFECT_BINDING_BAND] = + { + }, + + [HOLD_EFFECT_EJECT_BUTTON] = + { + }, + + [HOLD_EFFECT_ABSORB_BULB] = + { + .onTargetAfterHit = TRUE, + }, + + [HOLD_EFFECT_CELL_BATTERY] = + { + .onTargetAfterHit = TRUE, + }, + + [HOLD_EFFECT_MEGA_STONE] = + { + }, + + [HOLD_EFFECT_SAFETY_GOGGLES] = + { + }, + + [HOLD_EFFECT_LUMINOUS_MOSS] = + { + .onTargetAfterHit = TRUE, + }, + + [HOLD_EFFECT_SNOWBALL] = + { + .onTargetAfterHit = TRUE, + }, + + [HOLD_EFFECT_WEAKNESS_POLICY] = + { + .onTargetAfterHit = TRUE, + }, + + [HOLD_EFFECT_PRIMAL_ORB] = + { + }, + + [HOLD_EFFECT_PROTECTIVE_PADS] = + { + }, + + [HOLD_EFFECT_TERRAIN_EXTENDER] = + { + }, + + [HOLD_EFFECT_TERRAIN_SEED] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onEffect = TRUE, + }, + + [HOLD_EFFECT_ADRENALINE_ORB] = + { + }, + + [HOLD_EFFECT_MEMORY] = + { + }, + + [HOLD_EFFECT_Z_CRYSTAL] = + { + }, + + [HOLD_EFFECT_UTILITY_UMBRELLA] = + { + }, + + [HOLD_EFFECT_EJECT_PACK] = + { + }, + + [HOLD_EFFECT_ROOM_SERVICE] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onEffect = TRUE, + }, + + [HOLD_EFFECT_BLUNDER_POLICY] = + { + .onAttackerAfterHit = TRUE, + }, + + [HOLD_EFFECT_HEAVY_DUTY_BOOTS] = + { + }, + + [HOLD_EFFECT_THROAT_SPRAY] = + { + .onAttackerAfterHit = TRUE, + }, + + [HOLD_EFFECT_ABILITY_SHIELD] = + { + }, + + [HOLD_EFFECT_CLEAR_AMULET] = + { + }, + + [HOLD_EFFECT_MIRROR_HERB] = + { + .mirrorHerb = TRUE, + .mirrorHerbFirstTurn = TRUE, + }, + + [HOLD_EFFECT_PUNCHING_GLOVE] = + { + }, + + [HOLD_EFFECT_COVERT_CLOAK] = + { + }, + + [HOLD_EFFECT_LOADED_DICE] = + { + }, + + [HOLD_EFFECT_BOOSTER_ENERGY] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onEffect = TRUE, + }, + + [HOLD_EFFECT_OGERPON_MASK] = + { + }, + + [HOLD_EFFECT_BERSERK_GENE] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + }, +}; diff --git a/src/data/items.h b/src/data/items.h index 6e33f1174..107fde743 100644 --- a/src/data/items.h +++ b/src/data/items.h @@ -6366,6 +6366,474 @@ const struct Item gItemsInfo[] = .iconPalette = gItemIconPalette_Diancite, }, + [ITEM_CLEFABLITE] = + { + .name = ITEM_NAME("Clefablite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables " + "Clefable to\nMega " + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Clefablite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Clefablite, + }, + + [ITEM_VICTREEBELITE] = + { + .name = ITEM_NAME("Victreebelite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables " + "Victreebel to\nMega " + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Victreebelite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Victreebelite, + }, + + [ITEM_STARMINITE] = + { + .name = ITEM_NAME("Starminite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables " + "Starmie to\nMega " + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Starminite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Starminite, + }, + + [ITEM_DRAGONINITE] = + { + .name = ITEM_NAME("Dragoninite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables " + "Dragonite to\nMega " + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Dragoninite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Dragoninite, + }, + + [ITEM_MEGANIUMITE] = + { + .name = ITEM_NAME("Meganiumite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables " + "Meganium to\nMega " + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Meganiumite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Meganiumite, + }, + + [ITEM_FERALIGITE] = + { + .name = ITEM_NAME("Feraligite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables " + "Feraligatr to\nMega " + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Feraligite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Feraligite, + }, + + [ITEM_SKARMORITE] = + { + .name = ITEM_NAME("Skarmorite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables " + "Skarmory to\nMega " + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Skarmorite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Skarmorite, + }, + + [ITEM_FROSLASSITE] = + { + .name = ITEM_NAME("Froslassite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables " + "Froslass to\nMega " + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Froslassite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Froslassite, + }, + + [ITEM_EMBOARITE] = + { + .name = ITEM_NAME("Emboarite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables " + "Emboar to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Emboarite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Emboarite, + }, + + [ITEM_EXCADRITE] = + { + .name = ITEM_NAME("Excadrite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables " + "Excadrill to\nMega " + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Excadrite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Excadrite, + }, + + [ITEM_SCOLIPITE] = + { + .name = ITEM_NAME("Scolipite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables " + "Scolipede to\nMega " + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Scolipite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Scolipite, + }, + + [ITEM_SCRAFTINITE] = + { + .name = ITEM_NAME("Scraftinite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables " + "Scrafty to\nMega " + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Scraftinite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Scraftinite, + }, + + [ITEM_EELEKTROSSITE] = + { + .name = ITEM_NAME("Eelektrossite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables " + "Eelektross to\nMega " + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Eelektrossite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Eelektrossite, + }, + + [ITEM_CHANDELURITE] = + { + .name = ITEM_NAME("Chandelurite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables " + "Chandelure to\nMega " + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Chandelurite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Chandelurite, + }, + + [ITEM_CHESNAUGHTITE] = + { + .name = ITEM_NAME("Chesnaughtite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables " + "Chesnaught to\nMega " + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Chesnaughtite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Chesnaughtite, + }, + + [ITEM_DELPHOXITE] = + { + .name = ITEM_NAME("Delphoxite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables " + "Delphox to\nMega " + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Delphoxite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Delphoxite, + }, + + [ITEM_GRENINJITE] = + { + .name = ITEM_NAME("Greninjite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables " + "Greninja to\nMega " + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Greninjite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Greninjite, + }, + + [ITEM_PYROARITE] = + { + .name = ITEM_NAME("Pyroarite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables " + "Pyroar to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Pyroarite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Pyroarite, + }, + + [ITEM_FLOETTITE] = + { + .name = ITEM_NAME("Floettite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables " + "Floette to\nMega " + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Floettite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Floettite, + }, + + [ITEM_MALAMARITE] = + { + .name = ITEM_NAME("Malamarite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables " + "Malamar to\nMega " + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Malamarite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Malamarite, + }, + + [ITEM_BARBARACITE] = + { + .name = ITEM_NAME("Barbaracite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables " + "Barbaracle to\nMega " + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Barbaracite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Barbaracite, + }, + + [ITEM_DRAGALGITE] = + { + .name = ITEM_NAME("Dragalgite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables " + "Dragalge to\nMega " + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Dragalgite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Dragalgite, + }, + + [ITEM_HAWLUCHANITE] = + { + .name = ITEM_NAME("Hawluchanite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables " + "Hawlucha to\nMega " + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Hawluchanite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Hawluchanite, + }, + + [ITEM_ZYGARDITE] = + { + .name = ITEM_NAME("Zygardite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables " + "Zygarde to\nMega " + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Zygardite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Zygardite, + }, + + [ITEM_DRAMPANITE] = + { + .name = ITEM_NAME("Drampanite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables " + "Drampa to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Drampanite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Drampanite, + }, + + [ITEM_FALINKSITE] = + { + .name = ITEM_NAME("Falinksite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables " + "Falinks to\nMega " + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Falinksite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Falinksite, + }, + // Gems [ITEM_NORMAL_GEM] = @@ -8489,7 +8957,7 @@ const struct Item gItemsInfo[] = { .name = ITEM_NAME("Electric Seed"), .price = (I_PRICE >= GEN_9) ? 20000 : 4000, - .holdEffect = HOLD_EFFECT_SEEDS, + .holdEffect = HOLD_EFFECT_TERRAIN_SEED, .holdEffectParam = HOLD_EFFECT_PARAM_ELECTRIC_TERRAIN, .description = COMPOUND_STRING( "Boosts Defense on " @@ -8508,7 +8976,7 @@ const struct Item gItemsInfo[] = { .name = ITEM_NAME("Psychic Seed"), .price = (I_PRICE >= GEN_9) ? 20000 : 4000, - .holdEffect = HOLD_EFFECT_SEEDS, + .holdEffect = HOLD_EFFECT_TERRAIN_SEED, .holdEffectParam = HOLD_EFFECT_PARAM_PSYCHIC_TERRAIN, .description = COMPOUND_STRING( "Boosts Sp. Def. on " @@ -8527,7 +8995,7 @@ const struct Item gItemsInfo[] = { .name = ITEM_NAME("Misty Seed"), .price = (I_PRICE >= GEN_9) ? 20000 : 4000, - .holdEffect = HOLD_EFFECT_SEEDS, + .holdEffect = HOLD_EFFECT_TERRAIN_SEED, .holdEffectParam = HOLD_EFFECT_PARAM_MISTY_TERRAIN, .description = COMPOUND_STRING( "Boosts Sp. Def. on " @@ -8546,7 +9014,7 @@ const struct Item gItemsInfo[] = { .name = ITEM_NAME("Grassy Seed"), .price = (I_PRICE >= GEN_9) ? 20000 : 4000, - .holdEffect = HOLD_EFFECT_SEEDS, + .holdEffect = HOLD_EFFECT_TERRAIN_SEED, .holdEffectParam = HOLD_EFFECT_PARAM_GRASSY_TERRAIN, .description = COMPOUND_STRING( "Boosts Defense on " @@ -9826,7 +10294,7 @@ const struct Item gItemsInfo[] = "heals confusion " "\nin battle."), .pocket = POCKET_BERRIES, - .type = ITEM_USE_BAG_MENU, + .type = ITEM_USE_PARTY_MENU, .fieldUseFunc = ItemUseOutOfBattle_CannotUse, .battleUsage = EFFECT_ITEM_CURE_STATUS, .effect = gItemEffect_PersimBerry, diff --git a/src/data/moves_info.h b/src/data/moves_info.h index 4ee89d74e..00608542f 100644 --- a/src/data/moves_info.h +++ b/src/data/moves_info.h @@ -179,7 +179,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_FOCUS_ENERGY}, @@ -202,8 +202,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_POUND}, .battleAnimScript = gBattleAnimMove_DoubleSlap, @@ -226,7 +226,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .punchingMove = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -249,7 +249,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .punchingMove = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_FOCUS_ENERGY, COMBO_STARTER_MIND_READER}, @@ -274,7 +274,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_PAYDAY, }), - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST : CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -302,7 +302,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .chance = 10, }), .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = COMBO_STARTER_FIRE_PUNCH, .contestComboMoves = {COMBO_STARTER_ICE_PUNCH, COMBO_STARTER_SUNNY_DAY, COMBO_STARTER_THUNDER_PUNCH}, .battleAnimScript = gBattleAnimMove_FirePunch, @@ -503,7 +503,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .slicingMove = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SWORDS_DANCE}, @@ -527,7 +527,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresKingsRock = (B_UPDATED_MOVE_FLAGS == GEN_4) || (B_UPDATED_MOVE_FLAGS < GEN_3), .damagesAirborneDoubleDamage = TRUE, .windMove = TRUE, - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MON : CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -549,7 +549,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -577,7 +577,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .magicCoatAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_NEXT_APPEAL_LATER : CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -605,7 +605,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .instructBanned = TRUE, .assistBanned = TRUE, .argument.twoTurnAttack = { .stringId = STRINGID_PKMNFLEWHIGH, .status = STATE_ON_AIR }, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE_ONCE : CONTEST_EFFECT_AVOID_STARTLE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -657,7 +657,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_POUND}, @@ -714,7 +714,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_LEER}, @@ -738,7 +738,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .strikeCount = 2, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL : CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -761,7 +761,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_FOCUS_ENERGY, COMBO_STARTER_MIND_READER}, @@ -819,7 +819,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -843,7 +843,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_EVSN_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION : CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = COMBO_STARTER_SAND_ATTACK, .contestComboMoves = {COMBO_STARTER_MUD_SLAP, COMBO_STARTER_SANDSTORM}, @@ -870,7 +870,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_STARTLE_PREV_MON, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_FOCUS_ENERGY}, @@ -915,7 +915,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_HORN_ATTACK, COMBO_STARTER_PECK}, @@ -1073,7 +1073,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_THRASH, .self = TRUE, }), - .contestEffect = CONTEST_EFFECT_JAMS_OTHERS_BUT_MISS_ONE_TURN, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_USER_MORE_EASILY_STARTLED : CONTEST_EFFECT_JAMS_OTHERS_BUT_MISS_ONE_TURN, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_RAGE}, @@ -1173,7 +1173,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_POISON, .chance = 20, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_SAME_TYPE : CONTEST_EFFECT_STARTLE_PREV_MON, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -1195,7 +1195,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -1218,7 +1218,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_ATK_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION : CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = COMBO_STARTER_LEER, .contestComboMoves = {COMBO_STARTER_RAGE, COMBO_STARTER_SCARY_FACE}, @@ -1245,7 +1245,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MON : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_LEER, COMBO_STARTER_SCARY_FACE}, @@ -1299,7 +1299,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .soundMove = TRUE, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_NEXT_APPEAL_LATER : CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -1352,7 +1352,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresSubstitute = B_UPDATED_MOVE_FLAGS >= GEN_6, .magicCoatAffected = TRUE, .soundMove = TRUE, - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION : CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -1375,7 +1375,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .argument = { .fixedDamage = 20 }, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -1442,7 +1442,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = B_UPDATED_MOVE_DATA >= GEN_4 ? MOVE_EFFECT_SP_DEF_MINUS_1 : MOVE_EFFECT_DEF_MINUS_1, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -1468,7 +1468,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .chance = 10, }), .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SUNNY_DAY}, .battleAnimScript = gBattleAnimMove_Ember, @@ -1561,7 +1561,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_RAIN_DANCE}, @@ -1589,7 +1589,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .damagesUnderwater = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MONS : CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = COMBO_STARTER_SURF, .contestComboMoves = {COMBO_STARTER_DIVE, COMBO_STARTER_RAIN_DANCE}, @@ -1621,7 +1621,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FREEZE_OR_FROSTBITE, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON : CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_HAIL}, @@ -1653,7 +1653,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FREEZE_OR_FROSTBITE, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_HAIL, COMBO_STARTER_POWDER_SNOW}, @@ -1679,7 +1679,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_CONFUSION, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION : CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CALM_MIND}, @@ -1705,7 +1705,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SPD_MINUS_1, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MON : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_RAIN_DANCE}, @@ -1730,7 +1730,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_ATK_MINUS_1, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MON : CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_HAIL}, @@ -1799,7 +1799,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_PECK}, @@ -1846,7 +1846,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_WHEN_LATER : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -1874,7 +1874,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .metronomeBanned = B_UPDATED_MOVE_FLAGS >= GEN_2, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_LAST : CONTEST_EFFECT_AVOID_STARTLE_ONCE, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_TAUNT}, @@ -1898,7 +1898,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_FAKE_OUT}, @@ -1921,7 +1921,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -1946,7 +1946,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .absorbPercentage = 50 }, .ignoresKingsRock = (B_UPDATED_MOVE_FLAGS == GEN_3 || B_UPDATED_MOVE_FLAGS == GEN_4), .healingMove = B_HEAL_BLOCKING >= GEN_6, - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_STARTLE_PREV_MON, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_GROWTH}, @@ -1969,7 +1969,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .powerOverride = 120 }, .ignoresKingsRock = (B_UPDATED_MOVE_FLAGS == GEN_3 || B_UPDATED_MOVE_FLAGS == GEN_4), .healingMove = B_HEAL_BLOCKING >= GEN_6, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MON : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_GROWTH}, @@ -1992,7 +1992,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_RESET_STATS }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS : CONTEST_EFFECT_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = COMBO_STARTER_LEECH_SEED, .contestComboMoves = {COMBO_STARTER_GROWTH, COMBO_STARTER_WORRY_SEED}, @@ -2047,7 +2047,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .slicingMove = TRUE, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_GROWTH}, @@ -2072,7 +2072,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .sleepTalkBanned = TRUE, .instructBanned = TRUE, .argument.twoTurnAttack = { .stringId = STRINGID_PKMNTOOKSUNLIGHT, .status = B_WEATHER_SUN }, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_GROWTH, COMBO_STARTER_SUNNY_DAY}, @@ -2185,7 +2185,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_THRASH, .self = TRUE, }), - .contestEffect = CONTEST_EFFECT_JAMS_OTHERS_BUT_MISS_ONE_TURN, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_USER_MORE_EASILY_STARTLED : CONTEST_EFFECT_JAMS_OTHERS_BUT_MISS_ONE_TURN, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_GROWTH}, @@ -2232,7 +2232,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .ignoresKingsRock = (B_UPDATED_MOVE_FLAGS == GEN_4) || (B_UPDATED_MOVE_FLAGS < GEN_3), .argument = { .fixedDamage = 40 }, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_BETTER_WHEN_LATER, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = COMBO_STARTER_DRAGON_RAGE, .contestComboMoves = {COMBO_STARTER_DRAGON_BREATH, COMBO_STARTER_DRAGON_DANCE, COMBO_STARTER_DRAGON_RUSH, COMBO_STARTER_DRAGON_TAIL}, @@ -2335,7 +2335,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .nonVolatileStatus = MOVE_EFFECT_PARALYSIS }, .zMove = { .effect = Z_EFFECT_SPDEF_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS : CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CHARGE}, @@ -2364,7 +2364,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_PARALYSIS, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED : CONTEST_EFFECT_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CHARGE, COMBO_STARTER_LOCK_ON, COMBO_STARTER_RAIN_DANCE}, @@ -2386,7 +2386,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_ROCK_THROW, .contestComboMoves = {0}, @@ -2410,7 +2410,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresKingsRock = B_UPDATED_MOVE_FLAGS < GEN_3, .damagesUnderground = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_EARTHQUAKE, .contestComboMoves = {0}, @@ -2462,8 +2462,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .assistBanned = TRUE, .skyBattleBanned = TRUE, .argument.twoTurnAttack = { .stringId = STRINGID_PKMNDUGHOLE, .status = STATE_UNDERGROUND }, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE_ONCE : CONTEST_EFFECT_AVOID_STARTLE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Dig, @@ -2513,7 +2513,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_CONFUSION, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_STARTLE_PREV_MON, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = COMBO_STARTER_CONFUSION, .contestComboMoves = {COMBO_STARTER_CALM_MIND, COMBO_STARTER_KINESIS, COMBO_STARTER_PSYCHIC}, @@ -2538,7 +2538,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_DEF_MINUS_1, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = COMBO_STARTER_PSYCHIC, .contestComboMoves = {COMBO_STARTER_CALM_MIND, COMBO_STARTER_CONFUSION, COMBO_STARTER_KINESIS}, @@ -2661,8 +2661,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS : CONTEST_EFFECT_REPETITION_NOT_BORING, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_COOL, .contestComboStarterId = COMBO_STARTER_RAGE, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Rage, @@ -2712,7 +2712,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -2769,7 +2769,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresSubstitute = B_UPDATED_MOVE_FLAGS >= GEN_6, .magicCoatAffected = TRUE, .soundMove = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -2795,7 +2795,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .snatchAffected = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS : CONTEST_EFFECT_AVOID_STARTLE_ONCE, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = COMBO_STARTER_DOUBLE_TEAM, .contestComboMoves = {0}, @@ -2828,7 +2828,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .mirrorMoveBanned = TRUE, .healingMove = TRUE, .snatchAffected = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_SAME_TYPE : CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -2884,7 +2884,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .snatchAffected = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE : CONTEST_EFFECT_AVOID_STARTLE_ONCE, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -2908,7 +2908,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_EVSN_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MON : CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SMOG}, @@ -2932,7 +2932,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPATK_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION : CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -2958,7 +2958,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .snatchAffected = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE_ONCE : CONTEST_EFFECT_AVOID_STARTLE, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_RAIN_DANCE}, @@ -3036,7 +3036,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .snatchAffected = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE_ONCE : CONTEST_EFFECT_AVOID_STARTLE, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CALM_MIND}, @@ -3088,7 +3088,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .snatchAffected = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE_ONCE : CONTEST_EFFECT_AVOID_STARTLE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CALM_MIND}, @@ -3115,7 +3115,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .snatchAffected = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = COMBO_STARTER_FOCUS_ENERGY, .contestComboMoves = {0}, @@ -3141,7 +3141,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .sleepTalkBanned = TRUE, .instructBanned = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_NEXT_APPEAL_LATER : CONTEST_EFFECT_AVOID_STARTLE, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -3171,7 +3171,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .instructBanned = TRUE, .encoreBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_REPETITION_NOT_BORING, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -3249,7 +3249,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .ballisticMove = TRUE, .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SOFT_BOILED}, .battleAnimScript = gBattleAnimMove_EggBomb, @@ -3275,8 +3275,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_PARALYSIS, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MON : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Lick, @@ -3301,7 +3301,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_POISON, .chance = 40, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_SMOG, .contestComboMoves = {0}, @@ -3326,7 +3326,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_POISON, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MON : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_SLUDGE, .contestComboMoves = {COMBO_STARTER_SLUDGE_BOMB}, @@ -3351,7 +3351,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_BONE_CLUB, .contestComboMoves = {COMBO_STARTER_BONEMERANG, COMBO_STARTER_BONE_RUSH, COMBO_STARTER_SHADOW_BONE}, @@ -3376,7 +3376,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_BURN, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SUNNY_DAY}, @@ -3405,7 +3405,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .chance = 20, }), #endif - .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_BETTER_IF_LAST, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_RAIN_DANCE}, @@ -3486,7 +3486,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, .onChargeTurnOnly = TRUE, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -3508,7 +3508,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -3534,7 +3534,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SPD_MINUS_1, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS : CONTEST_EFFECT_STARTLE_PREV_MON, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -3559,7 +3559,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .snatchAffected = TRUE, - .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE : CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -3583,7 +3583,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_EVSN_UP_1 }, .magicCoatAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, - .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = COMBO_STARTER_KINESIS, .contestComboMoves = {COMBO_STARTER_CONFUSION, COMBO_STARTER_PSYCHIC}, @@ -3610,8 +3610,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .snatchAffected = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_FIRST : CONTEST_EFFECT_HIGHLY_APPEALING, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = COMBO_STARTER_SOFT_BOILED, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_SoftBoiled, @@ -3671,7 +3671,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .nonVolatileStatus = MOVE_EFFECT_PARALYSIS }, .zMove = { .effect = Z_EFFECT_SPDEF_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_SAME_TYPE : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_LEER}, @@ -3730,7 +3730,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .nonVolatileStatus = MOVE_EFFECT_POISON }, .zMove = { .effect = Z_EFFECT_DEF_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION : CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -3752,8 +3752,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .ballisticMove = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Barrage, @@ -3777,7 +3777,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .makesContact = TRUE, .ignoresKingsRock = (B_UPDATED_MOVE_FLAGS == GEN_3 || B_UPDATED_MOVE_FLAGS == GEN_4), .healingMove = B_HEAL_BLOCKING >= GEN_6, - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONE : CONTEST_EFFECT_STARTLE_PREV_MON, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -3801,7 +3801,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .nonVolatileStatus = MOVE_EFFECT_SLEEP }, .zMove = { .effect = Z_EFFECT_SPD_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, //C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUICKLY_GROW_BORED : .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -3890,7 +3890,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SPD_MINUS_1, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_RAIN_DANCE}, @@ -3917,8 +3917,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_CONFUSION, .chance = 20, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_DizzyPunch, @@ -3989,7 +3989,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CALM_MIND}, @@ -4015,7 +4015,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .gravityBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, + .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, //C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUICKLY_GROW_BORED : .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -4040,7 +4040,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE : CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -4064,7 +4064,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_RAIN_DANCE, COMBO_STARTER_SWORDS_DANCE}, @@ -4111,7 +4111,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SCRATCH}, @@ -4133,7 +4133,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .strikeCount = 2, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_BONEMERANG, .contestComboMoves = {COMBO_STARTER_BONE_CLUB, COMBO_STARTER_BONE_RUSH, COMBO_STARTER_SHADOW_BONE}, @@ -4160,7 +4160,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .healingMove = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE : CONTEST_EFFECT_AVOID_STARTLE_ONCE, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = COMBO_STARTER_REST, .contestComboMoves = {COMBO_STARTER_BELLY_DRUM, COMBO_STARTER_CHARM, COMBO_STARTER_YAWN}, @@ -4186,7 +4186,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MONS : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_ROCK_THROW}, @@ -4214,7 +4214,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -4300,7 +4300,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_TRI_ATTACK, .chance = 20, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_LOCK_ON}, @@ -4350,7 +4350,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .slicingMove = TRUE, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SCRATCH, COMBO_STARTER_SWORDS_DANCE}, @@ -4378,7 +4378,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .mirrorMoveBanned = TRUE, .skyBattleBanned = TRUE, .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Substitute, @@ -4422,6 +4422,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .sketchBanned = TRUE, .battleAnimScript = gBattleAnimMove_Struggle, .validApprenticeMove = TRUE, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_TOUGH, }, [MOVE_SKETCH] = @@ -4474,7 +4476,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .strikeCount = 3, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_FOCUS_ENERGY}, @@ -4550,7 +4552,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPATK_UP_1 }, - .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_NEXT_APPEAL_EARLIER : CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = COMBO_STARTER_MIND_READER, .contestComboMoves = {0}, @@ -4602,7 +4604,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_BURN, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SUNNY_DAY}, @@ -4630,7 +4632,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, //C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUICKLY_GROW_BORED : .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_REST}, @@ -4729,7 +4731,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .windMove = TRUE, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, //C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_LAST : .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -4781,7 +4783,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_WHEN_LATER : CONTEST_EFFECT_BETTER_IF_LAST, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_ENDURE}, @@ -4810,7 +4812,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_RECOVER_HP }, .magicCoatAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, .ignoresSubstitute = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS : CONTEST_EFFECT_BETTER_WHEN_LATER, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CURSE}, @@ -4864,7 +4866,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .metronomeBanned = TRUE, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE_ONCE : CONTEST_EFFECT_AVOID_STARTLE, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_HARDEN}, @@ -4912,7 +4914,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPD_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS : CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_SCARY_FACE, .contestComboMoves = {COMBO_STARTER_LEER, COMBO_STARTER_RAGE}, @@ -4985,7 +4987,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_USER_MORE_EASILY_STARTLED : CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = COMBO_STARTER_BELLY_DRUM, .contestComboMoves = {0}, @@ -5038,7 +5040,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_ACC_MINUS_1, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS : CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = COMBO_STARTER_MUD_SLAP, .contestComboMoves = {COMBO_STARTER_MUD_SPORT, COMBO_STARTER_SAND_ATTACK, COMBO_STARTER_SANDSTORM}, @@ -5065,7 +5067,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_ACC_MINUS_1, .chance = 50, }), - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_LOCK_ON, COMBO_STARTER_RAIN_DANCE}, @@ -5120,7 +5122,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_PARALYSIS, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CHARGE, COMBO_STARTER_LOCK_ON}, @@ -5145,7 +5147,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_BOOST_CRITS }, .magicCoatAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, .ignoresSubstitute = TRUE, - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL : CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -5174,7 +5176,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .metronomeBanned = TRUE, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_GREAT_APPEAL_BUT_NO_MORE_MOVES, + .contestEffect = CONTEST_EFFECT_GREAT_APPEAL_BUT_NO_MORE_MOVES, //C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUICKLY_GROW_BORED : .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CURSE, COMBO_STARTER_ENDURE, COMBO_STARTER_MEAN_LOOK}, @@ -5201,7 +5203,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresSubstitute = B_UPDATED_MOVE_FLAGS >= GEN_6, .mirrorMoveBanned = TRUE, .soundMove = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, //C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUICKLY_GROW_BORED : .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_MEAN_LOOK, COMBO_STARTER_SING}, @@ -5255,7 +5257,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .metronomeBanned = TRUE, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE : CONTEST_EFFECT_AVOID_STARTLE_ONCE, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_TAUNT}, @@ -5277,7 +5279,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_BONE_RUSH, .contestComboMoves = {COMBO_STARTER_BONE_CLUB, COMBO_STARTER_BONEMERANG, COMBO_STARTER_FOCUS_ENERGY, COMBO_STARTER_SHADOW_BONE}, @@ -5299,7 +5301,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPD_UP_1 }, - .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_NEXT_APPEAL_EARLIER : CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = COMBO_STARTER_LOCK_ON, .contestComboMoves = {0}, @@ -5327,7 +5329,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_THRASH, .self = TRUE, }), - .contestEffect = CONTEST_EFFECT_JAMS_OTHERS_BUT_MISS_ONE_TURN, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_USER_MORE_EASILY_STARTLED : CONTEST_EFFECT_JAMS_OTHERS_BUT_MISS_ONE_TURN, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -5353,7 +5355,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .windMove = TRUE, - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS : CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_SANDSTORM, .contestComboMoves = {0}, @@ -5378,7 +5380,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .absorbPercentage = 50 }, .ignoresKingsRock = (B_UPDATED_MOVE_FLAGS == GEN_3 || B_UPDATED_MOVE_FLAGS == GEN_4), .healingMove = B_HEAL_BLOCKING >= GEN_6, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON : CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_GROWTH}, @@ -5406,7 +5408,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .metronomeBanned = TRUE, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_NEXT_APPEAL_LATER : CONTEST_EFFECT_AVOID_STARTLE_ONCE, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_ENDURE, .contestComboMoves = {0}, @@ -5430,7 +5432,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_DEF_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION : CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = COMBO_STARTER_CHARM, .contestComboMoves = {0}, @@ -5455,8 +5457,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .makesContact = TRUE, .instructBanned = TRUE, .parentalBondBanned = TRUE, - .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_DEFENSE_CURL, COMBO_STARTER_HARDEN}, .battleAnimScript = gBattleAnimMove_Rollout, @@ -5476,7 +5478,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, //C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUICKLY_GROW_BORED : .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SWORDS_DANCE}, @@ -5500,7 +5502,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_RESET_STATS }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_FIRST, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS : CONTEST_EFFECT_BETTER_IF_FIRST, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -5527,7 +5529,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_FIRST : CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -5554,7 +5556,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_PARALYSIS, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CHARGE}, @@ -5611,7 +5613,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL : CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -5693,7 +5695,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .mimicBanned = TRUE, .encoreBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_REPETITION_NOT_BORING, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_REST}, @@ -5721,7 +5723,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresSubstitute = TRUE, .mirrorMoveBanned = TRUE, .soundMove = B_UPDATED_MOVE_FLAGS != GEN_5, - .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE : CONTEST_EFFECT_BETTER_IF_LAST, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = COMBO_STARTER_HEAL_BELL, .contestComboMoves = {COMBO_STARTER_LUCKY_CHANT}, @@ -5744,7 +5746,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -5790,7 +5792,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MON : CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -5816,7 +5818,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE_ONCE : CONTEST_EFFECT_AVOID_STARTLE, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -5839,7 +5841,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_DEF_UP_1 }, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONES : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_ENDURE}, @@ -5866,7 +5868,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_BURN, .chance = 50, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_LAST : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SUNNY_DAY}, @@ -5940,7 +5942,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -5967,7 +5969,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_PARALYSIS, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MON : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = COMBO_STARTER_DRAGON_BREATH, .contestComboMoves = {COMBO_STARTER_DRAGON_DANCE, COMBO_STARTER_DRAGON_RAGE, COMBO_STARTER_DRAGON_RUSH, COMBO_STARTER_DRAGON_TAIL}, @@ -5992,7 +5994,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_RESET_STATS }, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION : CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -6042,7 +6044,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .ignoresKingsRock = (B_UPDATED_MOVE_FLAGS == GEN_3 || B_UPDATED_MOVE_FLAGS == GEN_4), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL : CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -6078,7 +6080,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = } #endif ), - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED : CONTEST_EFFECT_AVOID_STARTLE_ONCE, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -6107,7 +6109,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_ACC_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE_ONCE : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = COMBO_STARTER_SWEET_SCENT, .contestComboMoves = {0}, @@ -6134,7 +6136,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_DEF_MINUS_1, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -6185,7 +6187,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = -1, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_LATER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_LAST : CONTEST_EFFECT_NEXT_APPEAL_LATER, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_FAKE_OUT}, @@ -6345,7 +6347,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 20, }), - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -6370,7 +6372,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_RAIN_DANCE, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_RainDance, @@ -6456,7 +6458,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .meFirstBanned = TRUE, .metronomeBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_LAST : CONTEST_EFFECT_AVOID_STARTLE_ONCE, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_TAUNT}, @@ -6561,7 +6563,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_DEF_MINUS_1, .chance = 20, }), - .contestEffect = CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -6591,7 +6593,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_SAME_TYPE : CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CALM_MIND, COMBO_STARTER_CONFUSION, COMBO_STARTER_KINESIS, COMBO_STARTER_PSYCHIC}, @@ -6618,7 +6620,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_DEF_MINUS_1, .chance = 50, }), - .contestEffect = CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -6667,7 +6669,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION : CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -6694,7 +6696,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MON : CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = COMBO_STARTER_FAKE_OUT, .contestComboMoves = {0}, @@ -6706,12 +6708,12 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = { .name = COMPOUND_STRING("Uproar"), .description = COMPOUND_STRING( - #if B_UPROAR_TURNS >= GEN_5 - "Causes an uproar\nfor 2 to 5 " - #else - "Causes an uproar\nfor 3 " - #endif - "turns and prevents\nsleep."), + #if B_UPROAR_TURNS >= GEN_5 + "Causes an uproar\nfor 3 " + #else + "Causes an uproar\nfor 2 to 5 " + #endif + "turns and prevents\nsleep."), .effect = EFFECT_UPROAR, .power = B_UPDATED_MOVE_DATA >= GEN_5 ? 90 : 50, .type = TYPE_NORMAL, @@ -6728,7 +6730,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_UPROAR, .self = TRUE, }), - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION : CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -6754,7 +6756,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS : CONTEST_EFFECT_AVOID_STARTLE_ONCE, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_STOCKPILE, .contestComboMoves = {0}, @@ -6777,7 +6779,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_STOCKPILE}, @@ -6804,7 +6806,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE_ONCE : CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_STOCKPILE}, @@ -6831,7 +6833,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_BURN, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MONS : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SUNNY_DAY}, @@ -6863,7 +6865,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_SPD_UP_1 }, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = COMBO_STARTER_HAIL, .contestComboMoves = {0}, @@ -6936,7 +6938,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .nonVolatileStatus = MOVE_EFFECT_BURN }, .zMove = { .effect = Z_EFFECT_ATK_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SUNNY_DAY}, @@ -7013,7 +7015,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .copycatBanned = TRUE, .instructBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_LATER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_LAST : CONTEST_EFFECT_NEXT_APPEAL_LATER, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_FOCUS_ENERGY}, @@ -7040,8 +7042,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_REMOVE_STATUS, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL : CONTEST_EFFECT_STARTLE_PREV_MON, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_SmellingSalts, @@ -7123,7 +7125,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS : CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = COMBO_STARTER_CHARGE, .contestComboMoves = {0}, @@ -7148,7 +7150,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_ATK_UP_1 }, .ignoresSubstitute = TRUE, .magicCoatAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, - .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION : CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = COMBO_STARTER_TAUNT, .contestComboMoves = {0}, @@ -7177,7 +7179,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .metronomeBanned = TRUE, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -7203,7 +7205,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .metronomeBanned = TRUE, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL : CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -7256,7 +7258,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_LAST : CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -7314,7 +7316,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS : CONTEST_EFFECT_AVOID_STARTLE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -7366,7 +7368,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_SPDEF_UP_2 }, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_LAST : CONTEST_EFFECT_AVOID_STARTLE, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -7392,7 +7394,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONE : CONTEST_EFFECT_REPETITION_NOT_BORING, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -7413,7 +7415,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = -4, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_LATER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_LAST : CONTEST_EFFECT_NEXT_APPEAL_LATER, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_REVENGE, .contestComboMoves = {COMBO_STARTER_PAYBACK}, @@ -7436,7 +7438,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_FOCUS_ENERGY}, @@ -7484,7 +7486,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MON : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_FAKE_OUT}, @@ -7530,7 +7532,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_BOTH, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_USER_MORE_EASILY_STARTLED : CONTEST_EFFECT_BETTER_WHEN_LATER, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_EARTHQUAKE, COMBO_STARTER_ENDURE, COMBO_STARTER_SUNNY_DAY}, @@ -7582,7 +7584,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresSubstitute = TRUE, .mirrorMoveBanned = TRUE, .forcePressure = TRUE, - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_DONT_EXCITE_AUDIENCE : CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -7608,7 +7610,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE_ONCE : CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SING, COMBO_STARTER_WATER_SPORT}, @@ -7634,7 +7636,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .ignoresSubstitute = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_JAMS_OTHERS_BUT_MISS_ONE_TURN : CONTEST_EFFECT_BETTER_WHEN_LATER, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CURSE}, @@ -7662,7 +7664,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .metronomeBanned = TRUE, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONE : CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -7739,7 +7741,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_FAKE_OUT, COMBO_STARTER_FOCUS_ENERGY}, @@ -7764,7 +7766,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONES : CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -7820,7 +7822,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_DEF_MINUS_1, .chance = 50, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL : CONTEST_EFFECT_STARTLE_PREV_MON, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CALM_MIND}, @@ -7847,7 +7849,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_ATK_MINUS_1, .chance = 50, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CALM_MIND}, @@ -7925,8 +7927,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_BURN, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_HIGHLY_APPEALING, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SUNNY_DAY}, .battleAnimScript = gBattleAnimMove_BlazeKick, @@ -7952,7 +7954,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = COMBO_STARTER_MUD_SPORT, .contestComboMoves = {COMBO_STARTER_MUD_SLAP, COMBO_STARTER_SANDSTORM, COMBO_STARTER_WATER_SPORT}, @@ -8005,7 +8007,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -8032,7 +8034,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, + .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, //C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUICKLY_GROW_BORED : .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -8056,7 +8058,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .soundMove = TRUE, .ignoresSubstitute = B_UPDATED_MOVE_FLAGS >= GEN_6, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MONS : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -8084,7 +8086,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_TOXIC, .chance = B_UPDATED_MOVE_DATA >= GEN_6 ? 50 : 30, }), - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -8191,7 +8193,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, .chance = 20, }), - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -8220,7 +8222,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .chance = 30, }), .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Astonish, @@ -8243,8 +8245,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .zMove = { .powerOverride = 160 }, .ballisticMove = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_HIGHLY_APPEALING, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_HAIL, COMBO_STARTER_RAIN_DANCE, COMBO_STARTER_SANDSTORM, COMBO_STARTER_SUNNY_DAY}, .battleAnimScript = gBattleAnimMove_WeatherBall, @@ -8269,7 +8271,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE : CONTEST_EFFECT_BETTER_IF_LAST, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -8293,8 +8295,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPATK_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, //C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUICKLY_GROW_BORED : + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_FakeTears, @@ -8318,7 +8320,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .windMove = TRUE, .slicingMove = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -8370,7 +8372,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_ATK_UP_1 }, .ignoresSubstitute = TRUE, .magicCoatAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE_ONCE : CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -8396,7 +8398,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SPD_MINUS_1, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION : CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_ROCK_THROW}, @@ -8477,7 +8479,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresSubstitute = B_UPDATED_MOVE_FLAGS >= GEN_6, .magicCoatAffected = TRUE, .soundMove = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE_ONCE : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -8528,7 +8530,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_CosmicPower, @@ -8549,7 +8551,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_BOTH, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_USER_MORE_EASILY_STARTLED : CONTEST_EFFECT_BETTER_WHEN_LATER, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_RAIN_DANCE}, @@ -8575,7 +8577,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_CONFUSION, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION : CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -8626,7 +8628,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -8726,7 +8728,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_ACC_MINUS_1, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MONS : CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_RAIN_DANCE}, @@ -8749,7 +8751,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .ballisticMove = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_GROWTH}, @@ -8794,7 +8796,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -8871,7 +8873,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .soundMove = B_UPDATED_MOVE_FLAGS >= GEN_8, - .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_LAST : CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -8894,7 +8896,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_DRAGON_BREATH, COMBO_STARTER_DRAGON_DANCE, COMBO_STARTER_DRAGON_RAGE, COMBO_STARTER_DRAGON_RUSH, COMBO_STARTER_DRAGON_TAIL}, @@ -8948,7 +8950,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_BulkUp, @@ -9005,7 +9007,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SPD_MINUS_1, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SANDSTORM}, @@ -9079,7 +9081,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = "A life-risking\ntackle that " "\nslightly hurts the\nuser."), #endif - .effect = EFFECT_HIT, + .effect = EFFECT_RECOIL, .power = 120, .type = TYPE_ELECTRIC, .accuracy = 100, @@ -9144,7 +9146,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = COMBO_STARTER_WATER_SPORT, .contestComboMoves = {COMBO_STARTER_MUD_SPORT, COMBO_STARTER_RAIN_DANCE}, @@ -9170,7 +9172,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS : CONTEST_EFFECT_AVOID_STARTLE_ONCE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = COMBO_STARTER_CALM_MIND, .contestComboMoves = {0}, @@ -9195,7 +9197,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .slicingMove = TRUE, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -9245,7 +9247,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .ballisticMove = B_UPDATED_MOVE_FLAGS >= GEN_6, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -9293,7 +9295,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_CONFUSION, .chance = 20, }), - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION : CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_RAIN_DANCE}, @@ -9317,8 +9319,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, //C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_LAST : + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_DoomDesire, @@ -9370,8 +9372,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, //CONTEST_EFFECT_QUICKLY_GROW_BORED + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_BRAVE_BIRD}, .battleAnimScript = gBattleAnimMove_Roost, @@ -9395,8 +9397,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Gravity, @@ -9419,8 +9421,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_SPATK_UP_1 }, .ignoresSubstitute = TRUE, .magicCoatAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_BETTER_IF_FIRST, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_MiracleEye, @@ -9445,8 +9447,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_REMOVE_STATUS, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_WakeUpSlap, @@ -9472,8 +9474,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SPD_MINUS_1, .self = TRUE, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_FOCUS_ENERGY}, .battleAnimScript = gBattleAnimMove_HammerArm, @@ -9495,8 +9497,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .ballisticMove = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_GyroBall, @@ -9519,7 +9521,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .contestEffect = CONTEST_EFFECT_GREAT_APPEAL_BUT_NO_MORE_MOVES, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_HealingWish, @@ -9539,8 +9541,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_RAIN_DANCE}, .battleAnimScript = gBattleAnimMove_Brine, @@ -9560,8 +9562,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_NaturalGift, @@ -9587,8 +9589,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_FEINT, }), - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_EARLIER, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Feint, @@ -9610,7 +9612,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_BUG_BITE, }), - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -9641,7 +9643,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_EARLIER, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Tailwind, @@ -9665,8 +9667,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .snatchAffected = B_UPDATED_MOVE_FLAGS < GEN_5, - .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Acupressure, @@ -9687,8 +9689,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .meFirstBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_METAL_SOUND}, .battleAnimScript = gBattleAnimMove_MetalBurst, @@ -9707,7 +9709,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, //CONTEST_EFFECT_QUICKLY_GROW_BORED .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -9732,7 +9734,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, }), .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_FOCUS_ENERGY, COMBO_STARTER_MIND_READER}, .battleAnimScript = gBattleAnimMove_CloseCombat, @@ -9753,8 +9755,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_COOL, .contestComboStarterId = COMBO_STARTER_PAYBACK, .contestComboMoves = {COMBO_STARTER_REVENGE}, .battleAnimScript = gBattleAnimMove_Payback, @@ -9775,8 +9777,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_LATER, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_PAYBACK, COMBO_STARTER_REVENGE}, .battleAnimScript = gBattleAnimMove_Assurance, @@ -9798,8 +9800,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPATK_UP_1 }, .magicCoatAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, - .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Embargo, @@ -9820,8 +9822,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .parentalBondBanned = TRUE, - .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Fling, @@ -9842,8 +9844,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPATK_UP_2 }, - .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_PsychoShift, @@ -9887,8 +9889,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPATK_UP_2 }, .magicCoatAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, - .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_HealBlock, @@ -9907,8 +9909,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_WringOut, @@ -9932,8 +9934,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_PowerTrick, @@ -9955,8 +9957,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPD_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_GastroAcid, @@ -9980,7 +9982,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = COMBO_STARTER_LUCKY_CHANT, .contestComboMoves = {COMBO_STARTER_HEAL_BELL}, @@ -10013,7 +10015,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .assistBanned = TRUE, .mimicBanned = TRUE, .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_EARLIER, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_MeFirst, @@ -10044,7 +10046,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .assistBanned = TRUE, .mimicBanned = TRUE, .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONE, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Copycat, @@ -10067,7 +10069,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_SPD_UP_1 }, .ignoresSubstitute = TRUE, .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONES, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_PowerSwap, @@ -10089,8 +10091,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPD_UP_1 }, .ignoresSubstitute = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONES, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_GuardSwap, @@ -10111,8 +10113,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Punishment, @@ -10133,7 +10135,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, + .contestEffect = CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -10146,7 +10148,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .description = COMPOUND_STRING( "Plants a seed on\nthe foe " "giving it\nInsomnia."), - .effect = EFFECT_WORRY_SEED, + .effect = EFFECT_OVERWRITE_ABILITY, .power = 0, .type = TYPE_GRASS, .accuracy = 100, @@ -10154,10 +10156,11 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_STATUS, + .argument = { .overwriteAbility = ABILITY_INSOMNIA }, .zMove = { .effect = Z_EFFECT_SPD_UP_1 }, .magicCoatAffected = TRUE, .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = COMBO_STARTER_WORRY_SEED, .contestComboMoves = {COMBO_STARTER_LEECH_SEED}, .battleAnimScript = gBattleAnimMove_WorrySeed, @@ -10227,7 +10230,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_BOOST_CRITS }, .ignoresSubstitute = TRUE, .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONES, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_HeartSwap, @@ -10251,7 +10254,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -10277,8 +10280,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .gravityBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_MagnetRise, @@ -10306,7 +10309,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .chance = 10, }), .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SUNNY_DAY}, .battleAnimScript = gBattleAnimMove_FlareBlitz, @@ -10331,7 +10334,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_PARALYSIS, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -10405,8 +10408,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_POISON, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_PoisonJab, @@ -10431,7 +10434,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 20, }), - .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -10456,7 +10459,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .makesContact = TRUE, .slicingMove = TRUE, .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_NightSlash, @@ -10478,7 +10481,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_RAIN_DANCE}, .battleAnimScript = gBattleAnimMove_AquaTail, @@ -10500,7 +10503,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .ballisticMove = TRUE, .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_SeedBomb, @@ -10525,7 +10528,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -10548,8 +10551,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .slicingMove = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SWORDS_DANCE}, .battleAnimScript = gBattleAnimMove_XScissor, @@ -10575,8 +10578,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_DEF_MINUS_1, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTIFUL : CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_BugBuzz, @@ -10597,8 +10600,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .pulseMove = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_DragonPulse, @@ -10624,8 +10627,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 20, }), - .contestEffect = CONTEST_EFFECT_BETTER_IF_FIRST, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_COOL, .contestComboStarterId = COMBO_STARTER_DRAGON_RUSH, .contestComboMoves = {COMBO_STARTER_DRAGON_BREATH, COMBO_STARTER_DRAGON_DANCE, COMBO_STARTER_DRAGON_RAGE, COMBO_STARTER_DRAGON_TAIL}, .battleAnimScript = gBattleAnimMove_DragonRush, @@ -10668,8 +10671,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .makesContact = TRUE, .punchingMove = TRUE, .healingMove = B_HEAL_BLOCKING >= GEN_6, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_FOCUS_ENERGY}, .battleAnimScript = gBattleAnimMove_DrainPunch, @@ -10690,7 +10693,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 1, .category = DAMAGE_CATEGORY_SPECIAL, .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_EARLIER, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_VacuumWave, @@ -10715,7 +10718,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_DEF_MINUS_1, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_FOCUS_ENERGY}, @@ -10741,7 +10744,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_DEF_MINUS_1, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_GROWTH}, @@ -10765,7 +10768,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .recoilPercentage = 33 }, .makesContact = TRUE, .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_CUTE, .contestComboStarterId = COMBO_STARTER_BRAVE_BIRD, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_BraveBird, @@ -10790,8 +10793,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_DEF_MINUS_1, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_EarthPower, @@ -10815,8 +10818,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .metronomeBanned = TRUE, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Switcheroo, @@ -10840,7 +10843,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, }), .contestEffect = CONTEST_EFFECT_JAMS_OTHERS_BUT_MISS_ONE_TURN, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_GigaImpact, @@ -10865,7 +10868,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_NastyPlot, @@ -10888,7 +10891,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .makesContact = TRUE, .punchingMove = TRUE, .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_EARLIER, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_BulletPunch, @@ -10907,8 +10910,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = -4, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_LATER, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Avalanche, @@ -10951,8 +10954,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_ShadowClaw, @@ -10983,7 +10986,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .chance = 10, }), .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_SMART, .contestComboStarterId = COMBO_STARTER_THUNDER_FANG, .contestComboMoves = {COMBO_STARTER_CHARGE, COMBO_STARTER_FIRE_FANG, COMBO_STARTER_ICE_FANG}, .battleAnimScript = gBattleAnimMove_ThunderFang, @@ -11049,7 +11052,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .chance = 10, }), .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = COMBO_STARTER_FIRE_FANG, .contestComboMoves = {COMBO_STARTER_ICE_FANG, COMBO_STARTER_THUNDER_FANG}, .battleAnimScript = gBattleAnimMove_FireFang, @@ -11096,8 +11099,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_ACC_MINUS_1, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_MudBomb, @@ -11119,7 +11122,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .slicingMove = TRUE, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -11145,8 +11148,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 20, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_ZenHeadbutt, @@ -11170,8 +11173,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_ACC_MINUS_1, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_MirrorShot, @@ -11195,8 +11198,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_DEF_MINUS_1, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_FlashCannon, @@ -11221,7 +11224,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_CONFUSION, .chance = 20, }), - .contestEffect = CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION, + .contestEffect = CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -11245,8 +11248,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_ACC_UP_1 }, //.ignoresSubstitute = TRUE, In Gen5+, the evasion drop will no longer bypass Substitute. However, this is tricky to code .magicCoatAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_BETTER_IF_FIRST, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Defog, @@ -11268,8 +11271,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_ACC_UP_1 }, .ignoresProtect = TRUE, - .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_LATER, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_TrickRoom, @@ -11294,7 +11297,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, }), .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_DracoMeteor, @@ -11318,8 +11321,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_PARALYSIS, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CHARGE}, .battleAnimScript = gBattleAnimMove_Discharge, @@ -11341,7 +11344,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_BURN, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SUNNY_DAY}, @@ -11367,7 +11370,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, }), .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_LeafStorm, @@ -11388,8 +11391,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_GROWTH}, .battleAnimScript = gBattleAnimMove_PowerWhip, @@ -11440,7 +11443,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_POISON, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -11465,8 +11468,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_POISON, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_GunkShot, @@ -11491,7 +11494,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -11558,8 +11561,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPDEF_UP_2 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, //CONTEST_EFFECT_QUICKLY_GROW_BORED + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CHARM}, .battleAnimScript = gBattleAnimMove_Captivate, @@ -11607,8 +11610,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .makesContact = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_GrassKnot, @@ -11647,8 +11650,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .chance = 31, #endif }), - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Chatter, @@ -11669,8 +11672,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .argument = { .holdEffect = HOLD_EFFECT_PLATE }, - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Judgment, @@ -11692,8 +11695,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_BUG_BITE, }), - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_BugBite, @@ -11718,7 +11721,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, .chance = 70, }), - .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, + .contestEffect = CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CHARGE}, @@ -11764,7 +11767,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_EARLIER, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_RAIN_DANCE}, .battleAnimScript = gBattleAnimMove_AquaJet, @@ -11785,7 +11788,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = COMBO_STARTER_ATTACK_ORDER, .contestComboMoves = {COMBO_STARTER_DEFEND_ORDER, COMBO_STARTER_HEAL_ORDER}, @@ -11810,7 +11813,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = COMBO_STARTER_DEFEND_ORDER, .contestComboMoves = {COMBO_STARTER_ATTACK_ORDER, COMBO_STARTER_HEAL_ORDER}, @@ -11882,8 +11885,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .strikeCount = 2, - .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_DoubleHit, @@ -11908,7 +11911,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, }), .contestEffect = CONTEST_EFFECT_JAMS_OTHERS_BUT_MISS_ONE_TURN, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_RoarOfTime, @@ -11929,8 +11932,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_SpacialRend, @@ -11973,7 +11976,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -12023,7 +12026,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_RESET_STATS }, .magicCoatAffected = TRUE, .sketchBanned = (B_SKETCH_BANS >= GEN_9), - .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -12048,8 +12051,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_DEF_MINUS_2, .chance = 40, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_SeedFlare, @@ -12076,7 +12079,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .chance = 10, }), .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_OminousWind, @@ -12104,8 +12107,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_FEINT, }), - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_ShadowForce, @@ -12130,7 +12133,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_HoneClaws, @@ -12179,7 +12182,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPD_UP_1 }, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONES, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -12225,8 +12228,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPDEF_UP_1 }, .ignoresProtect = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, + .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_WonderRoom, @@ -12244,8 +12247,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Psyshock, @@ -12267,7 +12270,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .argument = { .status = STATUS1_PSN_ANY }, .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_TOXIC}, .battleAnimScript = gBattleAnimMove_Venoshock, @@ -12291,8 +12294,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_EARLIER, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Autotomize, @@ -12320,7 +12323,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .copycatBanned = TRUE, .assistBanned = TRUE, .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_RagePowder, @@ -12343,7 +12346,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_SPATK_UP_1 }, .magicCoatAffected = TRUE, .gravityBanned = TRUE, - .contestEffect = CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION, + .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -12366,7 +12369,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPDEF_UP_1 }, .ignoresProtect = TRUE, - .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, + .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -12389,7 +12392,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .damagesAirborne = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -12410,8 +12413,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .alwaysCriticalHit = TRUE, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_StormThrow, @@ -12435,7 +12438,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLAME_BURST, .self = TRUE, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, + .contestEffect = CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -12460,7 +12463,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_POISON, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -12487,7 +12490,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_QuiverDance, @@ -12508,7 +12511,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .makesContact = TRUE, .minimizeDoubleDamage = B_UPDATED_MOVE_FLAGS >= GEN_7, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -12529,7 +12532,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_FOES_AND_ALLY, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -12551,7 +12554,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .ballisticMove = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, //CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_FIRST .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -12575,8 +12578,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .type = TYPE_WATER }, .zMove = { .effect = Z_EFFECT_SPATK_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Soak, @@ -12602,8 +12605,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION, + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_FlameCharge, @@ -12628,7 +12631,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Coil, @@ -12653,8 +12656,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SPD_MINUS_1, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, + .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_LowSweep, @@ -12679,8 +12682,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_DEF_MINUS_2, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_AcidSpray, @@ -12701,8 +12704,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONE, + .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_FoulPlay, @@ -12714,7 +12717,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .description = COMPOUND_STRING( "A beam that\nchanges the " "foe's\nAbility to Simple."), - .effect = EFFECT_SIMPLE_BEAM, + .effect = EFFECT_OVERWRITE_ABILITY, .power = 0, .type = TYPE_NORMAL, .accuracy = 100, @@ -12722,9 +12725,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_STATUS, + .argument = { .overwriteAbility = ABILITY_SIMPLE }, .zMove = { .effect = Z_EFFECT_SPATK_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONES, + .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -12747,7 +12751,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPDEF_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -12799,8 +12803,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_ROUND, }), - .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Round, @@ -12823,7 +12827,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresSubstitute = B_UPDATED_MOVE_FLAGS >= GEN_6, .soundMove = TRUE, .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_EchoedVoice, @@ -12843,7 +12847,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .ignoresTargetDefenseEvasionStages = TRUE, - .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, + .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -12867,7 +12871,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_CLEAR_SMOG, }), - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestEffect = CONTEST_EFFECT_BETTER_IF_FIRST, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -12888,8 +12892,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION, + .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_StoredPower, @@ -12915,8 +12919,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .metronomeBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_BETTER_IF_FIRST, + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_QuickGuard, @@ -12965,7 +12969,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_BURN, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_SCALD, .contestComboMoves = {0}, @@ -12990,7 +12994,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, + .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -13016,8 +13020,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .mirrorMoveBanned = TRUE, .healingMove = TRUE, .pulseMove = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_HealPulse, @@ -13039,7 +13043,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .zMove = { .powerOverride = 160 }, .argument = { .status = STATUS1_ANY }, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_TOXIC}, @@ -13066,8 +13070,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .instructBanned = TRUE, .assistBanned = TRUE, .argument.twoTurnAttack = { .stringId = STRINGID_PKMNTOOKTARGETHIGH, .status = STATE_ON_AIR }, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_SkyDrop, @@ -13113,8 +13117,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .makesContact = TRUE, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_LATER, + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_CircleThrow, @@ -13137,8 +13141,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_INCINERATE, }), - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION, + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Incinerate, @@ -13160,8 +13164,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPD_UP_1 }, .metronomeBanned = TRUE, - .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_LATER, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_EARLIER, + .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Quash, @@ -13182,7 +13186,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -13206,7 +13210,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_SPATK_UP_1 }, .ignoresSubstitute = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -13228,8 +13232,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_LATER, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Retaliate, @@ -13278,7 +13282,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .metronomeBanned = TRUE, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, + .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -13303,7 +13307,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_BURN, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -13325,8 +13329,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_WaterPledge, @@ -13347,7 +13351,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -13369,8 +13373,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_GrassPledge, @@ -13388,7 +13392,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, //CONTEST_EFFECT_QUICKLY_GROW_BORED .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -13413,8 +13417,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_ATK_MINUS_1, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, + .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_StruggleBug, @@ -13439,7 +13443,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SPD_MINUS_1, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -13459,7 +13463,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .alwaysCriticalHit = TRUE, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, //CONTEST_EFFECT_QUICKLY_GROW_BORED .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -13481,8 +13485,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .makesContact = TRUE, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_LATER, + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_DRAGON_TAIL, .contestComboMoves = {COMBO_STARTER_DRAGON_BREATH, COMBO_STARTER_DRAGON_DANCE, COMBO_STARTER_DRAGON_RAGE, COMBO_STARTER_DRAGON_RUSH}, .battleAnimScript = gBattleAnimMove_DragonTail, @@ -13506,8 +13510,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, //CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_FIRST + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_WorkUp, @@ -13531,8 +13535,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SPD_MINUS_1, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Electroweb, @@ -13555,7 +13559,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .recoilPercentage = 25 }, .makesContact = TRUE, .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_WildCharge, @@ -13600,7 +13604,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .strikeCount = 2, - .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, + .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -13626,7 +13630,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -13648,8 +13652,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .absorbPercentage = 50 }, .makesContact = TRUE, .healingMove = B_HEAL_BLOCKING >= GEN_6, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONE, + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_HornLeech, @@ -13670,8 +13674,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .makesContact = TRUE, .ignoresTargetDefenseEvasionStages = TRUE, .slicingMove = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_SacredSword, @@ -13697,8 +13701,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_DEF_MINUS_1, .chance = 50, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_RazorShell, @@ -13718,8 +13722,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .minimizeDoubleDamage = B_UPDATED_MOVE_FLAGS >= GEN_6, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_HeatCrash, @@ -13743,8 +13747,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_ACC_MINUS_1, .chance = 50, }), - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_LeafTornado, @@ -13770,7 +13774,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -13796,7 +13800,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_CottonGuard, @@ -13820,7 +13824,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_ACC_MINUS_1, .chance = 40, }), - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -13839,8 +13843,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Psystrike, @@ -13861,7 +13865,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -13890,8 +13894,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_CONFUSION, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Hurricane, @@ -13937,8 +13941,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .powerOverride = 180 }, .makesContact = TRUE, .strikeCount = 2, - .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_GearGrind, @@ -13961,8 +13965,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_BURN, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_SearingShot, @@ -13984,7 +13988,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .argument = { .holdEffect = HOLD_EFFECT_DRIVE }, .metronomeBanned = TRUE, - .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, + .contestEffect = CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -14013,8 +14017,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SLEEP, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, + .contestCategory = CONTEST_CATEGORY_BEAUTIFUL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_RelicSong, @@ -14036,8 +14040,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .slicingMove = TRUE, .metronomeBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, + .contestCategory = CONTEST_CATEGORY_BEAUTIFUL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_SecretSword, @@ -14061,7 +14065,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SPD_MINUS_1, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, + .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -14087,8 +14091,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_PARALYSIS, .chance = 20, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_BoltStrike, @@ -14112,7 +14116,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_BURN, .chance = 20, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -14139,7 +14143,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, .chance = 50, }), - .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, + .contestEffect = CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -14168,7 +14172,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_PARALYSIS, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, + .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -14225,8 +14229,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_ATK_MINUS_1, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, //CONTEST_EFFECT_QUICKLY_GROW_BORED + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Snarl, @@ -14250,7 +14254,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, + .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -14300,7 +14304,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .thawsUser = TRUE, - .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, + .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -14321,7 +14325,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, + .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -14348,8 +14352,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .minimizeDoubleDamage = TRUE, .gravityBanned = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_FlyingPress, @@ -14378,7 +14382,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .copycatBanned = TRUE, .assistBanned = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -14407,8 +14411,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .sleepTalkBanned = TRUE, .instructBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION, + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Belch, @@ -14458,8 +14462,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .mirrorMoveBanned = TRUE, .magicCoatAffected = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_StickyWeb, @@ -14480,8 +14484,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_FellStinger, @@ -14509,8 +14513,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_FEINT, }), - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_PhantomForce, @@ -14533,8 +14537,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .type = TYPE_GHOST }, .zMove = { .effect = Z_EFFECT_ALL_STATS_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_TrickOrTreat, @@ -14558,8 +14562,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresSubstitute = B_UPDATED_MOVE_FLAGS >= GEN_6, .magicCoatAffected = TRUE, .soundMove = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_BETTER_IF_FIRST, + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_NobleRoar, @@ -14582,7 +14586,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_SPATK_UP_1 }, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -14605,8 +14609,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .argument = { .absorbPercentage = 50 }, .healingMove = B_HEAL_BLOCKING >= GEN_6, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONES, + .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_ParabolicCharge, @@ -14629,7 +14633,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .type = TYPE_GRASS }, .zMove = { .effect = Z_EFFECT_ALL_STATS_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -14651,7 +14655,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .windMove = TRUE, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -14681,7 +14685,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FREEZE_OR_FROSTBITE, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -14729,8 +14733,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .magicCoatAffected = TRUE, .ignoresSubstitute = B_UPDATED_MOVE_FLAGS >= GEN_6, .soundMove = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, //CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_LAST + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_PartingShot, @@ -14752,8 +14756,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_ATK_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, + .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_TopsyTurvy, @@ -14774,7 +14778,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .absorbPercentage = 75 }, .makesContact = TRUE, .healingMove = B_HEAL_BLOCKING >= GEN_6, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONES, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -14800,7 +14804,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .metronomeBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, + .contestEffect = CONTEST_EFFECT_BETTER_IF_FIRST, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -14825,7 +14829,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_FlowerShield, @@ -14849,8 +14853,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, //CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_FIRST + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = COMBO_STARTER_GRASSY_TERRAIN, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_GrassyTerrain, @@ -14874,8 +14878,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, //CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_FIRST + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = COMBO_STARTER_MISTY_TERRAIN, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_MistyTerrain, @@ -14896,8 +14900,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPATK_UP_1 }, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Electrify, @@ -14922,8 +14926,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_ATK_MINUS_1, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_PlayRough, @@ -14945,7 +14949,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .windMove = TRUE, .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_FairyWind, @@ -14969,8 +14973,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_ATK_MINUS_1, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Moonblast, @@ -14992,8 +14996,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .ignoresSubstitute = B_UPDATED_MOVE_FLAGS >= GEN_6, .soundMove = TRUE, - .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_JAMS_OTHERS_BUT_MISS_ONE_TURN, + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Boomburst, @@ -15016,8 +15020,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_DEF_UP_1 }, .ignoresProtect = TRUE, .ignoresSubstitute = TRUE, - .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_FairyLock, @@ -15046,7 +15050,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .instructBanned = TRUE, .assistBanned = TRUE, .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_KingsShield, @@ -15070,7 +15074,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .ignoresSubstitute = TRUE, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, + .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -15096,8 +15100,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .magicCoatAffected = TRUE, .ignoresSubstitute = B_UPDATED_MOVE_FLAGS >= GEN_6, .soundMove = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Confide, @@ -15123,7 +15127,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, .chance = 50, }), - .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, + .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, //CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_LAST .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -15150,8 +15154,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_BURN, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, //CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_LAST + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SCALD}, .battleAnimScript = gBattleAnimMove_SteamEruption, @@ -15175,7 +15179,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_FEINT, }), - .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, //CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_FIRST .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = COMBO_STARTER_HYPERSPACE_HOLE, .contestComboMoves = {COMBO_STARTER_HYPERSPACE_FURY}, @@ -15196,8 +15200,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 1, .category = B_UPDATED_MOVE_DATA >= GEN_7 ? DAMAGE_CATEGORY_SPECIAL : DAMAGE_CATEGORY_PHYSICAL, - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_EARLIER, + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_WaterShuriken, @@ -15221,7 +15225,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_ATK_MINUS_1, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -15250,7 +15254,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .copycatBanned = TRUE, .assistBanned = TRUE, .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_SpikyShield, @@ -15274,8 +15278,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .ignoresSubstitute = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, + .contestCategory = CONTEST_CATEGORY_BEAUTIFUL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_AromaticMist, @@ -15297,8 +15301,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPDEF_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_EerieImpulse, @@ -15344,7 +15348,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_SPDEF_UP_2 }, .powderMove = TRUE, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, //CONTEST_EFFECT_QUICKLY_GROW_BORED .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -15371,7 +15375,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .skyBattleBanned = TRUE, .argument.twoTurnAttack = { .stringId = STRINGID_PKNMABSORBINGPOWER }, .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestCategory = CONTEST_CATEGORY_BEAUTIFUL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Geomancy, @@ -15396,8 +15400,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .ignoresSubstitute = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, + .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_MagneticFlux, @@ -15420,8 +15424,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_ALL_STATS_UP_1 }, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, + .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_HappyHour, @@ -15445,8 +15449,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, //CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_FIRST + .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = COMBO_STARTER_ELECTRIC_TERRAIN, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_ElectricTerrain, @@ -15466,8 +15470,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_BOTH, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_DazzlingGleam, @@ -15496,7 +15500,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .sleepTalkBanned = TRUE, .instructBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_FIRST, + .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -15575,7 +15579,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_PARALYSIS, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, + .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -15595,8 +15599,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, //CONTEST_EFFECT_QUICKLY_GROW_BORED + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_HoldBack, @@ -15622,7 +15626,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .multistring.wrapped = B_MSG_WRAPPED_INFESTATION, }), .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Infestation, @@ -15649,7 +15653,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -15670,7 +15674,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .argument = { .absorbPercentage = 75 }, .healingMove = B_HEAL_BLOCKING >= GEN_6, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONES, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -15695,8 +15699,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoreTypeIfFlyingAndUngrounded = TRUE, .metronomeBanned = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestCategory = CONTEST_CATEGORY_BEAUTIFUL, .contestComboStarterId = COMBO_STARTER_THOUSAND_ARROWS, .contestComboMoves = {COMBO_STARTER_THOUSAND_WAVES}, .battleAnimScript = gBattleAnimMove_ThousandArrows, @@ -15721,7 +15725,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_PREVENT_ESCAPE, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, + .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_THOUSAND_WAVES, .contestComboMoves = {COMBO_STARTER_THOUSAND_ARROWS}, @@ -15743,8 +15747,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_LandsWrath, @@ -15766,6 +15770,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .argument = { .recoilPercentage = 50 }, .metronomeBanned = TRUE, + .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, + .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestComboStarterId = 0, + .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_LightOfRuin, }, @@ -15785,7 +15793,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .pulseMove = TRUE, .metronomeBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_FIRST, + .contestEffect = CONTEST_EFFECT_BETTER_IF_FIRST, //CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_FIRST .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -15807,8 +15815,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .metronomeBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, //CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_LAST + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_PrecipiceBlades, @@ -15860,7 +15868,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_DEF_MINUS_1, .self = TRUE, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, //CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_FIRST .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_HYPERSPACE_FURY, .contestComboMoves = {COMBO_STARTER_HYPERSPACE_HOLE}, @@ -16040,7 +16048,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SPD_MINUS_1, .self = TRUE, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_HAIL}, @@ -16066,7 +16074,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .mirrorMoveBanned = TRUE, .healingMove = TRUE, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING, + .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -16432,7 +16440,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, + .contestEffect = CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -17103,6 +17111,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, + .argument = { .damagePercentage = 50 }, .metronomeBanned = B_UPDATED_MOVE_FLAGS >= GEN_8, .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, .contestCategory = CONTEST_CATEGORY_CUTE, @@ -17699,7 +17708,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .type = TYPE_PSYCHIC }, .magicCoatAffected = TRUE, .powderMove = TRUE, - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -18608,7 +18617,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .pulseMove = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_ELECTRIC_TERRAIN, COMBO_STARTER_MISTY_TERRAIN, COMBO_STARTER_GRASSY_TERRAIN, COMBO_STARTER_PSYCHIC_TERRAIN}, @@ -18968,7 +18977,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .metronomeBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_USER_MORE_EASILY_STARTLED : CONTEST_EFFECT_BETTER_WHEN_LATER, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -19281,6 +19290,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_THRASH, .self = TRUE, }), + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_USER_MORE_EASILY_STARTLED : CONTEST_EFFECT_JAMS_OTHERS_BUT_MISS_ONE_TURN, + .contestComboStarterId = 0, + .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_RagingFury, }, @@ -19301,6 +19313,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .recoilPercentage = 33 }, .makesContact = TRUE, .skyBattleBanned = B_EXTRAPOLATED_MOVE_FLAGS, + .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, + .contestComboStarterId = 0, + .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_WaveCrash, }, @@ -19331,7 +19346,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .power = 100, .type = TYPE_ICE, .accuracy = 85, - .pp = 5, + .pp = B_UPDATED_MOVE_DATA >= GEN_9 ? 10 : 5, .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, @@ -19360,6 +19375,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, + .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, + .contestComboStarterId = 0, + .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_VictoryDance, }, @@ -19383,6 +19401,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_DEF_SPDEF_DOWN, .self = TRUE, }), + .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, + .contestComboStarterId = 0, + .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_HeadlongRush, }, @@ -19797,6 +19818,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .makesContact = TRUE, .punchingMove = TRUE, .metronomeBanned = TRUE, + .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_EARLIER, + .contestComboStarterId = 0, + .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_JetPunch, }, @@ -20171,7 +20195,11 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, + .argument = { .damagePercentage = 50 }, .metronomeBanned = TRUE, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, + .contestComboStarterId = 0, + .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Ruination, }, @@ -20306,6 +20334,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .metronomeBanned = TRUE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestComboStarterId = 0, + .contestComboMoves = {0}, .battleAnimScript = (B_PREFERRED_ICE_WEATHER == B_ICE_WEATHER_HAIL) ? gBattleAnimMove_Hail : gBattleAnimMove_Snowscape, }, @@ -20353,6 +20385,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, .chance = 100, }), + .contestEffect = CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION, + .contestComboStarterId = 0, + .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Trailblaze, }, @@ -20375,6 +20410,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_ATK_MINUS_1, .chance = 100, }), + .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, + .contestComboStarterId = 0, + .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_ChillingWater, }, @@ -20456,6 +20494,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_DEF_SPDEF_DOWN, .self = TRUE, }), + .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, + .contestComboStarterId = 0, + .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_ArmorCannon, }, @@ -20539,6 +20580,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .makesContact = TRUE, .meFirstBanned = TRUE, .metronomeBanned = TRUE, + .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, + .contestComboStarterId = 0, + .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Comeuppance, }, @@ -20926,6 +20970,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 1, .category = DAMAGE_CATEGORY_SPECIAL, + .contestEffect = CONTEST_EFFECT_BETTER_IF_FIRST, + .contestComboStarterId = 0, + .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Thunderclap, }, @@ -21058,6 +21105,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .minimizeDoubleDamage = TRUE, + .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, + .contestComboStarterId = 0, + .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_SupercellSlam, }, @@ -21508,7 +21558,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .description = COMPOUND_STRING( "Mew attacks with\nfull force. " "\nPsychically\ncharges terrain."), - .effect = EFFECT_HIT_SET_TERRAIN, + .effect = EFFECT_HIT, .power = 185, .type = TYPE_PSYCHIC, .accuracy = 0, @@ -21516,8 +21566,11 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .argument = { .moveProperty = STATUS_FIELD_PSYCHIC_TERRAIN }, .battleAnimScript = gBattleAnimMove_GenesisSupernova, + .additionalEffects = ADDITIONAL_EFFECTS({ + .moveEffect = MOVE_EFFECT_PSYCHIC_TERRAIN, + .chance = 100, + }), }, [MOVE_SINISTER_ARROW_RAID] = { diff --git a/src/data/pokemon/form_change_table_pointers.h b/src/data/pokemon/form_change_table_pointers.h index ea2cdfd2a..1af386a89 100644 --- a/src/data/pokemon/form_change_table_pointers.h +++ b/src/data/pokemon/form_change_table_pointers.h @@ -34,3 +34,22 @@ const struct Fusion *const gFusionTablePointers[NUM_SPECIES] = #endif //P_FAMILY_CALYREX #endif //P_FUSION_FORMS }; + +#if P_FUSION_FORMS +#if P_FAMILY_KYUREM +#if P_FAMILY_RESHIRAM +const u16 gKyuremWhiteSwapMoveTable[][2] = +{ + {MOVE_SCARY_FACE, MOVE_FUSION_FLARE}, + {MOVE_GLACIATE, MOVE_ICE_BURN}, +}; +#endif //P_FAMILY_RESHIRAM +#if P_FAMILY_ZEKROM +const u16 gKyuremBlackSwapMoveTable[][2] = +{ + {MOVE_SCARY_FACE, MOVE_FUSION_BOLT}, + {MOVE_GLACIATE, MOVE_FREEZE_SHOCK}, +}; +#endif //P_FAMILY_ZEKROM +#endif //P_FAMILY_KYUREM +#endif //P_FUSION_FORMS diff --git a/src/field_player_avatar.c b/src/field_player_avatar.c index 6f611eb57..00fa25e78 100644 --- a/src/field_player_avatar.c +++ b/src/field_player_avatar.c @@ -83,7 +83,6 @@ static bool8 PlayerAnimIsMultiFrameStationaryAndStateNotTurning(void); static void PlayCollisionSoundIfNotFacingWarp(u8 direction); static void PlayerGoSpin(u8 direction); static void PlayerApplyTileForcedMovement(u8 metatileBehavior); -static bool8 MetatileAtCoordsIsWaterTile(s16 x, s16 y); static void HandleWarpArrowSpriteHideShow(struct ObjectEvent * playerObjEvent); static void StartStrengthAnim(u8 objectEventId, u8 direction); static void Task_BumpBoulder(u8 taskId); @@ -102,37 +101,6 @@ static bool8 PlayerAvatar_SecretBaseMatSpinStep3(struct Task *task, struct Objec static void CreateStopSurfingTask(u8 direction); static void Task_StopSurfingInit(u8 taskId); static void Task_WaitStopSurfing(u8 taskId); -static void Task_Fishing(u8 taskId); -static bool32 Fishing_Init(struct Task *task); -static bool32 Fishing_GetRodOut(struct Task *task); -static bool32 Fishing_WaitBeforeDots(struct Task *task); -static bool32 Fishing_InitDots(struct Task *task); -static bool32 Fishing_ShowDots(struct Task *task); -static bool32 Fishing_CheckForBite(struct Task *task); -static bool32 Fishing_GotBite(struct Task *task); -static bool32 Fishing_ChangeMinigame(struct Task *task); -static bool32 Fishing_WaitForA(struct Task *task); -static bool32 Fishing_APressNoMinigame(struct Task *task); -static bool32 Fishing_CheckMoreDots(struct Task *task); -static bool32 Fishing_MonOnHook(struct Task *task); -static bool32 Fishing_StartEncounter(struct Task *task); -static bool32 Fishing_NotEvenNibble(struct Task *task); -static bool32 Fishing_GotAway(struct Task *task); -static bool32 Fishing_NoMon(struct Task *task); -static bool32 Fishing_PutRodAway(struct Task *task); -static bool32 Fishing_EndNoMon(struct Task *task); -static bool32 DoesFishingMinigameAllowCancel(void); -static bool32 Fishing_DoesFirstMonInPartyHaveSuctionCupsOrStickyHold(void); -static bool32 Fishing_RollForBite(bool32); -static u32 CalculateFishingBiteOdds(bool32); -static u32 CalculateFishingProximityBoost(u32 odds); -static void GetCoordinatesAroundBobber(s16[], s16[][AXIS_COUNT], u32); -static u32 CountQualifyingTiles(s16[][AXIS_COUNT], s16 player[], u8 facingDirection, struct ObjectEvent *objectEvent, bool32 isTileLand[]); -static bool32 CheckTileQualification(s16 tile[], s16 player[], u32 facingDirection, struct ObjectEvent* objectEvent, bool32 isTileLand[], u32 direction); -static u32 CountLandTiles(bool32 isTileLand[]); -static bool32 IsPlayerHere(s16, s16, s16, s16); -static bool32 IsMetatileBlocking(s16, s16, u32); -static bool32 IsMetatileLand(s16, s16, u32); static void Task_TeleportWarpOutPlayerAnim(u8 taskId); static void Task_TeleportWarpInPlayerAnim(u8 taskId); @@ -1217,7 +1185,7 @@ bool8 IsPlayerFacingSurfableFishableWater(void) return FALSE; } -bool8 MetatileAtCoordsIsWaterTile(s16 x, s16 y) +bool32 MetatileAtCoordsIsWaterTile(s16 x, s16 y) { return TestMetatileAttributeBit(MapGridGetMetatileAttributeAt(x, y, METATILE_ATTRIBUTE_TERRAIN), TILE_TERRAIN_WATER); } @@ -1343,7 +1311,7 @@ void StartPlayerAvatarVsSeekerAnim(void) StartSpriteAnim(&gSprites[gPlayerAvatar.spriteId], ANIM_VS_SEEKER); } -void StartPlayerAvatarFishAnim(u8 direction) +void SetPlayerAvatarFishing(u8 direction) { QuestLogCallUpdatePlayerSprite(QL_PLAYER_GFX_FISH); } @@ -1641,599 +1609,6 @@ static void Task_WaitStopSurfing(u8 taskId) } } -enum -{ - FISHING_INIT, - FISHING_GET_ROD_OUT, - FISHING_WAIT_BEFORE_DOTS, - FISHING_INIT_DOTS, - FISHING_SHOW_DOTS, - FISHING_CHECK_FOR_BITE, - FISHING_GOT_BITE, - FISHING_CHANGE_MINIGAME, - FISHING_WAIT_FOR_A, - FISHING_A_PRESS_NO_MINIGAME, - FISHING_CHECK_MORE_DOTS, - FISHING_MON_ON_HOOK, - FISHING_START_ENCOUNTER, - FISHING_NOT_EVEN_NIBBLE, - FISHING_GOT_AWAY, - FISHING_NO_MON, - FISHING_PUT_ROD_AWAY, - FISHING_END_NO_MON, -}; - -#define tStep data[0] -#define tFrameCounter data[1] -#define tNumDots data[2] -#define tDotsRequired data[3] -#define tRoundsPlayed data[12] -#define tMinRoundsRequired data[13] -#define tPlayerGfxId data[14] -#define tFishingRod data[15] - -#define FISHING_PROXIMITY_BOOST 4 -#define FISHING_STICKY_BOOST 36 -#define FISHING_DEFAULT_ODDS 50 - -static bool32 (*const sFishingStateFuncs[])(struct Task *) = -{ - [FISHING_INIT] = Fishing_Init, - [FISHING_GET_ROD_OUT] = Fishing_GetRodOut, - [FISHING_WAIT_BEFORE_DOTS] = Fishing_WaitBeforeDots, - [FISHING_INIT_DOTS] = Fishing_InitDots, - [FISHING_SHOW_DOTS] = Fishing_ShowDots, - [FISHING_CHECK_FOR_BITE] = Fishing_CheckForBite, - [FISHING_GOT_BITE] = Fishing_GotBite, - [FISHING_CHANGE_MINIGAME] = Fishing_ChangeMinigame, - [FISHING_WAIT_FOR_A] = Fishing_WaitForA, - [FISHING_A_PRESS_NO_MINIGAME] = Fishing_APressNoMinigame, - [FISHING_CHECK_MORE_DOTS] = Fishing_CheckMoreDots, - [FISHING_MON_ON_HOOK] = Fishing_MonOnHook, - [FISHING_START_ENCOUNTER] = Fishing_StartEncounter, - [FISHING_NOT_EVEN_NIBBLE] = Fishing_NotEvenNibble, - [FISHING_GOT_AWAY] = Fishing_GotAway, - [FISHING_NO_MON] = Fishing_NoMon, - [FISHING_PUT_ROD_AWAY] = Fishing_PutRodAway, - [FISHING_END_NO_MON] = Fishing_EndNoMon, -}; - -void StartFishing(u8 rod) -{ - u8 taskId = CreateTask(Task_Fishing, 0xFF); - - gTasks[taskId].tFishingRod = rod; - Task_Fishing(taskId); - if (QuestLogTryRecordPlayerAvatarGfxTransition(QL_PLAYER_GFX_FISH) == TRUE) - QL_AfterRecordFishActionSuccessful(); -} - - -static void Task_Fishing(u8 taskId) -{ - while (sFishingStateFuncs[gTasks[taskId].tStep](&gTasks[taskId])) - ; -} - -static bool32 Fishing_Init(struct Task *task) -{ - LockPlayerFieldControls(); - gPlayerAvatar.preventStep = TRUE; - task->tStep = FISHING_GET_ROD_OUT; - return FALSE; -} - -static bool32 Fishing_GetRodOut(struct Task *task) -{ - struct ObjectEvent *playerObjEvent; - const s16 minRounds1[] = { - [OLD_ROD] = 1, - [GOOD_ROD] = 1, - [SUPER_ROD] = 1 - }; - const s16 minRounds2[] = { - [OLD_ROD] = 1, - [GOOD_ROD] = 3, - [SUPER_ROD] = 6 - }; - - task->tRoundsPlayed = 0; - task->tMinRoundsRequired = minRounds1[task->tFishingRod] + (Random() % minRounds2[task->tFishingRod]); - task->tPlayerGfxId = gObjectEvents[gPlayerAvatar.objectEventId].graphicsId; - playerObjEvent = &gObjectEvents[gPlayerAvatar.objectEventId]; - ObjectEventClearHeldMovementIfActive(playerObjEvent); - playerObjEvent->enableAnim = TRUE; - StartPlayerAvatarFishAnim(playerObjEvent->facingDirection); - task->tStep = FISHING_WAIT_BEFORE_DOTS; - return FALSE; -} - -static bool32 Fishing_WaitBeforeDots(struct Task *task) -{ - AlignFishingAnimationFrames(&gSprites[gPlayerAvatar.spriteId]); - - // Wait one second - task->tFrameCounter++; - if (task->tFrameCounter >= 60) - task->tStep = FISHING_INIT_DOTS; - return FALSE; -} - -static bool32 Fishing_InitDots(struct Task *task) -{ - u32 randVal; - - LoadMessageBoxAndFrameGfx(0, TRUE); - task->tStep = FISHING_SHOW_DOTS; - task->tFrameCounter = 0; - task->tNumDots = 0; - randVal = Random(); - randVal %= 10; - task->tDotsRequired = randVal + 1; - if (task->tRoundsPlayed == 0) - task->tDotsRequired = randVal + 4; - if (task->tDotsRequired >= 10) - task->tDotsRequired = 10; - return TRUE; -} - -// Play a round of the dot game -static bool32 Fishing_ShowDots(struct Task *task) -{ - static const u8 dot[] = _("·"); - - AlignFishingAnimationFrames(&gSprites[gPlayerAvatar.spriteId]); - task->tFrameCounter++; - - - if (JOY_NEW(A_BUTTON)) - { - if (!DoesFishingMinigameAllowCancel()) - return FALSE; - - task->tStep = FISHING_NOT_EVEN_NIBBLE; - if (task->tRoundsPlayed != 0) - task->tStep = FISHING_GOT_AWAY; - return TRUE; - } - else - { - if (task->tFrameCounter >= 20) - { - task->tFrameCounter = 0; - if (task->tNumDots >= task->tDotsRequired) - { - task->tStep = FISHING_CHECK_FOR_BITE; - if (task->tRoundsPlayed != 0) - task->tStep = FISHING_GOT_BITE; - task->tRoundsPlayed++; - } - else - { - AddTextPrinterParameterized(0, FONT_NORMAL, dot, task->tNumDots * 12, 1, 0, NULL); - task->tNumDots++; - } - } - return FALSE; - } -} - -// Determine if fish bites -static bool32 Fishing_CheckForBite(struct Task *task) -{ - bool32 bite, firstMonHasSuctionOrSticky; - - AlignFishingAnimationFrames(&gSprites[gPlayerAvatar.spriteId]); - task->tStep = FISHING_GOT_BITE; - bite = FALSE; - - if (!DoesCurrentMapHaveFishingMons()) - { - task->tStep = FISHING_NOT_EVEN_NIBBLE; - return TRUE; - } - - firstMonHasSuctionOrSticky = Fishing_DoesFirstMonInPartyHaveSuctionCupsOrStickyHold(); - - if(firstMonHasSuctionOrSticky) - bite = Fishing_RollForBite(firstMonHasSuctionOrSticky); - - if (!bite) - bite = Fishing_RollForBite(FALSE); - - if (!bite) - task->tStep = FISHING_NOT_EVEN_NIBBLE; - - if (bite) - StartSpriteAnim(&gSprites[gPlayerAvatar.spriteId], GetFishingBiteDirectionAnimNum(GetPlayerFacingDirection())); - - return TRUE; -} - -static bool32 Fishing_GotBite(struct Task *task) -{ - AlignFishingAnimationFrames(&gSprites[gPlayerAvatar.spriteId]); - AddTextPrinterParameterized(0, FONT_NORMAL, gText_OhABite, 0, 17, 0, NULL); - task->tStep = FISHING_CHANGE_MINIGAME; - task->tFrameCounter = 0; - return FALSE; -} - -static bool32 Fishing_ChangeMinigame(struct Task *task) -{ - switch (I_FISHING_MINIGAME) - { - case GEN_1: - case GEN_2: - task->tStep = FISHING_A_PRESS_NO_MINIGAME; - break; - case GEN_3: - default: - task->tStep = FISHING_WAIT_FOR_A; - break; - } - return TRUE; -} - -// We have a bite. Now, wait for the player to press A, or the timer to expire. -static bool32 Fishing_WaitForA(struct Task *task) -{ - const s16 reelTimeouts[3] = { - [OLD_ROD] = 36, - [GOOD_ROD] = 33, - [SUPER_ROD] = 30 - }; - - AlignFishingAnimationFrames(&gSprites[gPlayerAvatar.spriteId]); - task->tFrameCounter++; - if (task->tFrameCounter >= reelTimeouts[task->tFishingRod]) - task->tStep = FISHING_GOT_AWAY; - else if (JOY_NEW(A_BUTTON)) - task->tStep = FISHING_CHECK_MORE_DOTS; - return FALSE; -} - -static bool32 Fishing_APressNoMinigame(struct Task *task) -{ - AlignFishingAnimationFrames(&gSprites[gPlayerAvatar.spriteId]); - if (JOY_NEW(A_BUTTON)) - task->tStep = FISHING_MON_ON_HOOK; - return FALSE; -} - -// Determine if we're going to play the dot game again -static bool32 Fishing_CheckMoreDots(struct Task *task) -{ - const s16 moreDotsChance[][2] = - { - [OLD_ROD] = {0, 0}, - [GOOD_ROD] = {40, 10}, - [SUPER_ROD] = {70, 30} - }; - - AlignFishingAnimationFrames(&gSprites[gPlayerAvatar.spriteId]); - task->tStep = FISHING_MON_ON_HOOK; - if (task->tRoundsPlayed < task->tMinRoundsRequired) - { - task->tStep = FISHING_INIT_DOTS; - } - else if (task->tRoundsPlayed < 2) - { - // probability of having to play another round - s16 probability = Random() % 100; - - if (moreDotsChance[task->tFishingRod][task->tRoundsPlayed] > probability) - task->tStep = FISHING_INIT_DOTS; - } - return FALSE; -} - -static bool32 Fishing_MonOnHook(struct Task *task) -{ - AlignFishingAnimationFrames(&gSprites[gPlayerAvatar.spriteId]); - FillWindowPixelBuffer(0, PIXEL_FILL(1)); - AddTextPrinterParameterized2(0, FONT_NORMAL, gText_PokemonOnHook, 1, 0, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_WHITE, TEXT_COLOR_LIGHT_GRAY); - task->tStep = FISHING_START_ENCOUNTER; - task->tFrameCounter = 0; - return FALSE; -} - -static bool32 Fishing_StartEncounter(struct Task *task) -{ - if (task->tFrameCounter == 0) - AlignFishingAnimationFrames(&gSprites[gPlayerAvatar.spriteId]); - - RunTextPrinters(); - - if (task->tFrameCounter == 0) - { - if (!IsTextPrinterActive(0)) - { - struct ObjectEvent *playerObjEvent = &gObjectEvents[gPlayerAvatar.objectEventId]; - - ObjectEventSetGraphicsId(playerObjEvent, task->tPlayerGfxId); - ObjectEventTurn(playerObjEvent, playerObjEvent->movementDirection); - if (gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_SURFING) - SetSurfBlob_PlayerOffset(gObjectEvents[gPlayerAvatar.objectEventId].fieldEffectSpriteId, 0, 0); - gSprites[gPlayerAvatar.spriteId].x2 = 0; - gSprites[gPlayerAvatar.spriteId].y2 = 0; - ClearDialogWindowAndFrame(0, TRUE); - task->tFrameCounter++; - return FALSE; - } - } - - if (task->tFrameCounter != 0) - { - gPlayerAvatar.preventStep = FALSE; - UnlockPlayerFieldControls(); - FishingWildEncounter(task->tFishingRod); - DestroyTask(FindTaskIdByFunc(Task_Fishing)); - } - return FALSE; -} - -static bool32 Fishing_NotEvenNibble(struct Task *task) -{ - gChainFishingDexNavStreak = 0; - AlignFishingAnimationFrames(&gSprites[gPlayerAvatar.spriteId]); - StartSpriteAnim(&gSprites[gPlayerAvatar.spriteId], GetFishingNoCatchDirectionAnimNum(GetPlayerFacingDirection())); - FillWindowPixelBuffer(0, PIXEL_FILL(1)); - AddTextPrinterParameterized2(0, FONT_NORMAL, gText_NotEvenANibble, 1, NULL, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_WHITE, TEXT_COLOR_LIGHT_GRAY); - task->tStep = FISHING_NO_MON; - return TRUE; -} - -static bool32 Fishing_GotAway(struct Task *task) -{ - gChainFishingDexNavStreak = 0; - AlignFishingAnimationFrames(&gSprites[gPlayerAvatar.spriteId]); - StartSpriteAnim(&gSprites[gPlayerAvatar.spriteId], GetFishingNoCatchDirectionAnimNum(GetPlayerFacingDirection())); - FillWindowPixelBuffer(0, PIXEL_FILL(1)); - AddTextPrinterParameterized2(0, FONT_NORMAL, gText_ItGotAway, 1, NULL, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_WHITE, TEXT_COLOR_LIGHT_GRAY); - task->tStep = FISHING_NO_MON; - return TRUE; -} - -static bool32 Fishing_NoMon(struct Task *task) -{ - AlignFishingAnimationFrames(&gSprites[gPlayerAvatar.spriteId]); - task->tStep = FISHING_PUT_ROD_AWAY; - return FALSE; -} - -static bool32 Fishing_PutRodAway(struct Task *task) -{ - AlignFishingAnimationFrames(&gSprites[gPlayerAvatar.spriteId]); - if (gSprites[gPlayerAvatar.spriteId].animEnded) - { - struct ObjectEvent *playerObjEvent = &gObjectEvents[gPlayerAvatar.objectEventId]; - - ObjectEventSetGraphicsId(playerObjEvent, task->tPlayerGfxId); - ObjectEventTurn(playerObjEvent, playerObjEvent->movementDirection); - if (gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_SURFING) - SetSurfBlob_PlayerOffset(gObjectEvents[gPlayerAvatar.objectEventId].fieldEffectSpriteId, FALSE, 0); - gSprites[gPlayerAvatar.spriteId].x2 = 0; - gSprites[gPlayerAvatar.spriteId].y2 = 0; - task->tStep = FISHING_END_NO_MON; - } - return FALSE; -} - -static bool32 Fishing_EndNoMon(struct Task *task) -{ - RunTextPrinters(); - if (!IsTextPrinterActive(0)) - { - gPlayerAvatar.preventStep = FALSE; - UnlockPlayerFieldControls(); - UnfreezeObjectEvents(); - ClearDialogWindowAndFrame(0, TRUE); - DestroyTask(FindTaskIdByFunc(Task_Fishing)); - } - return FALSE; -} - -static bool32 DoesFishingMinigameAllowCancel(void) -{ - switch(I_FISHING_MINIGAME) - { - case GEN_1: - case GEN_2: - return FALSE; - case GEN_3: - default: - return TRUE; - } -} - -static bool32 Fishing_DoesFirstMonInPartyHaveSuctionCupsOrStickyHold(void) -{ - u32 ability; - - if (GetMonData(&gPlayerParty[0], MON_DATA_SANITY_IS_EGG)) - return FALSE; - - ability = GetMonAbility(&gPlayerParty[0]); - - return (ability == ABILITY_SUCTION_CUPS || ability == ABILITY_STICKY_HOLD); -} - -static bool32 Fishing_RollForBite(bool32 isStickyHold) -{ - return ((Random() % 100) > CalculateFishingBiteOdds(isStickyHold)); -} - -static u32 CalculateFishingBiteOdds(bool32 isStickyHold) -{ - u32 odds = FISHING_DEFAULT_ODDS; - - if (isStickyHold) - odds -= FISHING_STICKY_BOOST; - - odds -= CalculateFishingProximityBoost(odds); - return odds; -} - -static u32 CalculateFishingProximityBoost(u32 odds) -{ - s16 player[AXIS_COUNT], bobber[AXIS_COUNT]; - s16 surroundingTile[CARDINAL_DIRECTION_COUNT][AXIS_COUNT] = {{0, 0}}; - bool32 isTileLand[CARDINAL_DIRECTION_COUNT] = {FALSE}; - u32 facingDirection, numQualifyingTile = 0; - struct ObjectEvent *objectEvent; - - if (!I_FISHING_PROXIMITY) - return 0; - - objectEvent = &gObjectEvents[gPlayerAvatar.objectEventId]; - - player[AXIS_X] = objectEvent->currentCoords.x; - player[AXIS_Y] = objectEvent->currentCoords.y; - bobber[AXIS_X] = objectEvent->currentCoords.x; - bobber[AXIS_Y] = objectEvent->currentCoords.y; - - facingDirection = GetPlayerFacingDirection(); - MoveCoords(facingDirection, &bobber[AXIS_X], &bobber[AXIS_Y]); - - GetCoordinatesAroundBobber(bobber, surroundingTile, facingDirection); - numQualifyingTile = CountQualifyingTiles(surroundingTile, player, facingDirection, objectEvent, isTileLand); - - numQualifyingTile += CountLandTiles(isTileLand); - - return (numQualifyingTile == 3) ? odds : (numQualifyingTile * FISHING_PROXIMITY_BOOST); -} - -static void GetCoordinatesAroundBobber(s16 bobber[], s16 surroundingTile[][AXIS_COUNT], u32 facingDirection) -{ - u32 direction; - - for (direction = DIR_SOUTH; direction < CARDINAL_DIRECTION_COUNT; direction++) - { - surroundingTile[direction][AXIS_X] = bobber[AXIS_X]; - surroundingTile[direction][AXIS_Y] = bobber[AXIS_Y]; - MoveCoords(direction, &surroundingTile[direction][AXIS_X], &surroundingTile[direction][AXIS_Y]); - } -} - -static u32 CountQualifyingTiles(s16 surroundingTile[][AXIS_COUNT], s16 player[], u8 facingDirection, struct ObjectEvent *objectEvent, bool32 isTileLand[]) -{ - u32 numQualifyingTile = 0; - s16 tile[AXIS_COUNT]; - u8 direction = DIR_SOUTH; - - for (direction = DIR_SOUTH; direction < CARDINAL_DIRECTION_COUNT; direction++) - { - tile[AXIS_X] = surroundingTile[direction][AXIS_X]; - tile[AXIS_Y] = surroundingTile[direction][AXIS_Y]; - - if (!CheckTileQualification(tile, player, facingDirection, objectEvent, isTileLand, direction)) - continue; - - numQualifyingTile++; - } - return numQualifyingTile; -} - -static bool32 CheckTileQualification(s16 tile[], s16 player[], u32 facingDirection, struct ObjectEvent* objectEvent, bool32 isTileLand[], u32 direction) -{ - u32 collison = GetCollisionAtCoords(objectEvent, tile[AXIS_X], tile[AXIS_Y], facingDirection); - - if (IsPlayerHere(tile[AXIS_X], tile[AXIS_Y], player[AXIS_X], player[AXIS_Y])) - return FALSE; - else if (IsMetatileBlocking(tile[AXIS_X], tile[AXIS_Y], collison)) - return TRUE; - else if (MetatileBehavior_IsSurfableAndNotWaterfall(MapGridGetMetatileBehaviorAt(tile[AXIS_X], tile[AXIS_Y]))) - return FALSE; - else if (IsMetatileLand(tile[AXIS_X], tile[AXIS_Y], collison)) - isTileLand[direction] = TRUE; - - return FALSE; -} - -static u32 CountLandTiles(bool32 isTileLand[]) -{ - u32 direction, numQualifyingTile = 0; - - for (direction = DIR_SOUTH; direction < CARDINAL_DIRECTION_COUNT; direction++) - if (isTileLand[direction]) - numQualifyingTile++; - - return (numQualifyingTile < 2) ? 0 : numQualifyingTile; -} - -static bool32 IsPlayerHere(s16 x, s16 y, s16 playerX, s16 playerY) -{ - return ((x == playerX) && (y == playerY)); -} - -static bool32 IsMetatileBlocking(s16 x, s16 y, u32 collison) -{ - switch(collison) - { - case COLLISION_NONE: - case COLLISION_STOP_SURFING: - case COLLISION_ELEVATION_MISMATCH: - return FALSE; - default: - return TRUE; - case COLLISION_OBJECT_EVENT: - return (gObjectEvents[GetObjectEventIdByXY(x,y)].inanimate); - } - return TRUE; -} - -static bool32 IsMetatileLand(s16 x, s16 y, u32 collison) -{ - switch(collison) - { - case COLLISION_NONE: - case COLLISION_STOP_SURFING: - case COLLISION_ELEVATION_MISMATCH: - return TRUE; - default: - return FALSE; - } -} - -#undef tStep -#undef tFrameCounter -#undef tFishingRod - -void AlignFishingAnimationFrames(struct Sprite *playerSprite) -{ - u8 animCmdIndex; - u8 animType; - - AnimateSprite(playerSprite); - playerSprite->x2 = 0; - playerSprite->y2 = 0; - animCmdIndex = playerSprite->animCmdIndex; - if (playerSprite->anims[playerSprite->animNum][animCmdIndex].type == -1) - { - animCmdIndex--; - } - else - { - playerSprite->animDelayCounter++; - if (playerSprite->anims[playerSprite->animNum][animCmdIndex].type == -1) - animCmdIndex--; - } - animType = playerSprite->anims[playerSprite->animNum][animCmdIndex].type; - if (animType == 1 || animType == 2 || animType == 3) - { - playerSprite->x2 = 8; - if (GetPlayerFacingDirection() == 3) - playerSprite->x2 = -8; - } - if (animType == 5) - playerSprite->y2 = -8; - if (animType == 10 || animType == 11) - playerSprite->y2 = 8; - if (gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_SURFING) - SetSurfBlob_PlayerOffset(gObjectEvents[gPlayerAvatar.objectEventId].fieldEffectSpriteId, 1, playerSprite->y2); -} - #define tState data[0] #define tRotationTimer data[1] #define tDeltaY data[2] diff --git a/src/fishing.c b/src/fishing.c new file mode 100644 index 000000000..50df84179 --- /dev/null +++ b/src/fishing.c @@ -0,0 +1,649 @@ +#include "global.h" +#include "main.h" +#include "event_object_movement.h" +#include "fieldmap.h" +#include "field_effect_helpers.h" +#include "field_player_avatar.h" +#include "menu.h" +#include "metatile_behavior.h" +#include "random.h" +#include "script.h" +#include "strings.h" +#include "task.h" +#include "text.h" +// #include "tv.h" +#include "wild_encounter.h" +#include "config/fishing.h" + +static void Task_Fishing(u8); +static bool32 Fishing_Init(struct Task *); +static bool32 Fishing_GetRodOut(struct Task *); +static bool32 Fishing_WaitBeforeDots(struct Task *); +static bool32 Fishing_InitDots(struct Task *); +static bool32 Fishing_ShowDots(struct Task *); +static bool32 Fishing_CheckForBite(struct Task *); +static bool32 Fishing_GotBite(struct Task *); +static bool32 Fishing_ChangeMinigame(struct Task *); +static bool32 Fishing_WaitForA(struct Task *); +static bool32 Fishing_APressNoMinigame(struct Task *); +static bool32 Fishing_CheckMoreDots(struct Task *); +static bool32 Fishing_MonOnHook(struct Task *); +static bool32 Fishing_StartEncounter(struct Task *); +static bool32 Fishing_NotEvenNibble(struct Task *); +static bool32 Fishing_GotAway(struct Task *); +static bool32 Fishing_NoMon(struct Task *); +static bool32 Fishing_PutRodAway(struct Task *); +static bool32 Fishing_EndNoMon(struct Task *); +static bool32 DoesFishingMinigameAllowCancel(void); +static bool32 Fishing_DoesFirstMonInPartyHaveSuctionCupsOrStickyHold(void); +static bool32 Fishing_RollForBite(u32, bool32); +static u32 CalculateFishingBiteOdds(u32, bool32); +static u32 CalculateFishingFollowerBoost(void); +static u32 CalculateFishingProximityBoost(void); +static u32 CalculateFishingTimeOfDayBoost(void); + +#define FISHING_PROXIMITY_BOOST 20 //Active if config I_FISHING_PROXIMITY is TRUE +#define FISHING_TIME_OF_DAY_BOOST 20 //Active if config I_FISHING_TIME_OF_DAY_BOOST is TRUE +#define FISHING_GEN3_STICKY_CHANCE 85 //Active if config I_FISHING_STICKY_BOOST is set to GEN_3 or lower + +#if I_FISHING_BITE_ODDS >= GEN_4 + #define FISHING_OLD_ROD_ODDS 25 + #define FISHING_GOOD_ROD_ODDS 50 + #define FISHING_SUPER_ROD_ODDS 75 +#elif I_FISHING_BITE_ODDS >= GEN_3 + #define FISHING_OLD_ROD_ODDS 50 + #define FISHING_GOOD_ROD_ODDS 50 + #define FISHING_SUPER_ROD_ODDS 50 +#else + #define FISHING_OLD_ROD_ODDS 100 + #define FISHING_GOOD_ROD_ODDS 33 + #define FISHING_SUPER_ROD_ODDS 50 +#endif + +struct FriendshipHookChanceBoost +{ + u8 threshold; + u8 bonus; +}; + +//Needs to be defined in descending order and end with the 0 friendship boost +//Active if config I_FISHING_FOLLOWER_BOOST is TRUE +static const struct FriendshipHookChanceBoost sFriendshipHookChanceBoostArray[] = +{ + {.threshold = 250, .bonus = 50}, + {.threshold = 200, .bonus = 40}, + {.threshold = 150, .bonus = 30}, + {.threshold = 100, .bonus = 20}, + {.threshold = 0, .bonus = 0}, +}; + +#define FISHING_CHAIN_SHINY_STREAK_MAX 20 + +enum +{ + FISHING_INIT, + FISHING_GET_ROD_OUT, + FISHING_WAIT_BEFORE_DOTS, + FISHING_INIT_DOTS, + FISHING_SHOW_DOTS, + FISHING_CHECK_FOR_BITE, + FISHING_GOT_BITE, + FISHING_CHANGE_MINIGAME, + FISHING_WAIT_FOR_A, + FISHING_A_PRESS_NO_MINIGAME, + FISHING_CHECK_MORE_DOTS, + FISHING_MON_ON_HOOK, + FISHING_START_ENCOUNTER, + FISHING_NOT_EVEN_NIBBLE, + FISHING_GOT_AWAY, + FISHING_NO_MON, + FISHING_PUT_ROD_AWAY, + FISHING_END_NO_MON, +}; + +static bool32 (*const sFishingStateFuncs[])(struct Task *) = +{ + [FISHING_INIT] = Fishing_Init, + [FISHING_GET_ROD_OUT] = Fishing_GetRodOut, + [FISHING_WAIT_BEFORE_DOTS] = Fishing_WaitBeforeDots, + [FISHING_INIT_DOTS] = Fishing_InitDots, + [FISHING_SHOW_DOTS] = Fishing_ShowDots, + [FISHING_CHECK_FOR_BITE] = Fishing_CheckForBite, + [FISHING_GOT_BITE] = Fishing_GotBite, + [FISHING_CHANGE_MINIGAME] = Fishing_ChangeMinigame, + [FISHING_WAIT_FOR_A] = Fishing_WaitForA, + [FISHING_A_PRESS_NO_MINIGAME] = Fishing_APressNoMinigame, + [FISHING_CHECK_MORE_DOTS] = Fishing_CheckMoreDots, + [FISHING_MON_ON_HOOK] = Fishing_MonOnHook, + [FISHING_START_ENCOUNTER] = Fishing_StartEncounter, + [FISHING_NOT_EVEN_NIBBLE] = Fishing_NotEvenNibble, + [FISHING_GOT_AWAY] = Fishing_GotAway, + [FISHING_NO_MON] = Fishing_NoMon, + [FISHING_PUT_ROD_AWAY] = Fishing_PutRodAway, + [FISHING_END_NO_MON] = Fishing_EndNoMon, +}; + +#define tStep data[0] +#define tFrameCounter data[1] +#define tNumDots data[2] +#define tDotsRequired data[3] +#define tRoundsPlayed data[12] +#define tMinRoundsRequired data[13] +#define tPlayerGfxId data[14] +#define tFishingRod data[15] + +void StartFishing(u8 rod) +{ + u8 taskId = CreateTask(Task_Fishing, 0xFF); + + gTasks[taskId].tFishingRod = rod; + Task_Fishing(taskId); +} + +static void Task_Fishing(u8 taskId) +{ + while (sFishingStateFuncs[gTasks[taskId].tStep](&gTasks[taskId])) + ; +} + +static bool32 Fishing_Init(struct Task *task) +{ + LockPlayerFieldControls(); + gPlayerAvatar.preventStep = TRUE; + task->tStep = FISHING_GET_ROD_OUT; + return FALSE; +} + +static bool32 Fishing_GetRodOut(struct Task *task) +{ + struct ObjectEvent *playerObjEvent; + const s16 minRounds1[] = { + [OLD_ROD] = 1, + [GOOD_ROD] = 1, + [SUPER_ROD] = 1 + }; + const s16 minRounds2[] = { + [OLD_ROD] = 1, + [GOOD_ROD] = 3, + [SUPER_ROD] = 6 + }; + + task->tRoundsPlayed = 0; + task->tMinRoundsRequired = minRounds1[task->tFishingRod] + (Random() % minRounds2[task->tFishingRod]); + task->tPlayerGfxId = gObjectEvents[gPlayerAvatar.objectEventId].graphicsId; + playerObjEvent = &gObjectEvents[gPlayerAvatar.objectEventId]; + ObjectEventClearHeldMovementIfActive(playerObjEvent); + playerObjEvent->enableAnim = TRUE; + SetPlayerAvatarFishing(playerObjEvent->facingDirection); + task->tStep = FISHING_WAIT_BEFORE_DOTS; + return FALSE; +} + +static bool32 Fishing_WaitBeforeDots(struct Task *task) +{ + AlignFishingAnimationFrames(); + + // Wait one second + task->tFrameCounter++; + if (task->tFrameCounter >= 60) + task->tStep = FISHING_INIT_DOTS; + return FALSE; +} + +static bool32 Fishing_InitDots(struct Task *task) +{ + u32 randVal; + + LoadMessageBoxAndFrameGfx(0, TRUE); + task->tStep = FISHING_SHOW_DOTS; + task->tFrameCounter = 0; + task->tNumDots = 0; + randVal = Random(); + randVal %= 10; + task->tDotsRequired = randVal + 1; + if (task->tRoundsPlayed == 0) + task->tDotsRequired = randVal + 4; + if (task->tDotsRequired >= 10) + task->tDotsRequired = 10; + return TRUE; +} + +static bool32 Fishing_ShowDots(struct Task *task) +{ + const u8 dot[] = _("·"); + + AlignFishingAnimationFrames(); + task->tFrameCounter++; + if (JOY_NEW(A_BUTTON)) + { + if (!DoesFishingMinigameAllowCancel()) + return FALSE; + + task->tStep = FISHING_NOT_EVEN_NIBBLE; + if (task->tRoundsPlayed != 0) + task->tStep = FISHING_GOT_AWAY; + return TRUE; + } + else + { + if (task->tFrameCounter >= 20) + { + task->tFrameCounter = 0; + if (task->tNumDots >= task->tDotsRequired) + { + task->tStep = FISHING_CHECK_FOR_BITE; + if (task->tRoundsPlayed != 0) + task->tStep = FISHING_GOT_BITE; + task->tRoundsPlayed++; + } + else + { + AddTextPrinterParameterized(0, FONT_NORMAL, dot, task->tNumDots * 8, 1, 0, NULL); + task->tNumDots++; + } + } + return FALSE; + } +} + +static bool32 Fishing_CheckForBite(struct Task *task) +{ + bool32 bite, firstMonHasSuctionOrSticky; + + AlignFishingAnimationFrames(); + task->tStep = FISHING_GOT_BITE; + bite = FALSE; + + if (!DoesCurrentMapHaveFishingMons()) + { + task->tStep = FISHING_NOT_EVEN_NIBBLE; + return TRUE; + } + + firstMonHasSuctionOrSticky = Fishing_DoesFirstMonInPartyHaveSuctionCupsOrStickyHold(); + + if(firstMonHasSuctionOrSticky && I_FISHING_STICKY_BOOST < GEN_4) + bite = RandomPercentage(RNG_FISHING_GEN3_STICKY, FISHING_GEN3_STICKY_CHANCE); + + if (!bite) + bite = Fishing_RollForBite(task->tFishingRod, firstMonHasSuctionOrSticky); + + if (!bite) + task->tStep = FISHING_NOT_EVEN_NIBBLE; + + if (bite) + StartSpriteAnim(&gSprites[gPlayerAvatar.spriteId], GetFishingBiteDirectionAnimNum(GetPlayerFacingDirection())); + + return TRUE; +} + +static bool32 Fishing_GotBite(struct Task *task) +{ + AlignFishingAnimationFrames(); + AddTextPrinterParameterized(0, FONT_NORMAL, gText_OhABite, 0, 17, 0, NULL); + task->tStep = FISHING_CHANGE_MINIGAME; + task->tFrameCounter = 0; + return FALSE; +} + +static bool32 Fishing_ChangeMinigame(struct Task *task) +{ + switch (I_FISHING_MINIGAME) + { + case GEN_1: + case GEN_2: + task->tStep = FISHING_A_PRESS_NO_MINIGAME; + break; + case GEN_3: + default: + task->tStep = FISHING_WAIT_FOR_A; + break; + } + return TRUE; +} + +// We have a bite. Now, wait for the player to press A, or the timer to expire. +static bool32 Fishing_WaitForA(struct Task *task) +{ + const s16 reelTimeouts[3] = { + [OLD_ROD] = 36, + [GOOD_ROD] = 33, + [SUPER_ROD] = 30 + }; + + AlignFishingAnimationFrames(); + task->tFrameCounter++; + if (task->tFrameCounter >= reelTimeouts[task->tFishingRod]) + task->tStep = FISHING_GOT_AWAY; + else if (JOY_NEW(A_BUTTON)) + task->tStep = FISHING_CHECK_MORE_DOTS; + return FALSE; +} + +static bool32 Fishing_APressNoMinigame(struct Task *task) +{ + AlignFishingAnimationFrames(); + if (JOY_NEW(A_BUTTON)) + task->tStep = FISHING_MON_ON_HOOK; + return FALSE; +} + +// Determine if we're going to play the dot game again +static bool32 Fishing_CheckMoreDots(struct Task *task) +{ + const s16 moreDotsChance[][2] = + { + [OLD_ROD] = {0, 0}, + [GOOD_ROD] = {40, 10}, + [SUPER_ROD] = {70, 30} + }; + + AlignFishingAnimationFrames(); + task->tStep = FISHING_MON_ON_HOOK; + if (task->tRoundsPlayed < task->tMinRoundsRequired) + { + task->tStep = FISHING_INIT_DOTS; + } + else if (task->tRoundsPlayed < 2) + { + // probability of having to play another round + s16 probability = Random() % 100; + + if (moreDotsChance[task->tFishingRod][task->tRoundsPlayed] > probability) + task->tStep = FISHING_INIT_DOTS; + } + return FALSE; +} + +static bool32 Fishing_MonOnHook(struct Task *task) +{ + AlignFishingAnimationFrames(); + FillWindowPixelBuffer(0, PIXEL_FILL(1)); + AddTextPrinterParameterized2(0, FONT_NORMAL, gText_PokemonOnHook, 1, 0, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_WHITE, TEXT_COLOR_LIGHT_GRAY); + task->tStep = FISHING_START_ENCOUNTER; + task->tFrameCounter = 0; + return FALSE; +} + +static bool32 Fishing_StartEncounter(struct Task *task) +{ + if (task->tFrameCounter == 0) + AlignFishingAnimationFrames(); + + RunTextPrinters(); + + if (task->tFrameCounter == 0) + { + if (!IsTextPrinterActive(0)) + { + struct ObjectEvent *playerObjEvent = &gObjectEvents[gPlayerAvatar.objectEventId]; + + ObjectEventSetGraphicsId(playerObjEvent, task->tPlayerGfxId); + ObjectEventTurn(playerObjEvent, playerObjEvent->movementDirection); + if (gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_SURFING) + SetSurfBlob_PlayerOffset(gObjectEvents[gPlayerAvatar.objectEventId].fieldEffectSpriteId, FALSE, 0); + gSprites[gPlayerAvatar.spriteId].x2 = 0; + gSprites[gPlayerAvatar.spriteId].y2 = 0; + ClearDialogWindowAndFrame(0, TRUE); + task->tFrameCounter++; + return FALSE; + } + } + + if (task->tFrameCounter != 0) + { + gPlayerAvatar.preventStep = FALSE; + UnlockPlayerFieldControls(); + FishingWildEncounter(task->tFishingRod); + // RecordFishingAttemptForTV(TRUE); + DestroyTask(FindTaskIdByFunc(Task_Fishing)); + } + return FALSE; +} + +static bool32 Fishing_NotEvenNibble(struct Task *task) +{ + gChainFishingDexNavStreak = 0; + AlignFishingAnimationFrames(); + StartSpriteAnim(&gSprites[gPlayerAvatar.spriteId], GetFishingNoCatchDirectionAnimNum(GetPlayerFacingDirection())); + FillWindowPixelBuffer(0, PIXEL_FILL(1)); + AddTextPrinterParameterized2(0, FONT_NORMAL, gText_NotEvenANibble, 1, 0, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_WHITE, TEXT_COLOR_LIGHT_GRAY); + task->tStep = FISHING_NO_MON; + return TRUE; +} + +static bool32 Fishing_GotAway(struct Task *task) +{ + gChainFishingDexNavStreak = 0; + AlignFishingAnimationFrames(); + StartSpriteAnim(&gSprites[gPlayerAvatar.spriteId], GetFishingNoCatchDirectionAnimNum(GetPlayerFacingDirection())); + FillWindowPixelBuffer(0, PIXEL_FILL(1)); + AddTextPrinterParameterized2(0, FONT_NORMAL, gText_ItGotAway, 1, 0, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_WHITE, TEXT_COLOR_LIGHT_GRAY); + task->tStep = FISHING_NO_MON; + return TRUE; +} + +static bool32 Fishing_NoMon(struct Task *task) +{ + AlignFishingAnimationFrames(); + task->tStep = FISHING_PUT_ROD_AWAY; + return FALSE; +} + +static bool32 Fishing_PutRodAway(struct Task *task) +{ + AlignFishingAnimationFrames(); + if (gSprites[gPlayerAvatar.spriteId].animEnded) + { + struct ObjectEvent *playerObjEvent = &gObjectEvents[gPlayerAvatar.objectEventId]; + + ObjectEventSetGraphicsId(playerObjEvent, task->tPlayerGfxId); + ObjectEventTurn(playerObjEvent, playerObjEvent->movementDirection); + if (gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_SURFING) + SetSurfBlob_PlayerOffset(gObjectEvents[gPlayerAvatar.objectEventId].fieldEffectSpriteId, FALSE, 0); + gSprites[gPlayerAvatar.spriteId].x2 = 0; + gSprites[gPlayerAvatar.spriteId].y2 = 0; + task->tStep = FISHING_END_NO_MON; + } + return FALSE; +} + +static bool32 Fishing_EndNoMon(struct Task *task) +{ + RunTextPrinters(); + if (!IsTextPrinterActive(0)) + { + gPlayerAvatar.preventStep = FALSE; + UnlockPlayerFieldControls(); + UnfreezeObjectEvents(); + ClearDialogWindowAndFrame(0, TRUE); + // RecordFishingAttemptForTV(FALSE); + DestroyTask(FindTaskIdByFunc(Task_Fishing)); + } + return FALSE; +} + +static bool32 DoesFishingMinigameAllowCancel(void) +{ + switch(I_FISHING_MINIGAME) + { + case GEN_1: + case GEN_2: + return FALSE; + case GEN_3: + default: + return TRUE; + } +} + +static bool32 Fishing_DoesFirstMonInPartyHaveSuctionCupsOrStickyHold(void) +{ + enum Ability ability; + + if (GetMonData(&gPlayerParty[0], MON_DATA_SANITY_IS_EGG)) + return FALSE; + + ability = GetMonAbility(&gPlayerParty[0]); + + return (ability == ABILITY_SUCTION_CUPS || ability == ABILITY_STICKY_HOLD); +} + +static bool32 Fishing_RollForBite(u32 rod, bool32 isStickyHold) +{ + return ((RandomUniform(RNG_FISHING_BITE, 1, 100)) <= CalculateFishingBiteOdds(rod, isStickyHold)); +} + +static u32 CalculateFishingBiteOdds(u32 rod, bool32 isStickyHold) +{ + u32 odds; + + if (rod == OLD_ROD) + odds = FISHING_OLD_ROD_ODDS; + if (rod == GOOD_ROD) + odds = FISHING_GOOD_ROD_ODDS; + if (rod == SUPER_ROD) + odds = FISHING_SUPER_ROD_ODDS; + + odds += CalculateFishingFollowerBoost(); + odds += CalculateFishingProximityBoost(); + odds += CalculateFishingTimeOfDayBoost(); + + if (isStickyHold && I_FISHING_STICKY_BOOST >= GEN_4) + odds *= 2; + + odds = min(100, odds); + DebugPrintf("Fishing odds: %d", odds); + return odds; +} + +static u32 CalculateFishingFollowerBoost() +{ + u32 friendship; + struct Pokemon *mon = GetFirstLiveMon(); + + if (!I_FISHING_FOLLOWER_BOOST || !mon) + return 0; + + friendship = GetMonData(mon, MON_DATA_FRIENDSHIP); + for (u32 i = 0;; i++) + { + if (friendship >= sFriendshipHookChanceBoostArray[i].threshold) + return sFriendshipHookChanceBoostArray[i].bonus; + } +} + +static u32 CalculateFishingProximityBoost() +{ + s16 bobber_x, bobber_y, tile_x, tile_y; + u32 direction, facingDirection, numQualifyingTile = 0; + struct ObjectEvent *objectEvent; + + if (!I_FISHING_PROXIMITY) + return 0; + + objectEvent = &gObjectEvents[gPlayerAvatar.objectEventId]; + + bobber_x = objectEvent->currentCoords.x; + bobber_y = objectEvent->currentCoords.y; + + facingDirection = GetPlayerFacingDirection(); + MoveCoords(facingDirection, &bobber_x, &bobber_y); + + numQualifyingTile = 0; + for (direction = DIR_SOUTH; direction < CARDINAL_DIRECTION_COUNT; direction++) + { + tile_x = bobber_x; + tile_y = bobber_y; + MoveCoords(direction, &tile_x, &tile_y); + if (tile_x == objectEvent->currentCoords.x && tile_y == objectEvent->currentCoords.y) + continue; + if (!MetatileAtCoordsIsWaterTile(tile_x, tile_y)) + numQualifyingTile++; + else if (MapGridGetCollisionAt(tile_x, tile_y)) + numQualifyingTile++; + else if (GetMapBorderIdAt(tile_x, tile_y) == -1) + numQualifyingTile++; + } + + return (numQualifyingTile * FISHING_PROXIMITY_BOOST); +} + +static u32 CalculateFishingTimeOfDayBoost() +{ + if (!I_FISHING_TIME_OF_DAY_BOOST) + return 0; + + enum TimeOfDay timeOfDay = GetTimeOfDay(); + if (timeOfDay == TIME_MORNING || timeOfDay == TIME_EVENING) + return FISHING_TIME_OF_DAY_BOOST; + return 0; +} + +#undef tStep +#undef tFrameCounter +#undef tNumDots +#undef tDotsRequired +#undef tRoundsPlayed +#undef tMinRoundsRequired +#undef tPlayerGfxId +#undef tFishingRod + +void AlignFishingAnimationFrames(void) +{ + struct Sprite *playerSprite = &gSprites[gPlayerAvatar.spriteId]; + u8 animCmdIndex; + u8 animType; + + AnimateSprite(playerSprite); + playerSprite->x2 = 0; + playerSprite->y2 = 0; + animCmdIndex = playerSprite->animCmdIndex; + if (playerSprite->anims[playerSprite->animNum][animCmdIndex].type == -1) + { + animCmdIndex--; + } + else + { + playerSprite->animDelayCounter++; + if (playerSprite->anims[playerSprite->animNum][animCmdIndex].type == -1) + animCmdIndex--; + } + animType = playerSprite->anims[playerSprite->animNum][animCmdIndex].type; + if (animType == 1 || animType == 2 || animType == 3) + { + playerSprite->x2 = 8; + if (GetPlayerFacingDirection() == 3) + playerSprite->x2 = -8; + } + if (animType == 5) + playerSprite->y2 = -8; + if (animType == 10 || animType == 11) + playerSprite->y2 = 8; + if (gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_SURFING) + SetSurfBlob_PlayerOffset(gObjectEvents[gPlayerAvatar.objectEventId].fieldEffectSpriteId, TRUE, playerSprite->y2); +} + +void UpdateChainFishingStreak() +{ + if (!I_FISHING_CHAIN) + return; + + if (gChainFishingDexNavStreak == MAX_u8) + return; + + gChainFishingDexNavStreak++; +} + +u32 CalculateChainFishingShinyRolls(void) +{ + if (!I_FISHING_CHAIN || !gIsFishingEncounter) + return 0; + u32 a = 2 * min(gChainFishingDexNavStreak, FISHING_CHAIN_SHINY_STREAK_MAX); + DebugPrintf("Total Shiny Rolls %d", a); + return a; +} + +bool32 ShouldUseFishingEnvironmentInBattle() +{ + return (I_FISHING_ENVIRONMENT >= GEN_4 && gIsFishingEncounter); +} \ No newline at end of file diff --git a/src/item.c b/src/item.c index d0332f326..a5710932f 100644 --- a/src/item.c +++ b/src/item.c @@ -913,7 +913,7 @@ u32 GetItemSellPrice(u32 itemId) return GetItemPrice(itemId) / ITEM_SELL_FACTOR; } -bool32 IsHoldEffectChoice(enum ItemHoldEffect holdEffect) +bool32 IsHoldEffectChoice(enum HoldEffect holdEffect) { return holdEffect == HOLD_EFFECT_CHOICE_BAND || holdEffect == HOLD_EFFECT_CHOICE_SCARF @@ -939,6 +939,5 @@ bool8 IsItemTMHM(u16 itemId) bool8 IsItemBall(u16 itemId) { - itemId = SanitizeItemId(itemId); - return FIRST_BALL <= itemId && itemId <= LAST_BALL; + return GetPocketByItemId(itemId) == POCKET_POKE_BALLS; } diff --git a/src/item_use.c b/src/item_use.c index 30d7222b5..728701c3e 100644 --- a/src/item_use.c +++ b/src/item_use.c @@ -1073,9 +1073,10 @@ bool32 CannotUseItemsInBattle(u16 itemId, struct Pokemon *mon) } break; case EFFECT_ITEM_INCREASE_ALL_STATS: + u32 ability = GetBattlerAbility(gBattlerInMenuId); for (i = STAT_ATK; i < NUM_STATS; i++) { - if (CompareStat(gBattlerInMenuId, i, MAX_STAT_STAGE, CMP_EQUAL)) + if (CompareStat(gBattlerInMenuId, i, MAX_STAT_STAGE, CMP_EQUAL, ability)) { cannotUse = TRUE; break; diff --git a/src/learn_move.c b/src/learn_move.c index 9180b00c8..0b78d9854 100644 --- a/src/learn_move.c +++ b/src/learn_move.c @@ -16,6 +16,7 @@ #include "strings.h" #include "constants/songs.h" #include "constants/moves.h" +#include "constants/move_relearner.h" /* * Move relearner state machine diff --git a/src/party_menu.c b/src/party_menu.c index 75f9628bd..d30a87c2d 100644 --- a/src/party_menu.c +++ b/src/party_menu.c @@ -7122,13 +7122,14 @@ static void Task_PartyMenuWaitForFade(u8 taskId) #define tAnimWait data[2] #define tNextFunc 3 -#define fusionType data[7] -#define firstFusion data[8] -#define firstFusionSlot data[9] -#define fusionResult data[10] -#define secondFusionSlot data[11] -#define unfuseSecondMon data[12] -#define moveToLearn data[13] +#define fusionType data[6] +#define firstFusion data[7] +#define firstFusionSlot data[8] +#define fusionResult data[9] +#define secondFusionSlot data[10] +#define unfuseSecondMon data[11] +#define moveToLearn data[12] +#define tExtraMoveHandling data[13] #define forgetMove data[14] #define storageIndex data[15] @@ -7242,6 +7243,96 @@ bool32 TryItemUseFusionChange(u8 taskId, TaskFunc task) } } +static void RestoreFusionMon(struct Pokemon *mon) +{ + s32 i; + + for (i = 0; i < PARTY_SIZE; i++) + { + if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES, NULL) == SPECIES_NONE) + break; + } + + if (i >= PARTY_SIZE) + { + CopyMonToPC(mon); + } + else + { + CopyMon(&gPlayerParty[i], mon, sizeof(*mon)); + gPlayerPartyCount = i + 1; + } +} + +static void DeleteInvalidFusionMoves(struct Pokemon *mon, u32 species) +{ + for (u32 i = 0; i < MAX_MON_MOVES; i++) + { + u32 move = GetMonData(mon, MON_DATA_MOVE1 + i); + bool32 toDelete = TRUE; + const struct LevelUpMove *learnset = GetSpeciesLevelUpLearnset(species); + for (u32 j = 0; learnset[j].move != LEVEL_UP_MOVE_END;j++) + { + if (learnset[j].move == move) + { + toDelete = FALSE; + break; + } + } + if (!toDelete) + continue; + const u16 *learnset2 = GetSpeciesTeachableLearnset(species); + for (u32 j = 0; learnset2[j] != MOVE_UNAVAILABLE;j++) + { + if (learnset2[j] == move) + { + toDelete = FALSE; + break; + } + } + if (!toDelete) + continue; + const u16 *learnset3 = GetSpeciesEggMoves(species); + for (u32 j = 0; learnset3[j] != MOVE_UNAVAILABLE;j++) + { + if (learnset3[j] == move) + { + toDelete = FALSE; + break; + } + } + if (toDelete) + DeleteMove(mon, move); + } +} + +static void SwapFusionMonMoves(struct Pokemon *mon, const u16 moveTable[][2], u32 mode) +{ + u32 oldMoveIndex, newMoveIndex; + if (mode == FUSE_MON) + { + oldMoveIndex = 0; + newMoveIndex = 1; + } + else //mode == UNFUSE_MON + { + oldMoveIndex = 1; + newMoveIndex = 0; + } + for (u32 i = 0; i < MAX_MON_MOVES; i++) + { + u32 move = GetMonData(mon, MON_DATA_MOVE1 + i); + for (u32 j = 0; j < 2; j++) + { + if (move == moveTable[j][oldMoveIndex]) + { + SetMonData(mon, MON_DATA_MOVE1 + i, &moveTable[j][newMoveIndex]); + SetMonData(mon, MON_DATA_PP1 + i, &gMovesInfo[moveTable[j][newMoveIndex]].pp); + } + } + } +} + static void Task_TryItemUseFusionChange(u8 taskId) { struct Pokemon *mon = &gPlayerParty[gTasks[taskId].firstFusionSlot]; @@ -7262,7 +7353,7 @@ static void Task_TryItemUseFusionChange(u8 taskId) else { mon2 = &gPokemonStoragePtr->fusions[gTasks[taskId].storageIndex]; - GiveMonToPlayer(mon2); + RestoreFusionMon(mon2); ZeroMonData(&gPokemonStoragePtr->fusions[gTasks[taskId].storageIndex]); } targetSpecies = gTasks[taskId].tTargetSpecies; @@ -7333,15 +7424,38 @@ static void Task_TryItemUseFusionChange(u8 taskId) case 6: if (!IsPartyMenuTextPrinterActive()) { - if (gTasks[taskId].moveToLearn != 0) + if (gTasks[taskId].fusionType == FUSE_MON) { - if (gTasks[taskId].fusionType == FUSE_MON) +#if P_FAMILY_KYUREM +#if P_FAMILY_RESHIRAM + if (gTasks[taskId].tExtraMoveHandling == SWAP_EXTRA_MOVES_KYUREM_WHITE) + SwapFusionMonMoves(mon, gKyuremWhiteSwapMoveTable, FUSE_MON); +#endif //P_FAMILY_RESHIRAM +#if P_FAMILY_ZEKROM + if (gTasks[taskId].tExtraMoveHandling == SWAP_EXTRA_MOVES_KYUREM_BLACK) + SwapFusionMonMoves(mon, gKyuremBlackSwapMoveTable, FUSE_MON); +#endif //P_FAMILY_ZEKROM +#endif //P_FAMILY_KYUREM + if (gTasks[taskId].moveToLearn != 0) FormChangeTeachMove(taskId, gTasks[taskId].moveToLearn, gTasks[taskId].firstFusionSlot); - else + } + else //(gTasks[taskId].fusionType == UNFUSE_MON) + { +#if P_FAMILY_KYUREM +#if P_FAMILY_RESHIRAM + if (gTasks[taskId].tExtraMoveHandling == SWAP_EXTRA_MOVES_KYUREM_WHITE) + SwapFusionMonMoves(mon, gKyuremWhiteSwapMoveTable, UNFUSE_MON); +#endif //P_FAMILY_RESHIRAM +#if P_FAMILY_ZEKROM + if (gTasks[taskId].tExtraMoveHandling == SWAP_EXTRA_MOVES_KYUREM_BLACK) + SwapFusionMonMoves(mon, gKyuremBlackSwapMoveTable, UNFUSE_MON); +#endif //P_FAMILY_ZEKROM +#endif //P_FAMILY_KYUREM + if ( gTasks[taskId].tExtraMoveHandling == FORGET_EXTRA_MOVES) { - DeleteMove(mon, gTasks[taskId].forgetMove); + DeleteInvalidFusionMoves(mon, gTasks[taskId].fusionResult); if (!DoesMonHaveAnyMoves(mon)) - FormChangeTeachMove(taskId, gTasks[taskId].moveToLearn, gTasks[taskId].firstFusionSlot); + FormChangeTeachMove(taskId, MOVE_CONFUSION, gTasks[taskId].firstFusionSlot); } } gTasks[taskId].tState++; @@ -7388,7 +7502,7 @@ void ItemUseCB_Fusion(u8 taskId, TaskFunc taskFunc) task->storageIndex = itemFusion[i].fusionStorageIndex; task->fusionResult = itemFusion[i].targetSpecies1; task->unfuseSecondMon = itemFusion[i].targetSpecies2; - task->moveToLearn = itemFusion[i].unfuseForgetMove; + task->tExtraMoveHandling = itemFusion[i].extraMoveHandling; task->forgetMove = itemFusion[i].fusionMove; TryItemUseFusionChange(taskId, taskFunc); return; @@ -7428,6 +7542,7 @@ void ItemUseCB_Fusion(u8 taskId, TaskFunc taskFunc) task->fusionResult = itemFusion[i].fusingIntoMon; task->secondFusionSlot = gPartyMenu.slotId; task->moveToLearn = itemFusion[i].fusionMove; + task->tExtraMoveHandling = itemFusion[i].extraMoveHandling; // Start Fusion TryItemUseFusionChange(taskId, taskFunc); return; diff --git a/src/pokemon.c b/src/pokemon.c index 498c9ce61..58986a87d 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -12,6 +12,7 @@ #include "battle_tower.h" #include "battle_z_move.h" #include "data.h" +#include "daycare.h" #include "dexnav.h" #include "event_data.h" #include "event_object_movement.h" @@ -19,12 +20,14 @@ #include "field_player_avatar.h" #include "field_specials.h" #include "field_weather.h" +#include "fishing.h" #include "follower_npc.h" #include "graphics.h" #include "item.h" #include "caps.h" #include "link.h" #include "main.h" +// #include "move_relearner.h" #include "overworld.h" #include "m4a.h" #include "party_menu.h" @@ -56,7 +59,6 @@ #include "constants/cries.h" #include "constants/event_objects.h" #include "constants/form_change_types.h" -#include "constants/hold_effects.h" #include "constants/item_effects.h" #include "constants/items.h" #include "constants/layouts.h" @@ -66,7 +68,7 @@ #include "constants/trainers.h" #include "constants/union_room.h" #include "constants/weather.h" -#include "wild_encounter.h" +#include "constants/move_relearner.h" #define FRIENDSHIP_EVO_THRESHOLD ((P_FRIENDSHIP_EVO_THRESHOLD >= GEN_8) ? 160 : 220) @@ -122,7 +124,7 @@ static const struct CombinedMove sCombinedMoves[2] = #define HOENN_TO_NATIONAL(name) [HOENN_DEX_##name - HOENN_DEX_START] = NATIONAL_DEX_##name -static const enum NationalDexOrder sKantoDexNumToNationalDexNum[KANTO_DEX_COUNT] = +static const enum NationalDexOrder sKantoToNationalOrder[KANTO_DEX_COUNT] = { // Kanto KANTO_TO_NATIONAL(BULBASAUR), @@ -627,7 +629,7 @@ static const enum NationalDexOrder sHoennToNationalOrder[HOENN_DEX_COUNT - 1] = HOENN_TO_NATIONAL(DEOXYS), }; -static const struct SpindaSpot sSpindaSpotGraphics[] = +static const struct SpindaSpot gSpindaSpotGraphics[] = { {.x = 16, .y = 7, .image = INCBIN_U16("graphics/spinda_spots/spot_0.bin")}, {.x = 40, .y = 8, .image = INCBIN_U16("graphics/spinda_spots/spot_1.bin")}, @@ -1022,7 +1024,7 @@ static const u8 sGetMonDataEVConstants[] = }; // For stat-raising items -static const u8 sStatsToRaise[] = +static const enum Stat sStatsToRaise[] = { STAT_ATK, STAT_ATK, STAT_DEF, STAT_SPEED, STAT_SPATK, STAT_SPDEF, STAT_ACC }; @@ -1213,8 +1215,8 @@ void CreateBoxMon(struct BoxPokemon *boxMon, u16 species, u8 level, u8 fixedIV, u32 value; u16 checksum; u8 i; - u8 availableIVs[NUM_STATS]; - u8 selectedIvs[NUM_STATS]; + enum Stat availableIVs[NUM_STATS]; + enum Stat selectedIvs[NUM_STATS]; bool32 isShiny; ZeroBoxMonData(boxMon); @@ -1260,8 +1262,7 @@ void CreateBoxMon(struct BoxPokemon *boxMon, u16 species, u8 level, u8 fixedIV, totalRerolls += I_SHINY_CHARM_ADDITIONAL_ROLLS; if (LURE_STEP_COUNT != 0) totalRerolls += 1; - if (I_FISHING_CHAIN && gIsFishingEncounter) - totalRerolls += CalculateChainFishingShinyRolls(); + totalRerolls += CalculateChainFishingShinyRolls(); if (gDexNavSpecies) totalRerolls += CalculateDexNavShinyRolls(); @@ -1300,7 +1301,7 @@ void CreateBoxMon(struct BoxPokemon *boxMon, u16 species, u8 level, u8 fixedIV, SetBoxMonData(boxMon, MON_DATA_POKEBALL, &value); SetBoxMonData(boxMon, MON_DATA_OT_GENDER, &gSaveBlock2Ptr->playerGender); - u32 teraType = (boxMon->personality & 0x1) == 0 ? GetSpeciesType(species, 0) : GetSpeciesType(species, 1); + enum Type teraType = (boxMon->personality & 0x1) == 0 ? GetSpeciesType(species, 0) : GetSpeciesType(species, 1); SetBoxMonData(boxMon, MON_DATA_TERA_TYPE, &teraType); if (fixedIV < USE_RANDOM_IVS) @@ -1372,6 +1373,8 @@ void CreateBoxMon(struct BoxPokemon *boxMon, u16 species, u8 level, u8 fixedIV, case STAT_SPDEF: SetBoxMonData(boxMon, MON_DATA_SPDEF_IV, &iv); break; + default: + break; } } } @@ -1862,32 +1865,10 @@ static u16 CalculateBoxMonChecksumReencrypt(struct BoxPokemon *boxMon) return checksum; } -#define CALC_STAT(base, iv, ev, statIndex, field) \ -{ \ - u8 baseStat = gSpeciesInfo[species].base; \ - s32 n = (((2 * baseStat + iv + ev / 4) * level) / 100) + 5; \ - n = ModifyStatByNature(nature, n, statIndex); \ - if (B_FRIENDSHIP_BOOST == TRUE) \ - n = n + ((n * 10 * friendship) / (MAX_FRIENDSHIP * 100));\ - SetMonData(mon, field, &n); \ -} - void CalculateMonStats(struct Pokemon *mon) { s32 oldMaxHP = GetMonData(mon, MON_DATA_MAX_HP, NULL); s32 currentHP = GetMonData(mon, MON_DATA_HP, NULL); - s32 hpIV = GetMonData(mon, MON_DATA_HYPER_TRAINED_HP) ? MAX_PER_STAT_IVS : GetMonData(mon, MON_DATA_HP_IV, NULL); - s32 hpEV = GetMonData(mon, MON_DATA_HP_EV, NULL); - s32 attackIV = GetMonData(mon, MON_DATA_HYPER_TRAINED_ATK) ? MAX_PER_STAT_IVS : GetMonData(mon, MON_DATA_ATK_IV, NULL); - s32 attackEV = GetMonData(mon, MON_DATA_ATK_EV, NULL); - s32 defenseIV = GetMonData(mon, MON_DATA_HYPER_TRAINED_DEF) ? MAX_PER_STAT_IVS : GetMonData(mon, MON_DATA_DEF_IV, NULL); - s32 defenseEV = GetMonData(mon, MON_DATA_DEF_EV, NULL); - s32 speedIV = GetMonData(mon, MON_DATA_HYPER_TRAINED_SPEED) ? MAX_PER_STAT_IVS : GetMonData(mon, MON_DATA_SPEED_IV, NULL); - s32 speedEV = GetMonData(mon, MON_DATA_SPEED_EV, NULL); - s32 spAttackIV = GetMonData(mon, MON_DATA_HYPER_TRAINED_SPATK) ? MAX_PER_STAT_IVS : GetMonData(mon, MON_DATA_SPATK_IV, NULL); - s32 spAttackEV = GetMonData(mon, MON_DATA_SPATK_EV, NULL); - s32 spDefenseIV = GetMonData(mon, MON_DATA_HYPER_TRAINED_SPDEF) ? MAX_PER_STAT_IVS : GetMonData(mon, MON_DATA_SPDEF_IV, NULL); - s32 spDefenseEV = GetMonData(mon, MON_DATA_SPDEF_EV, NULL); u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL); u8 friendship = GetMonData(mon, MON_DATA_FRIENDSHIP, NULL); s32 level = GetLevelFromMonExp(mon); @@ -1897,28 +1878,55 @@ void CalculateMonStats(struct Pokemon *mon) SetMonData(mon, MON_DATA_LEVEL, &level); + bool32 hyperTrained[NUM_STATS]; //In a battle test, hyper training flag indicates a fixed stat + s32 iv[NUM_STATS]; + s32 ev[NUM_STATS]; + for (u32 i = 0; i < NUM_STATS; i++) + { + hyperTrained[i] = GetMonData(mon, MON_DATA_HYPER_TRAINED_HP + i); + iv[i] = GetMonData(mon, MON_DATA_HP_IV + i); + ev[i] = GetMonData(mon, MON_DATA_HP_EV + i); + + if (hyperTrained[i]) + { + #if TESTING + if (gMain.inBattle) + continue; + #endif + iv[i] = MAX_PER_STAT_IVS; + } + + if (i == STAT_HP) + continue; + + u8 baseStat = GetSpeciesBaseStat(species, i); + s32 n = (((2 * baseStat + iv[i] + ev[i] / 4) * level) / 100) + 5; + n = ModifyStatByNature(nature, n, i); + if (B_FRIENDSHIP_BOOST == TRUE) + n = n + ((n * 10 * friendship) / (MAX_FRIENDSHIP * 100)); + SetMonData(mon, MON_DATA_MAX_HP + i, &n); + } + +#if TESTING + if (hyperTrained[STAT_HP] && gMain.inBattle) + return; +#endif + if (species == SPECIES_SHEDINJA) { newMaxHP = 1; } else { - s32 n = 2 * GetSpeciesBaseHP(species) + hpIV; - newMaxHP = (((n + hpEV / 4) * level) / 100) + level + 10; + s32 n = 2 * GetSpeciesBaseHP(species) + iv[STAT_HP]; + newMaxHP = (((n + ev[STAT_HP] / 4) * level) / 100) + level + 10; } gBattleScripting.levelUpHP = newMaxHP - oldMaxHP; if (gBattleScripting.levelUpHP == 0) gBattleScripting.levelUpHP = 1; - SetMonData(mon, MON_DATA_MAX_HP, &newMaxHP); - CALC_STAT(baseAttack, attackIV, attackEV, STAT_ATK, MON_DATA_ATK) - CALC_STAT(baseDefense, defenseIV, defenseEV, STAT_DEF, MON_DATA_DEF) - CALC_STAT(baseSpeed, speedIV, speedEV, STAT_SPEED, MON_DATA_SPEED) - CALC_STAT(baseSpAttack, spAttackIV, spAttackEV, STAT_SPATK, MON_DATA_SPATK) - CALC_STAT(baseSpDefense, spDefenseIV, spDefenseEV, STAT_SPDEF, MON_DATA_SPDEF) - // Since a pokemon's maxHP data could either not have // been initialized at this point or this pokemon is // just fainted, the check for oldMaxHP is important. @@ -2905,7 +2913,7 @@ u32 GetBoxMonData3(struct BoxPokemon *boxMon, s32 field, u8 *data) } else if (substruct0->teraType == TYPE_NONE) // Tera Type hasn't been modified so we can just use the personality { - const u8 *types = gSpeciesInfo[substruct0->species].types; + const enum Type *types = gSpeciesInfo[substruct0->species].types; retVal = (boxMon->personality & 0x1) == 0 ? types[0] : types[1]; } else @@ -3008,6 +3016,19 @@ u32 GetBoxMonData2(struct BoxPokemon *boxMon, s32 field) #define SET8(lhs) (lhs) = *data #define SET16(lhs) (lhs) = data[0] + (data[1] << 8) #define SET32(lhs) (lhs) = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24) +// +// Prefer SET_BY_WIDTH for fields whose types might be extended (e.g. +// anything whose typedef is in gametypes.h). +// +#define SET_BY_WIDTH(lhs) \ + do { \ + if (sizeof(lhs) == 1) \ + SET8(lhs); \ + else if (sizeof(lhs) == 2) \ + SET16(lhs); \ + else if (sizeof(lhs) == 4) \ + SET32(lhs); \ + } while (0) void SetMonData(struct Pokemon *mon, s32 field, const void *dataArg) { @@ -3698,7 +3719,7 @@ u32 GetSpeciesWeight(u16 species) return gSpeciesInfo[SanitizeSpeciesId(species)].weight; } -u32 GetSpeciesType(u16 species, u8 slot) +enum Type GetSpeciesType(u16 species, u8 slot) { return gSpeciesInfo[SanitizeSpeciesId(species)].types[slot]; } @@ -3738,6 +3759,26 @@ u32 GetSpeciesBaseSpeed(u16 species) return gSpeciesInfo[SanitizeSpeciesId(species)].baseSpeed; } +u32 GetSpeciesBaseStat(u16 species, u32 statIndex) +{ + switch (statIndex) + { + case STAT_HP: + return GetSpeciesBaseHP(species); + case STAT_ATK: + return GetSpeciesBaseAttack(species); + case STAT_DEF: + return GetSpeciesBaseDefense(species); + case STAT_SPEED: + return GetSpeciesBaseSpeed(species); + case STAT_SPATK: + return GetSpeciesBaseSpAttack(species); + case STAT_SPDEF: + return GetSpeciesBaseSpDefense(species); + } + return 0; +} + const struct LevelUpMove *GetSpeciesLevelUpLearnset(u16 species) { const struct LevelUpMove *learnset = gSpeciesInfo[SanitizeSpeciesId(species)].levelUpLearnset; @@ -3915,9 +3956,9 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov u8 itemEffectParam = ITEM_EFFECT_ARG_START; u32 temp1, temp2; s8 friendshipChange = 0; - u8 holdEffect; + enum HoldEffect holdEffect; u8 battler = MAX_BATTLERS_COUNT; - u32 friendshipOnly = FALSE; + bool32 friendshipOnly = FALSE; u16 heldItem; u8 effectFlags; s8 evChange; @@ -4502,7 +4543,7 @@ u8 GetItemEffectParamOffset(u32 battler, u16 itemId, u8 effectByte, u8 effectBit return offset; } -static void BufferStatRoseMessage(s32 statIdx) +static void BufferStatRoseMessage(enum Stat statIdx) { gBattlerTarget = gBattlerInMenuId; StringCopy(gBattleTextBuff1, gStatNamesTable[sStatsToRaise[statIdx]]); @@ -4616,7 +4657,7 @@ bool32 DoesMonMeetAdditionalConditions(struct Pokemon *mon, const struct Evoluti u32 removeBagItemCount = 0; u32 evolutionTracker = GetMonData(mon, MON_DATA_EVOLUTION_TRACKER, 0); u32 partnerSpecies, partnerHeldItem; - enum ItemHoldEffect partnerHoldEffect; + enum HoldEffect partnerHoldEffect; if (tradePartner != NULL) { @@ -4643,7 +4684,7 @@ bool32 DoesMonMeetAdditionalConditions(struct Pokemon *mon, const struct Evoluti for (i = 0; params != NULL && params[i].condition != CONDITIONS_END; i++) { enum EvolutionConditions condition = params[i].condition; - u32 currentCondition = FALSE; + bool32 currentCondition = FALSE; switch(condition) { @@ -4934,7 +4975,7 @@ u32 GetEvolutionTargetSpecies(struct Pokemon *mon, enum EvolutionMode mode, u16 u32 species = GetMonData(mon, MON_DATA_SPECIES, 0); u32 heldItem = GetMonData(mon, MON_DATA_HELD_ITEM, 0); u32 level = GetMonData(mon, MON_DATA_LEVEL, 0); - u32 holdEffect; + enum HoldEffect holdEffect; const struct Evolution *evolutions = GetSpeciesEvolutions(species); if (evolutions == NULL) @@ -5016,7 +5057,7 @@ u32 GetEvolutionTargetSpecies(struct Pokemon *mon, enum EvolutionMode mode, u16 case EVO_MODE_ITEM_CHECK: for (i = 0; evolutions[i].method != EVOLUTIONS_END; i++) { - bool32 conditionMet = FALSE; + bool32 conditionsMet = FALSE; if (SanitizeSpeciesId(evolutions[i].targetSpecies) == SPECIES_NONE) continue; @@ -5024,11 +5065,11 @@ u32 GetEvolutionTargetSpecies(struct Pokemon *mon, enum EvolutionMode mode, u16 { case EVO_ITEM: if (evolutions[i].param == evolutionItem) - conditionMet = TRUE; + conditionsMet = TRUE; break; } - if (conditionMet && DoesMonMeetAdditionalConditions(mon, evolutions[i].params, NULL, PARTY_SIZE, canStopEvo, evoState)) + if (conditionsMet && DoesMonMeetAdditionalConditions(mon, evolutions[i].params, NULL, PARTY_SIZE, canStopEvo, evoState)) { // All checks passed, so stop checking the rest of the evolutions. // This is different from vanilla where the loop continues. @@ -5050,9 +5091,9 @@ u32 GetEvolutionTargetSpecies(struct Pokemon *mon, enum EvolutionMode mode, u16 switch (evolutions[i].method) { - case EVO_BATTLE_END: - conditionsMet = TRUE; - break; + case EVO_BATTLE_END: + conditionsMet = TRUE; + break; } if (conditionsMet && DoesMonMeetAdditionalConditions(mon, evolutions[i].params, NULL, evolutionItem, canStopEvo, evoState)) @@ -5078,7 +5119,6 @@ u32 GetEvolutionTargetSpecies(struct Pokemon *mon, enum EvolutionMode mode, u16 case EVO_SPIN: if (gSpecialVar_0x8000 == evolutions[i].param) conditionsMet = TRUE; - break; } @@ -5178,7 +5218,7 @@ enum HoennDexOrder NationalToHoennOrder(enum NationalDexOrder nationalNum) hoennNum = 0; - while (hoennNum < (HOENN_DEX_COUNT - 1) && sHoennToNationalOrder[hoennNum - HOENN_DEX_START] != nationalNum) + while (hoennNum < (HOENN_DEX_COUNT - 1) && sHoennToNationalOrder[hoennNum] != nationalNum) hoennNum++; if (hoennNum >= HOENN_DEX_COUNT - 1) @@ -5232,9 +5272,9 @@ enum KantoDexOrder NationalToKantoDexNum(enum NationalDexOrder natDexNum) return KANTO_DEX_NONE; } - for (i = 0; i < ARRAY_COUNT(sKantoDexNumToNationalDexNum); i++) + for (i = 0; i < ARRAY_COUNT(sKantoToNationalOrder); i++) { - if (sKantoDexNumToNationalDexNum[i] == natDexNum) + if (sKantoToNationalOrder[i] == natDexNum) { return i + KANTO_DEX_START; } @@ -5258,7 +5298,7 @@ bool32 IsSpeciesInKantoDex(u16 species) enum NationalDexOrder KantoToNationalDexNum(enum KantoDexOrder kantoNum) { if (KANTO_DEX_START <= kantoNum && kantoNum < KANTO_DEX_END) - return sKantoDexNumToNationalDexNum[kantoNum - KANTO_DEX_START]; + return sKantoToNationalOrder[kantoNum - KANTO_DEX_START]; return NATIONAL_DEX_NONE; } @@ -5310,11 +5350,11 @@ u16 KantoNumToSpecies(enum KantoDexOrder kantoNum) void DrawSpindaSpots(u32 personality, u8 *dest, bool32 isSecondFrame) { s32 i; - for (i = 0; i < (s32)ARRAY_COUNT(sSpindaSpotGraphics); i++) + for (i = 0; i < (s32)ARRAY_COUNT(gSpindaSpotGraphics); i++) { s32 row; - u8 x = sSpindaSpotGraphics[i].x + (personality & 0x0F); - u8 y = sSpindaSpotGraphics[i].y + ((personality & 0xF0) >> 4); + u8 x = gSpindaSpotGraphics[i].x + (personality & 0x0F); + u8 y = gSpindaSpotGraphics[i].y + ((personality & 0xF0) >> 4); if (isSecondFrame) { @@ -5330,7 +5370,7 @@ void DrawSpindaSpots(u32 personality, u8 *dest, bool32 isSecondFrame) for (row = 0; row < SPINDA_SPOT_HEIGHT; row++) { s32 column; - s32 spotPixelRow = sSpindaSpotGraphics[i].image[row]; + s32 spotPixelRow = gSpindaSpotGraphics[i].image[row]; for (column = x; column < x + SPINDA_SPOT_WIDTH; column++) { @@ -5429,7 +5469,7 @@ u8 GetTrainerEncounterMusicId(u16 trainerOpponentId) return gTrainers[difficulty][sanitizedTrainerId].encounterMusic_gender & (F_TRAINER_FEMALE - 1); } -u16 ModifyStatByNature(u8 nature, u16 stat, u8 statIndex) +u16 ModifyStatByNature(u8 nature, u16 stat, enum Stat statIndex) { // Don't modify HP, Accuracy, or Evasion by nature if (statIndex <= STAT_HP || statIndex > NUM_NATURE_STATS || gNaturesInfo[nature].statUp == gNaturesInfo[nature].statDown) @@ -5445,7 +5485,7 @@ u16 ModifyStatByNature(u8 nature, u16 stat, u8 statIndex) void AdjustFriendship(struct Pokemon *mon, u8 event) { u16 species, heldItem; - u8 holdEffect; + enum HoldEffect holdEffect; s8 mod; if (ShouldSkipFriendshipChange()) @@ -5527,8 +5567,9 @@ void MonGainEVs(struct Pokemon *mon, u16 defeatedSpecies) u16 evIncrease = 0; u16 totalEVs = 0; u16 heldItem; - u8 holdEffect; - int i, multiplier; + enum HoldEffect holdEffect; + enum Stat i; + int multiplier; u8 stat; u8 bonus; u32 currentEVCap = GetCurrentEVCap(); @@ -5607,6 +5648,8 @@ void MonGainEVs(struct Pokemon *mon, u16 defeatedSpecies) else evIncrease = gSpeciesInfo[defeatedSpecies].evYield_SpDefense * multiplier; break; + default: + break; } if (holdEffect == HOLD_EFFECT_MACHO_BRACE) @@ -5890,7 +5933,6 @@ u8 CanLearnTeachableMove(u16 species, u16 move) return FALSE; } } - u8 GetMoveRelearnerMoves(struct Pokemon *mon, u16 *moves) { u16 learnedMoves[4]; @@ -5987,6 +6029,282 @@ u8 GetNumberOfRelearnableMoves(struct Pokemon *mon) return numMoves; } +static void QuickSortMoves(u16 *moves, s32 left, s32 right) +{ + if (left >= right) + return; + + u16 pivot = moves[(left + right) / 2]; + s32 i = left, j = right; + + while (i <= j) + { + while (moves[i] != MOVE_NONE && StringCompare(GetMoveName(moves[i]), GetMoveName(pivot)) < 0) + i++; + while (moves[j] != MOVE_NONE && StringCompare(GetMoveName(moves[j]), GetMoveName(pivot)) > 0) + j--; + + if (i <= j) + { + u16 temp = moves[i]; + moves[i] = moves[j]; + moves[j] = temp; + i++; + j--; + } + } + + QuickSortMoves(moves, left, j); + QuickSortMoves(moves, i, right); +} + +static void SortMovesAlphabetically(u16 *moves, u8 numMoves) +{ + if (numMoves > 1) + QuickSortMoves(moves, 0, numMoves - 1); +} + +u8 GetRelearnerLevelUpMoves(struct Pokemon *mon, u16 *moves) +{ + u16 learnedMoves[MAX_MON_MOVES] = {0}; + u8 numMoves = 0; + u16 species = GetMonData(mon, MON_DATA_SPECIES, 0); + u8 level = (P_ENABLE_ALL_LEVEL_UP_MOVES ? MAX_LEVEL : GetMonData(mon, MON_DATA_LEVEL, 0)); + + for (u8 i = 0; i < MAX_MON_MOVES; i++) + learnedMoves[i] = GetMonData(mon, MON_DATA_MOVE1 + i, 0); + + do + { + const struct LevelUpMove *learnset = GetSpeciesLevelUpLearnset(species); + + for (u16 i = 0; i < MAX_LEVEL_UP_MOVES && learnset[i].move != LEVEL_UP_MOVE_END; i++) + { + if (learnset[i].level > level) + continue; + + u16 j; + for (j = 0; j < MAX_MON_MOVES; j++) + { + if (learnedMoves[j] == learnset[i].move) + break; + } + if (j < MAX_MON_MOVES) + continue; + + for (j = 0; j < numMoves; j++) + { + if (moves[j] == learnset[i].move) + break; + } + if (j < numMoves) + continue; + + moves[numMoves++] = learnset[i].move; + } + + species = (P_PRE_EVO_MOVES ? GetSpeciesPreEvolution(species) : SPECIES_NONE); + } while (species != SPECIES_NONE); + + if (P_SORT_MOVES) + SortMovesAlphabetically(moves, numMoves); + + return numMoves; +} + +u8 GetRelearnerEggMoves(struct Pokemon *mon, u16 *moves) +{ + u16 learnedMoves[MAX_MON_MOVES] = {0}; + u8 numMoves = 0; + u16 species = GetMonData(mon, MON_DATA_SPECIES); + + while (GetSpeciesPreEvolution(species) != SPECIES_NONE) + species = GetSpeciesPreEvolution(species); + const u16 *eggMoves = GetSpeciesEggMoves(species); + + if (eggMoves == sNoneEggMoveLearnset) + return numMoves; + + for (u8 i = 0; i < MAX_MON_MOVES; i++) + learnedMoves[i] = GetMonData(mon, MON_DATA_MOVE1 + i, 0); + + for (u16 i = 0; eggMoves[i] != MOVE_UNAVAILABLE; i++) + { + u16 j; + for (j = 0; j < MAX_MON_MOVES; j++) + { + if (learnedMoves[j] == eggMoves[i]) + break; + } + if (j < MAX_MON_MOVES) + continue; + + for (j = 0; j < numMoves; j++) + { + if (moves[j] == eggMoves[i]) + break; + } + if (j < numMoves) + continue; + + moves[numMoves++] = eggMoves[i]; + } + + if (P_SORT_MOVES) + SortMovesAlphabetically(moves, numMoves); + + return numMoves; +} + +u8 GetRelearnerTMMoves(struct Pokemon *mon, u16 *moves) +{ + u16 learnedMoves[MAX_MON_MOVES] = {0}; + u8 numMoves = 0; + u16 species = GetMonData(mon, MON_DATA_SPECIES); + u16 allMoves[NUM_ALL_MACHINES]; + u16 totalMoveCount = 0; + + for (u16 i = 0; i < NUM_ALL_MACHINES; i++) + { + enum TMHMItemId item = GetTMHMItemId(i + 1); + u16 move = GetTMHMMoveId(i + 1); + if ((P_ENABLE_ALL_TM_MOVES || CheckBagHasItem(item, 1)) && CanLearnTeachableMove(species, move) && move != MOVE_NONE) + allMoves[totalMoveCount++] = move; + } + + for (u8 i = 0; i < MAX_MON_MOVES; i++) + learnedMoves[i] = GetMonData(mon, MON_DATA_MOVE1 + i, 0); + + for (u16 i = 0; i < totalMoveCount; i++) + { + u16 j; + for (j = 0; j < MAX_MON_MOVES; j++) + { + if (learnedMoves[j] == allMoves[i]) + break; + } + if (j < MAX_MON_MOVES) + continue; + + for (j = 0; j < numMoves; j++) + { + if (moves[j] == allMoves[i]) + break; + } + if (j < numMoves) + continue; + + moves[numMoves++] = allMoves[i]; + } + + if (P_SORT_MOVES) + SortMovesAlphabetically(moves, numMoves); + + return numMoves; +} + +u8 GetRelearnerTutorMoves(struct Pokemon *mon, u16 *moves) +{ +#if P_TUTOR_MOVES_ARRAY + u16 learnedMoves[MAX_MON_MOVES] = {0}; + u8 numMoves = 0; + u16 species = GetMonData(mon, MON_DATA_SPECIES, 0); + + for (u8 i = 0; i < MAX_MON_MOVES; i++) + learnedMoves[i] = GetMonData(mon, MON_DATA_MOVE1 + i, 0); + + for (u16 i = 0; gTutorMoves[i] != MOVE_UNAVAILABLE; i++) + { + u16 move = gTutorMoves[i]; + + if (!CanLearnTeachableMove(species, move)) + continue; + + u16 j; + for (j = 0; j < MAX_MON_MOVES; j++) + { + if (learnedMoves[j] == move) + break; + } + if (j < MAX_MON_MOVES) + continue; + + for (j = 0; j < numMoves; j++) + { + if (moves[j] == move) + break; + } + if (j < numMoves) + continue; + + moves[numMoves++] = move; + } + + if (P_SORT_MOVES) + SortMovesAlphabetically(moves, numMoves); + + return numMoves; +#else + return 0; +#endif // P_TUTOR_MOVES_ARRAY +} + +u8 GetNumberOfLevelUpMoves(struct Pokemon *mon) +{ + u16 moves[MAX_RELEARNER_MOVES] = {0}; + u16 species = GetMonData(mon, MON_DATA_SPECIES_OR_EGG, 0); + + if (species == SPECIES_EGG) + return 0; + + return GetRelearnerLevelUpMoves(mon, moves); +} + +u8 GetNumberOfEggMoves(struct Pokemon *mon) +{ + if (!FlagGet(P_FLAG_EGG_MOVES) && !P_ENABLE_MOVE_RELEARNERS) + return 0; + + u16 moves[EGG_MOVES_ARRAY_COUNT] = {0}; + u16 species = GetMonData(mon, MON_DATA_SPECIES_OR_EGG, 0); + + if (species == SPECIES_EGG) + return 0; + + return GetRelearnerEggMoves(mon, moves); +} + +u8 GetNumberOfTMMoves(struct Pokemon *mon) +{ + if (!P_TM_MOVES_RELEARNER) + return 0; + + if (!P_ENABLE_ALL_TM_MOVES && !IsBagPocketNonEmpty(POCKET_TM_HM)) + return 0; + + u16 moves[MAX_RELEARNER_MOVES] = {0}; + u16 species = GetMonData(mon, MON_DATA_SPECIES_OR_EGG, 0); + + if (species == SPECIES_EGG) + return 0; + + return GetRelearnerTMMoves(mon, moves); +} + +u8 GetNumberOfTutorMoves(struct Pokemon *mon) +{ + if (!FlagGet(P_FLAG_TUTOR_MOVES) && !P_ENABLE_MOVE_RELEARNERS) + return 0; + + u16 moves[MAX_RELEARNER_MOVES] = {0}; + u16 species = GetMonData(mon, MON_DATA_SPECIES_OR_EGG, 0); + + if (species == SPECIES_EGG) + return 0; + + return GetRelearnerTutorMoves(mon, moves); +} + u16 SpeciesToPokedexNum(u16 species) { if (IsNationalPokedexEnabled()) @@ -6544,6 +6862,14 @@ void HandleSetPokedexFlag(enum NationalDexOrder nationalNum, u8 caseId, u32 pers } } +void HandleSetPokedexFlagFromMon(struct Pokemon *mon, u32 caseId) +{ + u32 personality = GetMonData(mon, MON_DATA_PERSONALITY); + enum NationalDexOrder nationalNum = SpeciesToNationalPokedexNum(GetMonData(mon, MON_DATA_SPECIES)); + + HandleSetPokedexFlag(nationalNum, caseId, personality); +} + bool8 HasTwoFramesAnimation(u16 species) { return P_TWO_FRAME_FRONT_SPRITES @@ -7046,7 +7372,7 @@ bool32 SpeciesHasGenderDifferences(u16 species) return FALSE; } -bool32 TryFormChange(u32 monId, u32 side, enum FormChanges method) +bool32 TryFormChange(u32 monId, enum BattleSide side, enum FormChanges method) { struct Pokemon *party = (side == B_SIDE_PLAYER) ? gPlayerParty : gEnemyParty; @@ -7164,7 +7490,7 @@ void UpdateMonPersonality(struct BoxPokemon *boxMon, u32 personality) bool32 isShiny = GetBoxMonData(boxMon, MON_DATA_IS_SHINY, NULL); u32 hiddenNature = GetBoxMonData(boxMon, MON_DATA_HIDDEN_NATURE, NULL); - u32 teraType = GetBoxMonData(boxMon, MON_DATA_TERA_TYPE, NULL); + enum Type teraType = GetBoxMonData(boxMon, MON_DATA_TERA_TYPE, NULL); old = *boxMon; old0 = &(GetSubstruct(&old, old.personality, SUBSTRUCT_TYPE_0)->type0); @@ -7279,9 +7605,9 @@ void UpdateDaysPassedSinceFormChange(u16 days) } } -u32 CheckDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum MonState state) +enum Type CheckDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum MonState state) { - u32 moveType = GetDynamicMoveType(mon, move, battler, state); + enum Type moveType = GetDynamicMoveType(mon, move, battler, state); if (moveType != TYPE_NONE) return moveType; return GetMoveType(move); @@ -7361,7 +7687,7 @@ bool32 IsSpeciesForeignRegionalForm(u32 species, u32 currentRegion) return FALSE; } -u32 GetTeraTypeFromPersonality(struct Pokemon *mon) +enum Type GetTeraTypeFromPersonality(struct Pokemon *mon) { const u8 *types = gSpeciesInfo[GetMonData(mon, MON_DATA_SPECIES)].types; return (GetMonData(mon, MON_DATA_PERSONALITY) & 0x1) == 0 ? types[0] : types[1]; @@ -7382,7 +7708,7 @@ void SavePlayerPartyMon(u32 index, struct Pokemon *mon) gSaveBlock1Ptr->playerParty[index] = *mon; } -u32 IsSpeciesOfType(u32 species, u32 type) +bool32 IsSpeciesOfType(u32 species, enum Type type) { if (gSpeciesInfo[species].types[0] == type || gSpeciesInfo[species].types[1] == type) diff --git a/src/quest_log_player.c b/src/quest_log_player.c index 6559bd4e7..3446b9426 100644 --- a/src/quest_log_player.c +++ b/src/quest_log_player.c @@ -108,7 +108,7 @@ static void Task_QLFishMovement(u8 taskId) gTasks[taskId].data[1] = 0; break; case 1: - AlignFishingAnimationFrames(sprite); + AlignFishingAnimationFrames(); if (gTasks[taskId].data[1] < 60) gTasks[taskId].data[1]++; else @@ -119,7 +119,7 @@ static void Task_QLFishMovement(u8 taskId) gTasks[taskId].data[0]++; break; case 3: - AlignFishingAnimationFrames(sprite); + AlignFishingAnimationFrames(); if (sprite->animEnded) { if (!(gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_SURFING)) diff --git a/src/recorded_battle.c b/src/recorded_battle.c index 632bb87b7..3d133a8d0 100644 --- a/src/recorded_battle.c +++ b/src/recorded_battle.c @@ -44,7 +44,7 @@ EWRAM_DATA u8 gRecordedBattleMultiplayerId = 0; EWRAM_DATA static u8 sBattleScene = 0; EWRAM_DATA static u8 sTextSpeed = 0; EWRAM_DATA static u32 sBattleFlags = 0; -EWRAM_DATA static u32 sAI_Scripts = 0; +EWRAM_DATA static u64 sAI_Scripts[MAX_BATTLERS_COUNT] = {0}; EWRAM_DATA static struct Pokemon sSavedPlayerParty[PARTY_SIZE] = {0}; EWRAM_DATA static struct Pokemon sSavedOpponentParty[PARTY_SIZE] = {0}; EWRAM_DATA static u16 sPlayerMonMoves[MAX_BATTLERS_COUNT / 2][MAX_MON_MOVES] = {0}; @@ -78,7 +78,7 @@ void RecordedBattle_Init(u8 mode) for (j = 0; j < BATTLER_RECORD_SIZE; j++) sBattleRecords[i][j] = 0xFF; sBattleFlags = gBattleTypeFlags; - sAI_Scripts = gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT]; + sAI_Scripts[i] = gAiThinkingStruct->aiFlags[i]; } } } @@ -271,6 +271,7 @@ void SetVariablesForRecordedBattle(struct RecordedBattleSave *src) gLinkPlayers[i].language = src->playersLanguage[i]; gLinkPlayers[i].id = src->playersBattlers[i]; gLinkPlayers[i].trainerId = src->playersTrainerId[i]; + sAI_Scripts[i] = src->AI_scripts[i]; if (var) ConvertInternationalString(gLinkPlayers[i].name, gLinkPlayers[i].language); @@ -284,7 +285,6 @@ void SetVariablesForRecordedBattle(struct RecordedBattleSave *src) gRecordedBattleMultiplayerId = src->multiplayerId; sBattleScene = src->battleScene; sTextSpeed = src->textSpeed; - sAI_Scripts = src->AI_scripts; for (i = 0; i < PLAYER_NAME_LENGTH + 1; i++) sRecordMixFriendName[i] = src->recordMixFriendName[i]; @@ -449,9 +449,9 @@ void RecordedBattle_CheckMovesetChanges(u8 mode) } } -u32 GetAiScriptsInRecordedBattle(void) +u64 GetAiScriptsInRecordedBattle(u32 battler) { - return sAI_Scripts; + return sAI_Scripts[battler]; } // Used to determine when the player is allowed to press B to end a recorded battle's playback diff --git a/src/wallclock.c b/src/wallclock.c index 35b4b533b..b10c93015 100644 --- a/src/wallclock.c +++ b/src/wallclock.c @@ -61,9 +61,9 @@ enum enum { - MOVE_NONE, - MOVE_BACKWARD, - MOVE_FORWARD, + CLOCK_MOVE_NONE, + CLOCK_MOVE_BACKWARD, + CLOCK_MOVE_FORWARD, }; static const u32 sHand_Gfx[] = INCBIN_U32("graphics/wallclock/hand.4bpp.lz"); @@ -815,15 +815,15 @@ static void Task_SetClock_HandleInput(u8 taskId) } else { - gTasks[taskId].tMoveDir = MOVE_NONE; + gTasks[taskId].tMoveDir = CLOCK_MOVE_NONE; if (JOY_HELD(DPAD_LEFT)) - gTasks[taskId].tMoveDir = MOVE_BACKWARD; + gTasks[taskId].tMoveDir = CLOCK_MOVE_BACKWARD; if (JOY_HELD(DPAD_RIGHT)) - gTasks[taskId].tMoveDir = MOVE_FORWARD; + gTasks[taskId].tMoveDir = CLOCK_MOVE_FORWARD; - if (gTasks[taskId].tMoveDir != MOVE_NONE) + if (gTasks[taskId].tMoveDir != CLOCK_MOVE_NONE) { if (gTasks[taskId].tMoveSpeed < 0xFF) gTasks[taskId].tMoveSpeed++; @@ -926,13 +926,13 @@ static u16 CalcNewMinHandAngle(u16 angle, u8 direction, u8 speed) u8 delta = CalcMinHandDelta(speed); switch (direction) { - case MOVE_BACKWARD: + case CLOCK_MOVE_BACKWARD: if (angle) angle -= delta; else angle = 360 - delta; break; - case MOVE_FORWARD: + case CLOCK_MOVE_FORWARD: if (angle < 360 - delta) angle += delta; else @@ -946,7 +946,7 @@ static bool32 AdvanceClock(u8 taskId, u8 direction) { switch (direction) { - case MOVE_BACKWARD: + case CLOCK_MOVE_BACKWARD: if (gTasks[taskId].tMinutes > 0) { gTasks[taskId].tMinutes--; @@ -963,7 +963,7 @@ static bool32 AdvanceClock(u8 taskId, u8 direction) UpdateClockPeriod(taskId, direction); } break; - case MOVE_FORWARD: + case CLOCK_MOVE_FORWARD: if (gTasks[taskId].tMinutes < 59) { gTasks[taskId].tMinutes++; @@ -989,7 +989,7 @@ static void UpdateClockPeriod(u8 taskId, u8 direction) u8 hours = gTasks[taskId].tHours; switch (direction) { - case MOVE_BACKWARD: + case CLOCK_MOVE_BACKWARD: switch (hours) { case 11: @@ -1000,7 +1000,7 @@ static void UpdateClockPeriod(u8 taskId, u8 direction) break; } break; - case MOVE_FORWARD: + case CLOCK_MOVE_FORWARD: switch (hours) { case 0: diff --git a/src/wild_encounter.c b/src/wild_encounter.c index d37613c83..b1d40097b 100644 --- a/src/wild_encounter.c +++ b/src/wild_encounter.c @@ -783,11 +783,6 @@ bool8 DoesCurrentMapHaveFishingMons(void) return TRUE; } -u32 CalculateChainFishingShinyRolls(void) -{ - return (2 * min(gChainFishingDexNavStreak, FISHING_CHAIN_SHINY_STREAK_MAX)); -} - static void UpdateChainFishingStreak() { if (!I_FISHING_CHAIN) From 001067adf39d43d369c93821374eb6343da07a8d Mon Sep 17 00:00:00 2001 From: cawtds <38510667+cawtds@users.noreply.github.com> Date: Fri, 14 Nov 2025 16:55:02 +0100 Subject: [PATCH 2/6] test framework compilable --- asm/macros/event.inc | 14 +- src/script_pokemon_util.c | 51 +- test/battle/ability/anticipation.c | 32 +- test/battle/ability/aura_break.c | 115 +++- test/battle/ability/battery.c | 50 +- test/battle/ability/beads_of_ruin.c | 116 +++- test/battle/ability/bulletproof.c | 18 +- test/battle/ability/color_change.c | 20 + test/battle/ability/contrary.c | 27 + test/battle/ability/cursed_body.c | 75 ++- test/battle/ability/emergency_exit.c | 101 +++ test/battle/ability/flower_gift.c | 19 + test/battle/ability/flower_veil.c | 4 +- test/battle/ability/forecast.c | 19 + test/battle/ability/hunger_switch.c | 1 - test/battle/ability/illusion.c | 2 +- test/battle/ability/immunity.c | 16 + test/battle/ability/intimidate.c | 36 +- test/battle/ability/liquid_ooze.c | 31 + test/battle/ability/magician.c | 28 + test/battle/ability/mimicry.c | 2 +- test/battle/ability/oblivious.c | 29 +- test/battle/ability/overcoat.c | 25 +- test/battle/ability/parental_bond.c | 9 +- test/battle/ability/power_construct.c | 53 ++ test/battle/ability/protean.c | 16 + test/battle/ability/protosynthesis.c | 19 + test/battle/ability/receiver.c | 59 ++ test/battle/ability/sand_force.c | 4 +- test/battle/ability/sand_rush.c | 4 +- test/battle/ability/sheer_force.c | 9 +- test/battle/ability/shield_dust.c | 28 + test/battle/ability/shields_down.c | 55 +- test/battle/ability/soundproof.c | 18 +- test/battle/ability/steadfast.c | 52 ++ test/battle/ability/supersweet_syrup.c | 10 + test/battle/ability/sword_of_ruin.c | 115 ++++ test/battle/ability/tangling_hair.c | 28 +- test/battle/ability/teraform_zero.c | 2 +- test/battle/ability/toxic_debris.c | 20 + test/battle/ability/unburden.c | 2 +- test/battle/ability/zero_to_hero.c | 4 +- test/battle/ai/ai_check_viability.c | 19 + test/battle/ai/ai_doubles.c | 32 +- test/battle/ai/ai_flag_predict_switch.c | 2 +- test/battle/ai/ai_multi.c | 127 ++++ test/battle/ai/ai_switching.c | 283 +++++++++ test/battle/ai/ai_trytofaint.c | 14 + test/battle/badge_boost.c | 166 +++++ test/battle/damage_formula.c | 125 +++- test/battle/end_turn_effects.c | 89 ++- test/battle/form_change/faint.c | 21 +- test/battle/form_change/mega_evolution.c | 14 +- test/battle/form_change/ultra_burst.c | 6 +- test/battle/gimmick/dynamax.c | 6 +- test/battle/gimmick/terastal.c | 12 +- test/battle/gimmick/zmove.c | 2 +- test/battle/hazards.c | 133 ++++ test/battle/hold_effect/big_root.c | 8 +- test/battle/hold_effect/booster_energy.c | 1 + test/battle/hold_effect/destiny_knot.c | 66 ++ test/battle/hold_effect/eject_pack.c | 23 + test/battle/hold_effect/gems.c | 34 +- test/battle/hold_effect/kee_berry.c | 16 + test/battle/hold_effect/maranga_berry.c | 16 + test/battle/hold_effect/restore_hp.c | 17 - test/battle/hold_effect/seeds.c | 8 +- test/battle/hold_effect/sticky_barb.c | 51 ++ test/battle/hold_effect/type_power.c | 24 + test/battle/hold_effect/weakness_berry.c | 126 ++++ test/battle/item_effect/poke_flute.c | 43 ++ test/battle/move.c | 44 ++ test/battle/move_effect/acrobatics.c | 1 - test/battle/move_effect/belly_drum.c | 4 +- test/battle/move_effect/destiny_bond.c | 8 +- test/battle/move_effect/dragon_darts.c | 19 +- test/battle/move_effect/echoed_voice.c | 170 ++++- test/battle/move_effect/endure.c | 23 +- test/battle/move_effect/fickle_beam.c | 7 +- test/battle/move_effect/fling.c | 38 ++ test/battle/move_effect/focus_energy.c | 29 +- test/battle/move_effect/future_sight.c | 28 +- test/battle/move_effect/grudge.c | 49 ++ test/battle/move_effect/hidden_power.c | 3 +- test/battle/move_effect/hit_escape.c | 6 +- test/battle/move_effect/instruct.c | 1 + test/battle/move_effect/knock_off.c | 27 + test/battle/move_effect/last_resort.c | 10 +- test/battle/move_effect/magic_room.c | 39 ++ test/battle/move_effect/misty_terrain.c | 13 + test/battle/move_effect/multi_hit.c | 6 +- test/battle/move_effect/nature_power.c | 25 +- test/battle/move_effect/powder.c | 6 +- test/battle/move_effect/psychic_terrain.c | 32 + test/battle/move_effect/purify.c | 40 ++ test/battle/move_effect/rest.c | 117 ++++ test/battle/move_effect/revival_blessing.c | 37 +- test/battle/move_effect/simple_beam.c | 3 +- test/battle/move_effect/stomping_tantrum.c | 25 + test/battle/move_effect/struggle.c | 75 +++ test/battle/move_effect/tera_blast.c | 2 +- test/battle/move_effect/toxic.c | 12 +- test/battle/move_effect/worry_seed.c | 3 +- test/battle/move_effect_secondary/dire_claw.c | 3 +- test/battle/move_effect_secondary/paralysis.c | 16 +- test/battle/move_effect_secondary/recharge.c | 52 ++ .../battle/move_effect_secondary/steal_item.c | 22 +- .../battle/move_effect_secondary/tri_attack.c | 3 +- test/battle/move_flags/powder.c | 15 +- test/battle/sleep_clause.c | 1 + test/battle/status1/paralysis.c | 19 +- test/battle/status1/sleep.c | 18 +- test/battle/switch_in_abilities.c | 121 ++++ test/battle/test_runner_features.c | 55 ++ test/battle/trainer_control.c | 3 + test/battle/weather/sandstorm.c | 4 +- test/daycare.c | 5 +- test/pokemon.c | 36 +- test/save.c | 35 ++ test/species.c | 2 +- test/test_runner.c | 188 +++++- test/test_runner_battle.c | 591 +++++++++++++----- 122 files changed, 4488 insertions(+), 425 deletions(-) create mode 100644 test/battle/ai/ai_multi.c create mode 100644 test/battle/badge_boost.c create mode 100644 test/battle/hold_effect/destiny_knot.c create mode 100644 test/battle/hold_effect/sticky_barb.c create mode 100644 test/battle/hold_effect/weakness_berry.c create mode 100644 test/battle/item_effect/poke_flute.c create mode 100644 test/battle/move_effect/struggle.c create mode 100644 test/battle/move_effect_secondary/recharge.c create mode 100644 test/save.c diff --git a/asm/macros/event.inc b/asm/macros/event.inc index a2cba00b0..bffca6b25 100644 --- a/asm/macros/event.inc +++ b/asm/macros/event.inc @@ -988,10 +988,10 @@ @ Gives the player a Pokémon of the specified species and level, and allows to customize extra parameters. @ VAR_RESULT will be set to MON_GIVEN_TO_PARTY, MON_GIVEN_TO_PC, or MON_CANT_GIVE depending on the outcome. - .macro givemon species:req, level:req, item, ball, nature, abilityNum, gender, hpEv, atkEv, defEv, speedEv, spAtkEv, spDefEv, hpIv, atkIv, defIv, speedIv, spAtkIv, spDefIv, move1, move2, move3, move4, isShiny, gmaxFactor, teraType, dmaxLevel + .macro givemon species:req, level:req, item, ball, nature, abilityNum, gender, hpEv, atkEv, defEv, speedEv, spAtkEv, spDefEv, hpIv, atkIv, defIv, speedIv, spAtkIv, spDefIv, move1, move2, move3, move4, shinyMode, gmaxFactor, teraType, dmaxLevel callnative ScrCmd_createmon, requests_effects=1 .byte 0 - .byte 6 @ assign to first empty slot + .byte PARTY_SIZE @ assign to first empty slot .set givemon_flags, 0 .2byte \species .2byte \level @@ -1016,7 +1016,7 @@ .ifnb \move2; .set givemon_flags, givemon_flags | (1 << 18); .endif .ifnb \move3; .set givemon_flags, givemon_flags | (1 << 19); .endif .ifnb \move4; .set givemon_flags, givemon_flags | (1 << 20); .endif - .ifnb \isShiny; .set givemon_flags, givemon_flags | (1 << 21); .endif + .ifnb \shinyMode; .set givemon_flags, givemon_flags | (1 << 21); .endif .ifnb \gmaxFactor; .set givemon_flags, givemon_flags | (1 << 22); .endif .ifnb \teraType; .set givemon_flags, givemon_flags | (1 << 23); .endif .ifnb \dmaxLevel; .set givemon_flags, givemon_flags | (1 << 24); .endif @@ -1042,7 +1042,7 @@ .ifnb \move2; .2byte \move2; .endif .ifnb \move3; .2byte \move3; .endif .ifnb \move4; .2byte \move4; .endif - .ifnb \isShiny; .2byte \isShiny; .endif + .ifnb \shinyMode; .2byte \shinyMode; .endif .ifnb \gmaxFactor; .2byte \gmaxFactor; .endif .ifnb \teraType; .2byte \teraType; .endif .ifnb \dmaxLevel; .2byte \dmaxLevel; .endif @@ -1050,7 +1050,7 @@ @ creates a mon for a given party and slot @ otherwise - .macro createmon side:req, slot:req, species:req, level:req, item, ball, nature, abilityNum, gender, hpEv, atkEv, defEv, speedEv, spAtkEv, spDefEv, hpIv, atkIv, defIv, speedIv, spAtkIv, spDefIv, move1, move2, move3, move4, isShiny, gmaxFactor, teraType, dmaxLevel + .macro createmon side:req, slot:req, species:req, level:req, item, ball, nature, abilityNum, gender, hpEv, atkEv, defEv, speedEv, spAtkEv, spDefEv, hpIv, atkIv, defIv, speedIv, spAtkIv, spDefIv, move1, move2, move3, move4, shinyMode, gmaxFactor, teraType, dmaxLevel callnative ScrCmd_createmon, requests_effects=1 .byte \side @ 0 - player, 1 - opponent .byte \slot @ 0-5 @@ -1078,7 +1078,7 @@ .ifnb \move2; .set givemon_flags, givemon_flags | (1 << 18); .endif .ifnb \move3; .set givemon_flags, givemon_flags | (1 << 19); .endif .ifnb \move4; .set givemon_flags, givemon_flags | (1 << 20); .endif - .ifnb \isShiny; .set givemon_flags, givemon_flags | (1 << 21); .endif + .ifnb \shinyMode; .set givemon_flags, givemon_flags | (1 << 21); .endif .ifnb \gmaxFactor; .set givemon_flags, givemon_flags | (1 << 22); .endif .ifnb \teraType; .set givemon_flags, givemon_flags | (1 << 23); .endif .ifnb \dmaxLevel; .set givemon_flags, givemon_flags | (1 << 24); .endif @@ -1104,7 +1104,7 @@ .ifnb \move2; .2byte \move2; .endif .ifnb \move3; .2byte \move3; .endif .ifnb \move4; .2byte \move4; .endif - .ifnb \isShiny; .2byte \isShiny; .endif + .ifnb \shinyMode; .2byte \shinyMode; .endif .ifnb \gmaxFactor; .2byte \gmaxFactor; .endif .ifnb \teraType; .2byte \teraType; .endif .ifnb \dmaxLevel; .2byte \dmaxLevel; .endif diff --git a/src/script_pokemon_util.c b/src/script_pokemon_util.c index af7fb8048..1c0f9c9b7 100644 --- a/src/script_pokemon_util.c +++ b/src/script_pokemon_util.c @@ -149,14 +149,15 @@ void SetTeraType(struct ScriptContext *ctx) * if side/slot are assigned, it will create the mon at the assigned party location * if slot == PARTY_SIZE, it will give the mon to first available party or storage slot */ -static u32 ScriptGiveMonParameterized(u8 side, u8 slot, u16 species, u8 level, u16 item, enum PokeBall ball, u8 nature, u8 abilityNum, u8 gender, u8 *evs, u8 *ivs, u16 *moves, bool8 isShiny, bool8 gmaxFactor, u8 teraType, u8 dmaxLevel) +static u32 ScriptGiveMonParameterized(u8 side, u8 slot, u16 species, u8 level, u16 item, enum PokeBall ball, u8 nature, u8 abilityNum, u8 gender, u8 *evs, u8 *ivs, u16 *moves, enum ShinyMode shinyMode, bool8 gmaxFactor, enum Type teraType, u8 dmaxLevel) { - u16 nationalDexNum; + enum NationalDexOrder nationalDexNum; int sentToPc; struct Pokemon mon; u32 i; u8 genderRatio = gSpeciesInfo[species].genderRatio; u16 targetSpecies; + bool32 isShiny; // check whether to use a specific nature or a random one if (nature >= NUM_NATURES) @@ -177,10 +178,13 @@ static u32 ScriptGiveMonParameterized(u8 side, u8 slot, u16 species, u8 level, u CreateMonWithNature(&mon, species, level, 32, nature); // shininess - if (P_FLAG_FORCE_SHINY != 0 && FlagGet(P_FLAG_FORCE_SHINY)) + if (shinyMode == SHINY_MODE_ALWAYS || (P_FLAG_FORCE_SHINY != 0 && FlagGet(P_FLAG_FORCE_SHINY))) isShiny = TRUE; - else if (P_FLAG_FORCE_NO_SHINY != 0 && FlagGet(P_FLAG_FORCE_NO_SHINY)) + else if (shinyMode == SHINY_MODE_NEVER || (P_FLAG_FORCE_NO_SHINY != 0 && FlagGet(P_FLAG_FORCE_NO_SHINY))) isShiny = FALSE; + else + isShiny = GetMonData(&mon, MON_DATA_IS_SHINY); + SetMonData(&mon, MON_DATA_IS_SHINY, &isShiny); // gigantamax factor @@ -190,8 +194,8 @@ static u32 ScriptGiveMonParameterized(u8 side, u8 slot, u16 species, u8 level, u SetMonData(&mon, MON_DATA_DYNAMAX_LEVEL, &dmaxLevel); // tera type - if (teraType >= NUMBER_OF_MON_TYPES) - teraType = TYPE_NONE; + if (teraType == TYPE_NONE || teraType == TYPE_MYSTERY || teraType >= NUMBER_OF_MON_TYPES) + teraType = GetTeraTypeFromPersonality(&mon); SetMonData(&mon, MON_DATA_TERA_TYPE, &teraType); // EV and IV @@ -331,8 +335,8 @@ void ScrCmd_createmon(struct ScriptContext *ctx) // Perfect IV calculation u32 i; - u8 availableIVs[NUM_STATS]; - u8 selectedIvs[NUM_STATS]; + enum Stat availableIVs[NUM_STATS]; + enum Stat selectedIvs[NUM_STATS]; if (gSpeciesInfo[species].perfectIVCount != 0) { // Initialize a list of IV indices. @@ -356,23 +360,24 @@ void ScrCmd_createmon(struct ScriptContext *ctx) case STAT_SPEED: speedIv = MAX_PER_STAT_IVS; break; case STAT_SPATK: spAtkIv = MAX_PER_STAT_IVS; break; case STAT_SPDEF: spDefIv = MAX_PER_STAT_IVS; break; + default: break; } } } - hpIv = PARSE_FLAG(11, hpIv); - atkIv = PARSE_FLAG(12, atkIv); - defIv = PARSE_FLAG(13, defIv); - speedIv = PARSE_FLAG(14, speedIv); - spAtkIv = PARSE_FLAG(15, spAtkIv); - spDefIv = PARSE_FLAG(16, spDefIv); - u16 move1 = PARSE_FLAG(17, MOVE_NONE); - u16 move2 = PARSE_FLAG(18, MOVE_NONE); - u16 move3 = PARSE_FLAG(19, MOVE_NONE); - u16 move4 = PARSE_FLAG(20, MOVE_NONE); - bool8 isShiny = PARSE_FLAG(21, FALSE); - bool8 gmaxFactor = PARSE_FLAG(22, FALSE); - u8 teraType = PARSE_FLAG(23, NUMBER_OF_MON_TYPES); - u8 dmaxLevel = PARSE_FLAG(24, 0); + hpIv = PARSE_FLAG(11, hpIv); + atkIv = PARSE_FLAG(12, atkIv); + defIv = PARSE_FLAG(13, defIv); + speedIv = PARSE_FLAG(14, speedIv); + spAtkIv = PARSE_FLAG(15, spAtkIv); + spDefIv = PARSE_FLAG(16, spDefIv); + u16 move1 = PARSE_FLAG(17, MOVE_NONE); + u16 move2 = PARSE_FLAG(18, MOVE_NONE); + u16 move3 = PARSE_FLAG(19, MOVE_NONE); + u16 move4 = PARSE_FLAG(20, MOVE_NONE); + enum ShinyMode shinyMode = PARSE_FLAG(21, SHINY_MODE_RANDOM); + bool8 gmaxFactor = PARSE_FLAG(22, FALSE); + enum Type teraType = PARSE_FLAG(23, NUMBER_OF_MON_TYPES); + u8 dmaxLevel = PARSE_FLAG(24, 0); u8 evs[NUM_STATS] = {hpEv, atkEv, defEv, speedEv, spAtkEv, spDefEv}; u8 ivs[NUM_STATS] = {hpIv, atkIv, defIv, speedIv, spAtkIv, spDefIv}; @@ -383,7 +388,7 @@ void ScrCmd_createmon(struct ScriptContext *ctx) else Script_RequestEffects(SCREFF_V1); - gSpecialVar_Result = ScriptGiveMonParameterized(side, slot, species, level, item, ball, nature, abilityNum, gender, evs, ivs, moves, isShiny, gmaxFactor, teraType, dmaxLevel); + gSpecialVar_Result = ScriptGiveMonParameterized(side, slot, species, level, item, ball, nature, abilityNum, gender, evs, ivs, moves, shinyMode, gmaxFactor, teraType, dmaxLevel); } #undef PARSE_FLAG diff --git a/test/battle/ability/anticipation.c b/test/battle/ability/anticipation.c index 223512710..ee5b602a1 100644 --- a/test/battle/ability/anticipation.c +++ b/test/battle/ability/anticipation.c @@ -16,6 +16,18 @@ SINGLE_BATTLE_TEST("Anticipation causes notifies if an opponent has a super-effe } } +SINGLE_BATTLE_TEST("Anticipation does not trigger even when a move is super effective on only 1 type") +{ + GIVEN { + PLAYER(SPECIES_WHISCASH) { Ability(ABILITY_ANTICIPATION); } + OPPONENT(SPECIES_PIKACHU) { Moves(MOVE_CELEBRATE, MOVE_THUNDERBOLT); } + } WHEN { + TURN { } + } SCENE { + NOT ABILITY_POPUP(player, ABILITY_ANTICIPATION); + } +} + SINGLE_BATTLE_TEST("Anticipation causes notifies if an opponent has a One-hit KO move") { GIVEN { @@ -59,28 +71,21 @@ SINGLE_BATTLE_TEST("Anticipation doesn't consider Normalize into their effective SINGLE_BATTLE_TEST("Anticipation doesn't consider Scrappy into their effectiveness (Gen5+)") { - KNOWN_FAILING; GIVEN { ASSUME(GetMoveType(MOVE_CLOSE_COMBAT) == TYPE_FIGHTING); - ASSUME(GetSpeciesType(SPECIES_EEVEE, 0) == TYPE_NORMAL); - ASSUME(GetSpeciesType(SPECIES_EEVEE, 1) == TYPE_NORMAL); - PLAYER(SPECIES_EEVEE) { Ability(ABILITY_ANTICIPATION); } - OPPONENT(SPECIES_KANGASKHAN) { Ability(ABILITY_SCRAPPY); Moves(MOVE_CLOSE_COMBAT, MOVE_TRICK_OR_TREAT, MOVE_SKILL_SWAP, MOVE_CELEBRATE); } + ASSUME(GetSpeciesType(SPECIES_DOUBLADE, 0) == TYPE_STEEL); + ASSUME(GetSpeciesType(SPECIES_DOUBLADE, 1) == TYPE_GHOST); + PLAYER(SPECIES_DOUBLADE) { Ability(ABILITY_ANTICIPATION); } + OPPONENT(SPECIES_KANGASKHAN) { Ability(ABILITY_SCRAPPY); Moves(MOVE_CLOSE_COMBAT, MOVE_CELEBRATE); } } WHEN { - TURN { MOVE(opponent, MOVE_TRICK_OR_TREAT); MOVE(player, MOVE_SKILL_SWAP); } - TURN { MOVE(opponent, MOVE_SKILL_SWAP); } + TURN { } } SCENE { - ABILITY_POPUP(player, ABILITY_ANTICIPATION); - ANIMATION(ANIM_TYPE_MOVE, MOVE_TRICK_OR_TREAT, opponent); - ANIMATION(ANIM_TYPE_MOVE, MOVE_SKILL_SWAP, player); - ANIMATION(ANIM_TYPE_MOVE, MOVE_SKILL_SWAP, opponent); NOT ABILITY_POPUP(player, ABILITY_ANTICIPATION); } } SINGLE_BATTLE_TEST("Anticipation doesn't consider Gravity into their effectiveness (Gen5+)") { - KNOWN_FAILING; GIVEN { PLAYER(SPECIES_SKARMORY); OPPONENT(SPECIES_EEVEE) { Ability(ABILITY_ANTICIPATION); Moves(MOVE_EARTHQUAKE, MOVE_GRAVITY, MOVE_SCRATCH, MOVE_POUND); } @@ -95,7 +100,8 @@ SINGLE_BATTLE_TEST("Anticipation doesn't consider Gravity into their effectivene SINGLE_BATTLE_TEST("Anticipation counts Counter, Metal Burst or Mirror Coat as attacking moves of their types (Gen5+)") { - u32 move, species, typeAtk, typeDef; + u32 move, species; + enum Type typeAtk, typeDef; PARAMETRIZE { move = MOVE_COUNTER; species = SPECIES_RATICATE; typeAtk = TYPE_FIGHTING; typeDef = TYPE_NORMAL; } PARAMETRIZE { move = MOVE_METAL_BURST; species = SPECIES_ROGGENROLA; typeAtk = TYPE_STEEL; typeDef = TYPE_ROCK; } PARAMETRIZE { move = MOVE_MIRROR_COAT; species = SPECIES_NIDORINO; typeAtk = TYPE_PSYCHIC; typeDef = TYPE_POISON; } diff --git a/test/battle/ability/aura_break.c b/test/battle/ability/aura_break.c index 93b21421e..389ab327b 100644 --- a/test/battle/ability/aura_break.c +++ b/test/battle/ability/aura_break.c @@ -1,6 +1,115 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("Aura Break inverts Fairy Aura's effect"); -TO_DO_BATTLE_TEST("Aura Break inverts Dark Aura's effect"); -TO_DO_BATTLE_TEST("Aura Break ignores Mold Breaker abilities"); +DOUBLE_BATTLE_TEST("Aura Break inverts Fairy Aura's effect") +{ + s16 damage[3]; + + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_XERNEAS) { Ability(ABILITY_FAIRY_AURA); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_ZYGARDE_50) { Ability(ABILITY_AURA_BREAK); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_PLAY_ROUGH, target:opponentLeft); } + TURN { MOVE(playerLeft, MOVE_PLAY_ROUGH, target:opponentLeft); SWITCH(playerRight, 2); } + TURN { MOVE(playerLeft, MOVE_PLAY_ROUGH, target:opponentLeft); SWITCH(opponentRight, 2); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[0]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[1]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[2]); + + } THEN { + EXPECT_MUL_EQ(damage[0], UQ_4_12(1.33), damage[1]); + EXPECT_MUL_EQ(damage[0], UQ_4_12(0.75), damage[2]); + } +} + +DOUBLE_BATTLE_TEST("Aura Break inverts Dark Aura's effect") +{ + s16 damage[3]; + + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_YVELTAL) { Ability(ABILITY_DARK_AURA); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_ZYGARDE_50) { Ability(ABILITY_AURA_BREAK); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_BITE, target:opponentLeft); } + TURN { MOVE(playerLeft, MOVE_BITE, target:opponentLeft); SWITCH(playerRight, 2); } + TURN { MOVE(playerLeft, MOVE_BITE, target:opponentLeft); SWITCH(opponentRight, 2); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[0]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[1]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[2]); + + } THEN { + EXPECT_MUL_EQ(damage[0], UQ_4_12(1.33), damage[1]); + EXPECT_MUL_EQ(damage[0], UQ_4_12(0.75), damage[2]); + } +} + +DOUBLE_BATTLE_TEST("Aura Break ignores Mold Breaker abilities") +{ + s16 damage[6]; + u32 species = SPECIES_WOBBUFFET, ability = ABILITY_NONE; + + PARAMETRIZE { species = SPECIES_WOBBUFFET, ability = ABILITY_SHADOW_TAG; } + PARAMETRIZE { species = SPECIES_CRANIDOS, ability = ABILITY_MOLD_BREAKER; } + PARAMETRIZE { species = SPECIES_ZEKROM, ability = ABILITY_TERAVOLT; } + PARAMETRIZE { species = SPECIES_RESHIRAM, ability = ABILITY_TURBOBLAZE; } + + GIVEN { + PLAYER(species) { Ability(ability); Level(50); } + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_YVELTAL) { Ability(ABILITY_DARK_AURA); } + PLAYER(SPECIES_XERNEAS) { Ability(ABILITY_FAIRY_AURA); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_ZYGARDE_50) { Ability(ABILITY_AURA_BREAK); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_BITE, target: opponentLeft); } + TURN { MOVE(playerLeft, MOVE_PLAY_ROUGH, target: opponentLeft); } + TURN { MOVE(playerLeft, MOVE_BITE, target: opponentLeft); SWITCH(playerRight, 2); } + TURN { MOVE(playerLeft, MOVE_PLAY_ROUGH, target: opponentLeft); SWITCH(playerRight, 3); } + TURN { MOVE(playerLeft, MOVE_BITE, target: opponentLeft); SWITCH(playerRight, 2); SWITCH(opponentRight, 2); } + TURN { MOVE(playerLeft, MOVE_PLAY_ROUGH, target: opponentLeft); SWITCH(playerRight, 3); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[0]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[1]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[2]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[3]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[4]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[5]); + } THEN { + EXPECT_MUL_EQ(damage[0], UQ_4_12(1.33), damage[2]); + EXPECT_MUL_EQ(damage[0], UQ_4_12(0.75), damage[4]); + EXPECT_MUL_EQ(damage[1], UQ_4_12(1.33), damage[3]); + EXPECT_MUL_EQ(damage[1], UQ_4_12(0.75), damage[5]); + } +} diff --git a/test/battle/ability/battery.c b/test/battle/ability/battery.c index cecfa81d0..7ddc0b837 100644 --- a/test/battle/ability/battery.c +++ b/test/battle/ability/battery.c @@ -1,5 +1,51 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("Battery increases Sp. Attack damage of allies by ~30%"); // 5325/4096 -TO_DO_BATTLE_TEST("Battery does not increase its own Sp. Attack damage"); +DOUBLE_BATTLE_TEST("Battery increases Sp. Attack damage of allies by ~30%") +{ + s16 damage[2]; + + GIVEN { + PLAYER(SPECIES_CHARJABUG) { Speed(1); Ability(ABILITY_BATTERY); } + PLAYER(SPECIES_WOBBUFFET) { Speed(2); Moves(MOVE_SHOCK_WAVE); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(4); Moves(MOVE_CELEBRATE, MOVE_GASTRO_ACID); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(3); } + } WHEN { + TURN { MOVE(playerRight, MOVE_SHOCK_WAVE, target: opponentLeft); } + TURN { MOVE(opponentLeft, MOVE_GASTRO_ACID, target: playerLeft); MOVE(playerRight, MOVE_SHOCK_WAVE, target: opponentLeft); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SHOCK_WAVE, playerRight); + HP_BAR(opponentLeft, captureDamage: &damage[0]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_GASTRO_ACID, opponentLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SHOCK_WAVE, playerRight); + HP_BAR(opponentLeft, captureDamage: &damage[1]); + } THEN { + EXPECT_MUL_EQ(damage[1], UQ_4_12(1.3), damage[0]); + } + +} + +DOUBLE_BATTLE_TEST("Battery does not increase its own Sp. Attack damage") +{ + s16 damage[2]; + + GIVEN { + PLAYER(SPECIES_CHARJABUG) { Speed(1); Ability(ABILITY_BATTERY); } + PLAYER(SPECIES_WOBBUFFET) { Speed(2); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(4); Moves(MOVE_CELEBRATE, MOVE_GASTRO_ACID); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(3); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_SHOCK_WAVE, target: opponentLeft); } + TURN { MOVE(opponentLeft, MOVE_GASTRO_ACID, target: playerLeft); MOVE(playerLeft, MOVE_SHOCK_WAVE, target: opponentLeft); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SHOCK_WAVE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[0]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_GASTRO_ACID, opponentLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SHOCK_WAVE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[1]); + } THEN { + EXPECT_EQ(damage[0], damage[1]); + } +} diff --git a/test/battle/ability/beads_of_ruin.c b/test/battle/ability/beads_of_ruin.c index 37240d2d6..86172459a 100644 --- a/test/battle/ability/beads_of_ruin.c +++ b/test/battle/ability/beads_of_ruin.c @@ -4,6 +4,7 @@ ASSUMPTIONS { ASSUME(GetMoveCategory(MOVE_WATER_GUN) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_ROUND) == DAMAGE_CATEGORY_SPECIAL); ASSUME(GetMoveEffect(MOVE_ROLE_PLAY) == EFFECT_ROLE_PLAY); } @@ -74,4 +75,117 @@ SINGLE_BATTLE_TEST("Beads of Ruin's message displays correctly after all battler } } -TO_DO_BATTLE_TEST("Beads of Ruin reduce Defense if Wonder Room is active"); +DOUBLE_BATTLE_TEST("Beads of Ruin increases damage taken by physical moves in Wonder Room", s16 damage) +{ + bool32 useWonderRoom; + u32 move; + + PARAMETRIZE { useWonderRoom = FALSE; move = MOVE_SCRATCH; } + PARAMETRIZE { useWonderRoom = FALSE; move = MOVE_ROUND; } + PARAMETRIZE { useWonderRoom = TRUE; move = MOVE_SCRATCH; } + PARAMETRIZE { useWonderRoom = TRUE; move = MOVE_ROUND; } + + GIVEN { + ASSUME(GetMoveEffect(MOVE_WONDER_ROOM) == EFFECT_WONDER_ROOM); + ASSUME(GetMoveCategory(MOVE_SCRATCH) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveEffect(MOVE_ROUND) != EFFECT_PSYSHOCK); + PLAYER(SPECIES_CHI_YU) { Ability(ABILITY_BEADS_OF_RUIN); } + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + if (useWonderRoom) + TURN { MOVE(opponentLeft, MOVE_WONDER_ROOM); MOVE(playerRight, move, target: opponentLeft); } + else + TURN { MOVE(playerRight, move, target: opponentLeft); } + } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_BEADS_OF_RUIN); + MESSAGE("Chi-Yu's Beads of Ruin weakened the Sp. Def of all surrounding Pokémon!"); + ANIMATION(ANIM_TYPE_MOVE, move, playerRight); + HP_BAR(opponentLeft, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_GT(results[2].damage, results[0].damage); // In Wonder Room, physical move deals more damage + EXPECT_LT(results[3].damage, results[1].damage); // In Wonder Room, special move deals less damage + } +} + +SINGLE_BATTLE_TEST("Beads of Ruin doesn't activate when dragged out by Mold Breaker attacker") +{ + u32 ability; + + PARAMETRIZE { ability = ABILITY_MOLD_BREAKER; } + PARAMETRIZE { ability = ABILITY_SAND_RUSH; } + + GIVEN { + ASSUME(GetMoveEffect(MOVE_DRAGON_TAIL) == EFFECT_HIT_SWITCH_TARGET); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_CHI_YU) { Ability(ABILITY_BEADS_OF_RUIN); } + OPPONENT(SPECIES_EXCADRILL) { Ability(ability); } + } WHEN { + TURN { MOVE(opponent, MOVE_DRAGON_TAIL); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_TAIL, opponent); + if (ability == ABILITY_MOLD_BREAKER) + { + NONE_OF { + ABILITY_POPUP(player, ABILITY_BEADS_OF_RUIN); + MESSAGE("Chi-Yu's Beads of Ruin weakened the Sp. Def of all surrounding Pokémon!"); + } + } + else + { + ABILITY_POPUP(player, ABILITY_BEADS_OF_RUIN); + MESSAGE("Chi-Yu's Beads of Ruin weakened the Sp. Def of all surrounding Pokémon!"); + } + } +} + +DOUBLE_BATTLE_TEST("Beads of Ruin's Sp. Def reduction is not ignored by Mold Breaker", s16 damage) +{ + u32 ability; + + PARAMETRIZE { ability = ABILITY_MOLD_BREAKER; } + PARAMETRIZE { ability = ABILITY_SAND_RUSH; } + + GIVEN { + PLAYER(SPECIES_CHI_YU) { Ability(ABILITY_BEADS_OF_RUIN); } + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_EXCADRILL) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponentLeft, MOVE_ROUND, target: playerRight); } + } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_BEADS_OF_RUIN); + MESSAGE("Chi-Yu's Beads of Ruin weakened the Sp. Def of all surrounding Pokémon!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROUND, opponentLeft); + HP_BAR(playerRight, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + } +} + +DOUBLE_BATTLE_TEST("Beads of Ruin's Sp. Def reduction is ignored by Gastro Acid", s16 damage) +{ + u32 move; + + PARAMETRIZE { move = MOVE_GASTRO_ACID; } + PARAMETRIZE { move = MOVE_CELEBRATE; } + + GIVEN { + ASSUME(GetMoveEffect(MOVE_GASTRO_ACID) == EFFECT_GASTRO_ACID); + PLAYER(SPECIES_CHI_YU) { Ability(ABILITY_BEADS_OF_RUIN); } + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponentRight, move, target: playerLeft); MOVE(opponentLeft, MOVE_ROUND, target: playerRight); } + } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_BEADS_OF_RUIN); + MESSAGE("Chi-Yu's Beads of Ruin weakened the Sp. Def of all surrounding Pokémon!"); + ANIMATION(ANIM_TYPE_MOVE, move, opponentRight); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROUND, opponentLeft); + HP_BAR(playerRight, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_LT(results[0].damage, results[1].damage); + } +} diff --git a/test/battle/ability/bulletproof.c b/test/battle/ability/bulletproof.c index 733eb63a1..37d59b468 100644 --- a/test/battle/ability/bulletproof.c +++ b/test/battle/ability/bulletproof.c @@ -1,4 +1,20 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("Bulletproof makes ballistic moves fail against the ability user"); +SINGLE_BATTLE_TEST("Bulletproof makes ballistic moves fail against the ability user") +{ + GIVEN { + ASSUME(IsBallisticMove(MOVE_ELECTRO_BALL)); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_CHESPIN) { Ability(ABILITY_BULLETPROOF); } + } WHEN { + TURN { MOVE(player, MOVE_ELECTRO_BALL); } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_BULLETPROOF); + MESSAGE("The opposing Chespin's Bulletproof blocks Electro Ball!"); + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ELECTRO_BALL, player); + HP_BAR(opponent); + } + } +} diff --git a/test/battle/ability/color_change.c b/test/battle/ability/color_change.c index 4c0792650..49eaa3e91 100644 --- a/test/battle/ability/color_change.c +++ b/test/battle/ability/color_change.c @@ -154,6 +154,26 @@ SINGLE_BATTLE_TEST("Color Change changes the type to Normal when a Pokemon is hi } } +SINGLE_BATTLE_TEST("Color Change does not change the type to Normal when a Pokemon is hit by Struggle") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_KECLEON) { Ability(ABILITY_COLOR_CHANGE); } + } WHEN { + TURN { MOVE(player, MOVE_SOAK); } + TURN { MOVE(player, MOVE_STRUGGLE); } + TURN { } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SOAK, player); + MESSAGE("The opposing Kecleon transformed into the Water type!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_STRUGGLE, player); + NONE_OF { + ABILITY_POPUP(opponent, ABILITY_COLOR_CHANGE); + MESSAGE("The opposing Kecleon's Color Change made it the Normal type!"); + } + } +} + SINGLE_BATTLE_TEST("Color Change does not activate if move is boosted by Sheer Force") { GIVEN { diff --git a/test/battle/ability/contrary.c b/test/battle/ability/contrary.c index 0c6eba7d1..ef5b4c6c7 100644 --- a/test/battle/ability/contrary.c +++ b/test/battle/ability/contrary.c @@ -242,4 +242,31 @@ SINGLE_BATTLE_TEST("Sticky Web raises Speed by 1 for Contrary mon on switch-in") } } +AI_SINGLE_BATTLE_TEST("AI sees Contrary-effected moves correctly in MoveEffectInPlus instead of as a neutral effect") +{ + GIVEN{ + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_OMNISCIENT); + PLAYER(SPECIES_HERACROSS){ + Level(44); + HP(1); + Speed(5); + Nature(NATURE_ADAMANT); + Item(ITEM_LOADED_DICE); + Moves(MOVE_PIN_MISSILE); + } + OPPONENT(SPECIES_SERPERIOR){ + Level(44); + Speed(10); + Nature(NATURE_TIMID); + Ability(ABILITY_CONTRARY); + Moves(MOVE_DRAGON_PULSE, MOVE_SPIN_OUT, MOVE_HIDDEN_POWER, MOVE_GLARE); + } + } WHEN { + TURN{ + MOVE(player, MOVE_PIN_MISSILE); + EXPECT_MOVE(opponent, MOVE_SPIN_OUT); // previously all 107, now sees speed can rise w/ Contrary + } + } +} + TO_DO_BATTLE_TEST("Contrary does not invert stat changes that have been Baton-passed") diff --git a/test/battle/ability/cursed_body.c b/test/battle/ability/cursed_body.c index 25dbdc4b5..b3bc886a3 100644 --- a/test/battle/ability/cursed_body.c +++ b/test/battle/ability/cursed_body.c @@ -16,10 +16,77 @@ SINGLE_BATTLE_TEST("Cursed Body triggers 30% of the time") } } -TO_DO_BATTLE_TEST("Cursed Body cannot disable Struggle") -TO_DO_BATTLE_TEST("Cursed Body can trigger if the attacker is behind a Substitute") -TO_DO_BATTLE_TEST("Cursed Body cannot trigger if the target is behind a Substitute") -TO_DO_BATTLE_TEST("Cursed Body does not stop a multistrike move mid-execution") +SINGLE_BATTLE_TEST("Cursed Body cannot disable Struggle") +{ + GIVEN { + ASSUME(GetItemHoldEffect(ITEM_CHOICE_SCARF) == HOLD_EFFECT_CHOICE_SCARF); + ASSUME(GetMoveEffect(MOVE_TAUNT) == EFFECT_TAUNT); + ASSUME(GetMoveCategory(MOVE_CELEBRATE) == DAMAGE_CATEGORY_STATUS); + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_CHOICE_SCARF); Moves(MOVE_CELEBRATE); } + OPPONENT(SPECIES_FRILLISH) { Ability(ABILITY_CURSED_BODY); } + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_TAUNT); } + TURN { FORCED_MOVE(player); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STRUGGLE, player); + NONE_OF { + ABILITY_POPUP(opponent, ABILITY_CURSED_BODY); + MESSAGE("Wobbuffet's Struggle was disabled by the opposing Frillish's Cursed Body!"); + } + } +} + +SINGLE_BATTLE_TEST("Cursed Body can trigger if the attacker is behind a Substitute") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_SUBSTITUTE) == EFFECT_SUBSTITUTE); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_FRILLISH) { Ability(ABILITY_CURSED_BODY); } + } WHEN { + TURN { MOVE(player, MOVE_SUBSTITUTE); } + TURN { MOVE(player, MOVE_AQUA_JET); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_AQUA_JET, player); + ABILITY_POPUP(opponent, ABILITY_CURSED_BODY); + MESSAGE("Wobbuffet's Aqua Jet was disabled by the opposing Frillish's Cursed Body!"); + } +} + +SINGLE_BATTLE_TEST("Cursed Body cannot trigger if the target is behind a Substitute") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_SUBSTITUTE) == EFFECT_SUBSTITUTE); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_FRILLISH) { Ability(ABILITY_CURSED_BODY); } + } WHEN { + TURN { MOVE(opponent, MOVE_SUBSTITUTE); } + TURN { MOVE(player, MOVE_AQUA_JET); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_AQUA_JET, player); + NONE_OF { + ABILITY_POPUP(opponent, ABILITY_CURSED_BODY); + MESSAGE("Wobbuffet's Aqua Jet was disabled by the opposing Frillish's Cursed Body!"); + } + } +} + +SINGLE_BATTLE_TEST("Cursed Body does not stop a multistrike move mid-execution") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_ROCK_BLAST) == EFFECT_MULTI_HIT); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_FRILLISH) { Ability(ABILITY_CURSED_BODY); } + } WHEN { + TURN { MOVE(player, MOVE_ROCK_BLAST); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROCK_BLAST, player); + HP_BAR(opponent); + ABILITY_POPUP(opponent, ABILITY_CURSED_BODY); + MESSAGE("Wobbuffet's Rock Blast was disabled by the opposing Frillish's Cursed Body!"); + HP_BAR(opponent); + } +} + TO_DO_BATTLE_TEST("Cursed Body disables the move that called another move instead of the called move") TO_DO_BATTLE_TEST("Cursed Body disables damaging Z-Moves, but not the base move") // Rotom Powers can restore Z-Moves TO_DO_BATTLE_TEST("Cursed Body disables the base move of a status Z-Move") diff --git a/test/battle/ability/emergency_exit.c b/test/battle/ability/emergency_exit.c index 5027d929e..3592b91b0 100644 --- a/test/battle/ability/emergency_exit.c +++ b/test/battle/ability/emergency_exit.c @@ -81,6 +81,23 @@ SINGLE_BATTLE_TEST("Emergency Exit activates when taking residual damage and fal } } +SINGLE_BATTLE_TEST("Emergency Exit activates when healing from under 50% max-hp and taking residual damage to under 50% max-hp - Burn") +{ + // Might fail if users set healing higher than burn damage + GIVEN { + ASSUME(GetMoveEffect(MOVE_AQUA_RING) == EFFECT_AQUA_RING); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_GOLISOPOD) { Ability(ABILITY_EMERGENCY_EXIT); MaxHP(263); HP(130); Status1(STATUS1_BURN); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_AQUA_RING); SEND_OUT(opponent, 1); } + } SCENE { + HP_BAR(opponent); + HP_BAR(opponent); + ABILITY_POPUP(opponent, ABILITY_EMERGENCY_EXIT); + } +} + SINGLE_BATTLE_TEST("Emergency Exit activates when taking residual damage and falling under 50% max-hp - Weather") { GIVEN { @@ -95,6 +112,24 @@ SINGLE_BATTLE_TEST("Emergency Exit activates when taking residual damage and fal } } +SINGLE_BATTLE_TEST("Emergency Exit activates when healing from under 50% max-hp and taking residual damage to under 50% max-hp - Sticky Barb") +{ + // Might fail if users set healing higher than sticky barb damage + GIVEN { + ASSUME(GetMoveEffect(MOVE_AQUA_RING) == EFFECT_AQUA_RING); + ASSUME(GetItemHoldEffect(ITEM_STICKY_BARB) == HOLD_EFFECT_STICKY_BARB); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_GOLISOPOD) { Ability(ABILITY_EMERGENCY_EXIT); MaxHP(263); HP(130); Item(ITEM_STICKY_BARB); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_AQUA_RING); SEND_OUT(opponent, 1); } + } SCENE { + HP_BAR(opponent); + HP_BAR(opponent); + ABILITY_POPUP(opponent, ABILITY_EMERGENCY_EXIT); + } +} + SINGLE_BATTLE_TEST("Emergency Exit activates when taking residual damage and falling under 50% max-hp - Salt Cure") { GIVEN { @@ -108,3 +143,69 @@ SINGLE_BATTLE_TEST("Emergency Exit activates when taking residual damage and fal ABILITY_POPUP(opponent, ABILITY_EMERGENCY_EXIT); } } + +WILD_BATTLE_TEST("Emergency Exit makes the pokemon flee during wild battle") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_GOLISOPOD) { Ability(ABILITY_EMERGENCY_EXIT); MaxHP(263); HP(262); }; + } WHEN { + TURN { MOVE(player, MOVE_SUPER_FANG);} + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SUPER_FANG, player); + HP_BAR(opponent); + ABILITY_POPUP(opponent, ABILITY_EMERGENCY_EXIT); + } THEN { + EXPECT_EQ(gBattleOutcome, B_OUTCOME_MON_TELEPORTED); + } +} + +WILD_BATTLE_TEST("Emergency Exit activates when taking residual damage and falling under 50% max-hp (wild battle)") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_GOLISOPOD) { Ability(ABILITY_EMERGENCY_EXIT); MaxHP(263); HP(134); Status1(STATUS1_BURN); }; + } WHEN { + TURN { } + } SCENE { + HP_BAR(opponent); + ABILITY_POPUP(opponent, ABILITY_EMERGENCY_EXIT); + } THEN { + EXPECT_EQ(gBattleOutcome, B_OUTCOME_MON_TELEPORTED); + } +} + +WILD_BATTLE_TEST("Emergency Exit makes the player ran during wild battle") +{ + GIVEN { + PLAYER(SPECIES_GOLISOPOD) { Ability(ABILITY_EMERGENCY_EXIT); MaxHP(263); HP(262); }; + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SUPER_FANG);} + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SUPER_FANG, opponent); + HP_BAR(player); + ABILITY_POPUP(player, ABILITY_EMERGENCY_EXIT); + } THEN { + EXPECT_EQ(gBattleOutcome, B_OUTCOME_PLAYER_TELEPORTED); + } +} + +WILD_BATTLE_TEST("Emergency Exit activates when taking residual damage and falling under 50% max-hp (wild battle player side)") +{ + GIVEN { + PLAYER(SPECIES_GOLISOPOD) { Ability(ABILITY_EMERGENCY_EXIT); MaxHP(263); HP(134); }; + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SANDSTORM);} + } SCENE { + HP_BAR(player); + ABILITY_POPUP(player, ABILITY_EMERGENCY_EXIT); + } THEN { + EXPECT_EQ(gBattleOutcome, B_OUTCOME_PLAYER_TELEPORTED); + } +} diff --git a/test/battle/ability/flower_gift.c b/test/battle/ability/flower_gift.c index da6dbc16b..30cc7926e 100644 --- a/test/battle/ability/flower_gift.c +++ b/test/battle/ability/flower_gift.c @@ -200,4 +200,23 @@ SINGLE_BATTLE_TEST("Flower Gift transforms Cherrim back when it uses a move that } } +DOUBLE_BATTLE_TEST("Flower Gift reverts Cherrim back after Teraform Zero clears weather") +{ + GIVEN { + PLAYER(SPECIES_TERAPAGOS_TERASTAL); + PLAYER(SPECIES_CHERRIM) { Ability(ABILITY_FLOWER_GIFT); } + OPPONENT(SPECIES_GROUDON) { Ability(ABILITY_DROUGHT); } + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(playerLeft, MOVE_CELEBRATE, gimmick: GIMMICK_TERA); } + } SCENE { + ABILITY_POPUP(opponentLeft, ABILITY_DROUGHT); + ABILITY_POPUP(playerRight, ABILITY_FLOWER_GIFT); + ABILITY_POPUP(playerLeft, ABILITY_TERAFORM_ZERO); + ABILITY_POPUP(playerRight, ABILITY_FLOWER_GIFT); + } THEN { + EXPECT_EQ(playerRight->species, SPECIES_CHERRIM); + } +} + TO_DO_BATTLE_TEST("Flower Gift does not transform Cherrim back to normal when suppressed if Cherrim is Dynamaxed"); diff --git a/test/battle/ability/flower_veil.c b/test/battle/ability/flower_veil.c index cb72cd33a..78d15df1b 100644 --- a/test/battle/ability/flower_veil.c +++ b/test/battle/ability/flower_veil.c @@ -15,7 +15,7 @@ ASSUMPTIONS ASSUME(GetMoveNonVolatileStatus(MOVE_HYPNOSIS) == MOVE_EFFECT_SLEEP); } -DOUBLE_BATTLE_TEST("Flower Veil prevents Toxic bad poison on partner - right target") +DOUBLE_BATTLE_TEST("Flower Veil prevents status on allied Grass-types - right target") { u32 move; @@ -39,7 +39,7 @@ DOUBLE_BATTLE_TEST("Flower Veil prevents Toxic bad poison on partner - right tar } } -DOUBLE_BATTLE_TEST("Flower Veil prevents Toxic bad poison on partner - left target") +DOUBLE_BATTLE_TEST("Flower Veil prevents status on allied Grass-types - left target") { u32 move; diff --git a/test/battle/ability/forecast.c b/test/battle/ability/forecast.c index 764c5bd98..b6889620a 100644 --- a/test/battle/ability/forecast.c +++ b/test/battle/ability/forecast.c @@ -427,3 +427,22 @@ SINGLE_BATTLE_TEST("Forecast transforms Castform when Cloud Nine ability user le MESSAGE("Castform transformed!"); } } + +DOUBLE_BATTLE_TEST("Forecast reverts Castform back after Teraform Zero clears weather") +{ + GIVEN { + PLAYER(SPECIES_TERAPAGOS_TERASTAL); + PLAYER(SPECIES_CASTFORM) { Ability(ABILITY_FORECAST); } + OPPONENT(SPECIES_KYOGRE) { Ability(ABILITY_DRIZZLE); } + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(playerLeft, MOVE_CELEBRATE, gimmick: GIMMICK_TERA); } + } SCENE { + ABILITY_POPUP(opponentLeft, ABILITY_DRIZZLE); + ABILITY_POPUP(playerRight, ABILITY_FORECAST); + ABILITY_POPUP(playerLeft, ABILITY_TERAFORM_ZERO); + ABILITY_POPUP(playerRight, ABILITY_FORECAST); + } THEN { + EXPECT_EQ(playerRight->species, SPECIES_CASTFORM_NORMAL); + } +} diff --git a/test/battle/ability/hunger_switch.c b/test/battle/ability/hunger_switch.c index 1892de442..469cf02d3 100644 --- a/test/battle/ability/hunger_switch.c +++ b/test/battle/ability/hunger_switch.c @@ -53,7 +53,6 @@ SINGLE_BATTLE_TEST("Hunger Switch does not switch Morpeko's form when Terastalli SINGLE_BATTLE_TEST("Hunger Switch does not switch Morpeko's form after switching out while Terastallized") { - KNOWN_FAILING; // #7062 GIVEN { ASSUME(GetMoveEffect(MOVE_ROAR) == EFFECT_ROAR); PLAYER(SPECIES_MORPEKO) { Ability(ABILITY_HUNGER_SWITCH); TeraType(TYPE_NORMAL); } diff --git a/test/battle/ability/illusion.c b/test/battle/ability/illusion.c index 56fad1b62..26c8daabc 100644 --- a/test/battle/ability/illusion.c +++ b/test/battle/ability/illusion.c @@ -102,7 +102,7 @@ SINGLE_BATTLE_TEST("Illusion breaks if affected by Gastro Acid") SINGLE_BATTLE_TEST("Illusion breaks if user loses Illusion due to Worry Seed") { GIVEN { - ASSUME(GetMoveEffect(MOVE_WORRY_SEED) == EFFECT_WORRY_SEED); + ASSUME(GetMoveEffect(MOVE_WORRY_SEED) == EFFECT_OVERWRITE_ABILITY); PLAYER(SPECIES_ZOROARK); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/ability/immunity.c b/test/battle/ability/immunity.c index c02a37c69..9199638ad 100644 --- a/test/battle/ability/immunity.c +++ b/test/battle/ability/immunity.c @@ -63,3 +63,19 @@ SINGLE_BATTLE_TEST("Immunity doesn't prevent Pokémon from being poisoned by Tox NOT HP_BAR(player); } } + +SINGLE_BATTLE_TEST("Immunity cures existing poison on turn 0") +{ + GIVEN { + PLAYER(SPECIES_ZANGOOSE) { + Ability(ABILITY_IMMUNITY); + Status1(STATUS1_POISON); + } + OPPONENT(SPECIES_WOBBUFFET); + } SCENE { + ABILITY_POPUP(player, ABILITY_IMMUNITY); + TURN { MOVE(player, MOVE_SPLASH); } + } THEN { + EXPECT_EQ(player->status1, STATUS1_NONE); + } +} diff --git a/test/battle/ability/intimidate.c b/test/battle/ability/intimidate.c index bdd521d78..0606938d4 100644 --- a/test/battle/ability/intimidate.c +++ b/test/battle/ability/intimidate.c @@ -240,6 +240,7 @@ DOUBLE_BATTLE_TEST("Intimidate is not going to trigger if a mon switches out thr ANIMATION(ANIM_TYPE_MOVE, MOVE_HEALING_WISH, opponentRight); ANIMATION(ANIM_TYPE_MOVE, MOVE_U_TURN, playerLeft); HP_BAR(opponentLeft); + NOT ABILITY_POPUP(playerLeft, ABILITY_INTIMIDATE); MESSAGE("2 sent out Treecko!"); MESSAGE("2 sent out Torchic!"); NOT ABILITY_POPUP(playerLeft, ABILITY_INTIMIDATE); @@ -264,7 +265,7 @@ SINGLE_BATTLE_TEST("Intimidate activates when it's no longer effected by Neutral } } -SINGLE_BATTLE_TEST("Intimidate activates when it's no longer affected by Neutralizing Gas - switching moves") +DOUBLE_BATTLE_TEST("Intimidate activates when it's no longer affected by Neutralizing Gas - switching moves") { u32 move; PARAMETRIZE { move = MOVE_U_TURN; } @@ -276,19 +277,24 @@ SINGLE_BATTLE_TEST("Intimidate activates when it's no longer affected by Neutral ASSUME(GetMoveEffect(MOVE_BATON_PASS) == EFFECT_BATON_PASS); PLAYER(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); } PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_ARBOK) { Ability(ABILITY_INTIMIDATE); } + OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { MOVE(player, move); SEND_OUT(player, 1); } + TURN { + if (move == MOVE_U_TURN) + MOVE(playerLeft, move, target: opponentLeft); + else + MOVE(playerLeft, move); + SEND_OUT(playerLeft, 2); + } } SCENE { - ABILITY_POPUP(player, ABILITY_NEUTRALIZING_GAS); + ABILITY_POPUP(playerLeft, ABILITY_NEUTRALIZING_GAS); MESSAGE("Neutralizing gas filled the area!"); - ANIMATION(ANIM_TYPE_MOVE, move, player); + ANIMATION(ANIM_TYPE_MOVE, move, playerLeft); MESSAGE("The effects of the neutralizing gas wore off!"); - ABILITY_POPUP(opponent, ABILITY_INTIMIDATE); + ABILITY_POPUP(opponentLeft, ABILITY_INTIMIDATE); SEND_IN_MESSAGE("Wobbuffet"); - } THEN { - if (move == MOVE_HEALING_WISH) - EXPECT_EQ(player->hp, player->maxHP); } } @@ -330,23 +336,25 @@ SINGLE_BATTLE_TEST("Intimidate activates when it's no longer affected by Neutral } } -SINGLE_BATTLE_TEST("Intimidate activates when it's no longer affected by Neutralizing Gas - fainted") +DOUBLE_BATTLE_TEST("Intimidate activates when it's no longer affected by Neutralizing Gas - fainted") { GIVEN { ASSUME(GetMoveEffect(MOVE_FELL_STINGER) == EFFECT_FELL_STINGER); PLAYER(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); HP(1); } PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_ARBOK) { Ability(ABILITY_INTIMIDATE); } + OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { MOVE(opponent, MOVE_FELL_STINGER); SEND_OUT(player, 1); } + TURN { MOVE(opponentLeft, MOVE_FELL_STINGER, target: playerLeft); SEND_OUT(playerLeft, 2); } } SCENE { - ABILITY_POPUP(player, ABILITY_NEUTRALIZING_GAS); + ABILITY_POPUP(playerLeft, ABILITY_NEUTRALIZING_GAS); MESSAGE("Neutralizing gas filled the area!"); - ANIMATION(ANIM_TYPE_MOVE, MOVE_FELL_STINGER, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_FELL_STINGER, opponentLeft); MESSAGE("The effects of the neutralizing gas wore off!"); - ABILITY_POPUP(opponent, ABILITY_INTIMIDATE); + ABILITY_POPUP(opponentLeft, ABILITY_INTIMIDATE); MESSAGE("Weezing fainted!"); - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft); SEND_IN_MESSAGE("Wobbuffet"); } } diff --git a/test/battle/ability/liquid_ooze.c b/test/battle/ability/liquid_ooze.c index 3af8cc102..a9e5fb4b9 100644 --- a/test/battle/ability/liquid_ooze.c +++ b/test/battle/ability/liquid_ooze.c @@ -187,3 +187,34 @@ SINGLE_BATTLE_TEST("Liquid Ooze does not cause Dream Eater users to lose HP inst EXPECT_LT(damage, 0); // Negative damage = Heal } } + +SINGLE_BATTLE_TEST("Liquid Ooze HP loss from Absorb is blocked by Magic Guard") +{ + GIVEN { + PLAYER(SPECIES_CLEFFA) { Ability(ABILITY_MAGIC_GUARD); } + OPPONENT(SPECIES_TENTACOOL) { Ability(ABILITY_LIQUID_OOZE); } + } WHEN { + TURN { MOVE(player, MOVE_ABSORB); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ABSORB, player); + HP_BAR(opponent); + NONE_OF { + HP_BAR(player); + MESSAGE("Wobbuffet sucked up the liquid ooze!"); + } + } +} + +SINGLE_BATTLE_TEST("Liquid Ooze HP loss from Leech Seed is blocked by Magic Guard") +{ + GIVEN { + PLAYER(SPECIES_CLEFFA) { Ability(ABILITY_MAGIC_GUARD); } + OPPONENT(SPECIES_TENTACOOL) { Ability(ABILITY_LIQUID_OOZE); } + } WHEN { + TURN { MOVE(player, MOVE_LEECH_SEED); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_LEECH_SEED, player); + HP_BAR(opponent); + NOT HP_BAR(player); + } +} diff --git a/test/battle/ability/magician.c b/test/battle/ability/magician.c index 9e8012002..a54ba2df7 100644 --- a/test/battle/ability/magician.c +++ b/test/battle/ability/magician.c @@ -25,3 +25,31 @@ SINGLE_BATTLE_TEST("Magician gets self-damage recoil after stealing Life Orb") } } +DOUBLE_BATTLE_TEST("Magician steal the item from the fastest possible target") +{ + u32 playerRightSpeed = 0; + u32 opponentLeftSpeed = 0; + u32 opponentRightSpeed = 0; + + PARAMETRIZE { playerRightSpeed = 4; opponentLeftSpeed = 2; opponentRightSpeed = 3; } + PARAMETRIZE { playerRightSpeed = 3; opponentLeftSpeed = 4; opponentRightSpeed = 2; } + PARAMETRIZE { playerRightSpeed = 2; opponentLeftSpeed = 3; opponentRightSpeed = 4; } + + GIVEN { + PLAYER(SPECIES_DELPHOX) { Speed(1); Ability(ABILITY_MAGICIAN); Item(ITEM_NONE); } + PLAYER(SPECIES_WOBBUFFET) { Speed(playerRightSpeed); Item(ITEM_POKE_BALL); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(opponentLeftSpeed); Item(ITEM_GREAT_BALL); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(opponentRightSpeed); Item(ITEM_ULTRA_BALL); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_SURF); } + } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_MAGICIAN); + } THEN { + if (playerRightSpeed == 4) + EXPECT(playerLeft->item == ITEM_POKE_BALL); + else if (opponentLeftSpeed == 4) + EXPECT(playerLeft->item == ITEM_GREAT_BALL); + else if (playerRightSpeed == 4) + EXPECT(playerLeft->item == ITEM_ULTRA_BALL); + } +} diff --git a/test/battle/ability/mimicry.c b/test/battle/ability/mimicry.c index 67eab2057..5cdea7276 100644 --- a/test/battle/ability/mimicry.c +++ b/test/battle/ability/mimicry.c @@ -13,7 +13,7 @@ SINGLE_BATTLE_TEST("Mimicry changes the battler's type based on Terrain") { u32 j; u32 terrainMove = MOVE_NONE; - u32 terrainType = TYPE_NONE; + enum Type terrainType = TYPE_NONE; for (j = 0; j < ARRAY_COUNT(terrainData); j++) PARAMETRIZE { terrainMove = terrainData[j][0]; terrainType = terrainData[j][1]; } diff --git a/test/battle/ability/oblivious.c b/test/battle/ability/oblivious.c index 40506e196..c160ab423 100644 --- a/test/battle/ability/oblivious.c +++ b/test/battle/ability/oblivious.c @@ -31,22 +31,35 @@ SINGLE_BATTLE_TEST("Oblivious prevents Captivate") } } -SINGLE_BATTLE_TEST("Oblivious prevents Taunt") +SINGLE_BATTLE_TEST("Oblivious prevents Taunt (Gen6+)") { + u32 gen = 0; + PARAMETRIZE { gen = GEN_5; } + PARAMETRIZE { gen = GEN_6; } GIVEN { + WITH_CONFIG(GEN_CONFIG_OBLIVIOUS_TAUNT, gen); ASSUME(GetMoveEffect(MOVE_TAUNT) == EFFECT_TAUNT); - ASSUME(B_OBLIVIOUS_TAUNT >= GEN_6); PLAYER(SPECIES_SLOWPOKE) { Ability(ABILITY_OBLIVIOUS); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { TURN { MOVE(opponent, MOVE_TAUNT); } - TURN { MOVE(player, MOVE_SPORE); } + TURN { MOVE(player, MOVE_SPORE, allowed: gen == GEN_6); } } SCENE { - ABILITY_POPUP(player, ABILITY_OBLIVIOUS); - NONE_OF { ANIMATION(ANIM_TYPE_MOVE, MOVE_TAUNT, opponent); } - MESSAGE("It doesn't affect Slowpoke…"); - ANIMATION(ANIM_TYPE_MOVE, MOVE_SPORE, player); - ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_SLP, opponent); + if (gen == GEN_6) { + NONE_OF { ANIMATION(ANIM_TYPE_MOVE, MOVE_TAUNT, opponent); } + ABILITY_POPUP(player, ABILITY_OBLIVIOUS); + MESSAGE("It doesn't affect Slowpoke…"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SPORE, player); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_SLP, opponent); + } else { + ANIMATION(ANIM_TYPE_MOVE, MOVE_TAUNT, opponent); + NONE_OF { + ABILITY_POPUP(player, ABILITY_OBLIVIOUS); + MESSAGE("It doesn't affect Slowpoke…"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SPORE, player); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_SLP, opponent); + } + } } } diff --git a/test/battle/ability/overcoat.c b/test/battle/ability/overcoat.c index c722d7ac5..cfdbad7de 100644 --- a/test/battle/ability/overcoat.c +++ b/test/battle/ability/overcoat.c @@ -1,25 +1,37 @@ #include "global.h" #include "test/battle.h" -SINGLE_BATTLE_TEST("Overcoat blocks powder and spore moves") +SINGLE_BATTLE_TEST("Overcoat blocks powder and spore moves (Gen6+)") { + u32 gen = 0; + PARAMETRIZE { gen = GEN_5; } + PARAMETRIZE { gen = GEN_6; } GIVEN { + WITH_CONFIG(GEN_CONFIG_POWDER_OVERCOAT, gen); ASSUME(IsPowderMove(MOVE_STUN_SPORE)); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_PINECO) { Ability(ABILITY_OVERCOAT); } } WHEN { TURN { MOVE(player, MOVE_STUN_SPORE); } } SCENE { - ABILITY_POPUP(opponent, ABILITY_OVERCOAT); - NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_STUN_SPORE, player); - MESSAGE("It doesn't affect the opposing Pineco…"); + if (gen == GEN_6) { + ABILITY_POPUP(opponent, ABILITY_OVERCOAT); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_STUN_SPORE, player); + MESSAGE("It doesn't affect the opposing Pineco…"); + } else { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STUN_SPORE, player); + NONE_OF { + ABILITY_POPUP(opponent, ABILITY_OVERCOAT); + MESSAGE("It doesn't affect the opposing Pineco…"); + } + } } } DOUBLE_BATTLE_TEST("Overcoat blocks damage from sandstorm") { GIVEN { - PLAYER(SPECIES_WYNAUT) { Speed(50); } + PLAYER(SPECIES_WYNAUT) { Speed(50); } PLAYER(SPECIES_HELIOLISK) { Speed(40); Ability(ABILITY_SAND_VEIL); } OPPONENT(SPECIES_PINECO) { Speed(30); Ability(ABILITY_OVERCOAT); } OPPONENT(SPECIES_STARLY) { Speed(20); } @@ -41,7 +53,7 @@ DOUBLE_BATTLE_TEST("Overcoat blocks damage from hail") { GIVEN { ASSUME(GetMoveEffect(MOVE_HAIL) == EFFECT_HAIL); - PLAYER(SPECIES_WYNAUT) { Speed(50); Ability(ABILITY_SNOW_CLOAK); } + PLAYER(SPECIES_WYNAUT) { Speed(50); Ability(ABILITY_SNOW_CLOAK); } PLAYER(SPECIES_SOLOSIS) { Speed(40); Ability(ABILITY_RUN_AWAY); } OPPONENT(SPECIES_PINECO) { Speed(30); Ability(ABILITY_OVERCOAT); } OPPONENT(SPECIES_SNORUNT) { Speed(20); } @@ -73,4 +85,3 @@ SINGLE_BATTLE_TEST("Overcoat blocks Effect Spore's effect") EXPECT_EQ(player->status1, 0); } } - diff --git a/test/battle/ability/parental_bond.c b/test/battle/ability/parental_bond.c index c684963f0..1909efe28 100644 --- a/test/battle/ability/parental_bond.c +++ b/test/battle/ability/parental_bond.c @@ -105,7 +105,8 @@ DOUBLE_BATTLE_TEST("Parental Bond does not convert multi-target moves into a two SINGLE_BATTLE_TEST("Parental Bond-converted moves only hit once on Lightning Rod/Storm Drain mons") { - u16 move, species, type; + u16 move, species; + enum Type type; enum Ability ability; PARAMETRIZE { move = MOVE_THUNDERBOLT; ability = ABILITY_LIGHTNING_ROD; species = SPECIES_RAICHU; type = TYPE_ELECTRIC; } PARAMETRIZE { move = MOVE_SURF; ability = ABILITY_STORM_DRAIN; species = SPECIES_LILEEP; type = TYPE_WATER; } @@ -292,10 +293,10 @@ SINGLE_BATTLE_TEST("Parental Bond Snore strikes twice while asleep") HP_BAR(opponent, captureDamage: &damage[1]); MESSAGE("The Pokémon was hit 2 time(s)!"); } THEN { - if (B_PARENTAL_BOND_DMG == GEN_6) - EXPECT_MUL_EQ(damage[0], Q_4_12(0.5), damage[1]); - else + if (B_PARENTAL_BOND_DMG >= GEN_7) EXPECT_MUL_EQ(damage[0], Q_4_12(0.25), damage[1]); + else + EXPECT_MUL_EQ(damage[0], Q_4_12(0.5), damage[1]); } } diff --git a/test/battle/ability/power_construct.c b/test/battle/ability/power_construct.c index 6a8ca9db5..07d52c176 100644 --- a/test/battle/ability/power_construct.c +++ b/test/battle/ability/power_construct.c @@ -2,3 +2,56 @@ #include "test/battle.h" TO_DO_BATTLE_TEST("TODO: Write Power Construct (Ability) test titles") + +SINGLE_BATTLE_TEST("Power Construct switches Zygarde's form when HP is below half") +{ + u16 baseSpecies; + PARAMETRIZE { baseSpecies = SPECIES_ZYGARDE_10_POWER_CONSTRUCT; } + PARAMETRIZE { baseSpecies = SPECIES_ZYGARDE_50_POWER_CONSTRUCT; } + + GIVEN { + PLAYER(baseSpecies) + { + Ability(ABILITY_POWER_CONSTRUCT); + HP((GetMonData(&PLAYER_PARTY[0], MON_DATA_MAX_HP) / 2) + 1); + } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SCRATCH); MOVE(player, MOVE_CELEBRATE); } + } SCENE { + MESSAGE("You sense the presence of many!"); + ABILITY_POPUP(player, ABILITY_POWER_CONSTRUCT); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_POWER_CONSTRUCT, player); + } THEN { + EXPECT_EQ(player->species, SPECIES_ZYGARDE_COMPLETE); + } +} + +WILD_BATTLE_TEST("Power Construct Zygarde reverts to its original form upon catching") +{ + u16 baseSpecies; + PARAMETRIZE { baseSpecies = SPECIES_ZYGARDE_10_POWER_CONSTRUCT; } + PARAMETRIZE { baseSpecies = SPECIES_ZYGARDE_50_POWER_CONSTRUCT; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(baseSpecies) + { + Ability(ABILITY_POWER_CONSTRUCT); + HP((GetMonData(&OPPONENT_PARTY[0], MON_DATA_MAX_HP) / 2) + 1); + } + } WHEN { + TURN { MOVE(player, MOVE_SCRATCH); } + TURN { USE_ITEM(player, ITEM_MASTER_BALL); } + } SCENE { + // Turn 1 + MESSAGE("You sense the presence of many!"); + ABILITY_POPUP(opponent, ABILITY_POWER_CONSTRUCT); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_POWER_CONSTRUCT, opponent); + + // Turn 2 + ANIMATION(ANIM_TYPE_SPECIAL, B_ANIM_BALL_THROW, player); + } THEN { + EXPECT_EQ(GetMonData(&gPlayerParty[1], MON_DATA_SPECIES), baseSpecies); + } +} diff --git a/test/battle/ability/protean.c b/test/battle/ability/protean.c index c5d141d24..fe4ae25e6 100644 --- a/test/battle/ability/protean.c +++ b/test/battle/ability/protean.c @@ -54,3 +54,19 @@ SINGLE_BATTLE_TEST("Protean changes the type of the user only once per switch in ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, opponent); } } + +SINGLE_BATTLE_TEST("Protean does not change the user's type when using Struggle") +{ + GIVEN { + PLAYER(SPECIES_REGIROCK); + OPPONENT(SPECIES_GRENINJA) { Ability(ABILITY_PROTEAN); } + } WHEN { + TURN { MOVE(opponent, MOVE_STRUGGLE); } + } SCENE { + NONE_OF { + ABILITY_POPUP(opponent, ABILITY_PROTEAN); + MESSAGE("The opposing Greninja transformed into the Normal type!"); + } + ANIMATION(ANIM_TYPE_MOVE, MOVE_STRUGGLE, opponent); + } +} diff --git a/test/battle/ability/protosynthesis.c b/test/battle/ability/protosynthesis.c index c45f41602..9bffb125e 100644 --- a/test/battle/ability/protosynthesis.c +++ b/test/battle/ability/protosynthesis.c @@ -59,6 +59,7 @@ SINGLE_BATTLE_TEST("Protosynthesis ability pop up activates only once during the u16 turns; GIVEN { + WITH_CONFIG(GEN_CONFIG_ABILITY_WEATHER, GEN_6); PLAYER(SPECIES_WALKING_WAKE) { Ability(ABILITY_PROTOSYNTHESIS); } OPPONENT(SPECIES_NINETALES) { Ability(ABILITY_DROUGHT); }; } WHEN { @@ -200,3 +201,21 @@ SINGLE_BATTLE_TEST("Protosynthesis doesn't activate if Cloud Nine/Air Lock is on NOT ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS); } } + +SINGLE_BATTLE_TEST("Protosynthesis activates after weather was reset") +{ + GIVEN { + PLAYER(SPECIES_WALKING_WAKE) { Ability(ABILITY_PROTOSYNTHESIS); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_SUNNY_DAY); } + TURN { MOVE(player, MOVE_RAIN_DANCE); } + TURN { MOVE(player, MOVE_SUNNY_DAY); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, player); + ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS); + ANIMATION(ANIM_TYPE_MOVE, MOVE_RAIN_DANCE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, player); + ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS); + } +} diff --git a/test/battle/ability/receiver.c b/test/battle/ability/receiver.c index a9155b724..7e6b7076b 100644 --- a/test/battle/ability/receiver.c +++ b/test/battle/ability/receiver.c @@ -1,4 +1,63 @@ #include "global.h" #include "test/battle.h" +DOUBLE_BATTLE_TEST("Receiver copies ally's ability when they faint and immediately activates it") +{ + GIVEN { + ASSUME(!gAbilitiesInfo[ABILITY_INTIMIDATE].cantBeCopied); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_PASSIMIAN) { Ability(ABILITY_RECEIVER); } + OPPONENT(SPECIES_GYARADOS) { Ability(ABILITY_INTIMIDATE); HP(1); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_SCRATCH, target: opponentRight); } + } SCENE { + ABILITY_POPUP(opponentRight, ABILITY_INTIMIDATE); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, playerLeft); + ABILITY_POPUP(opponentLeft, ABILITY_RECEIVER); + ABILITY_POPUP(opponentLeft, ABILITY_INTIMIDATE); + } THEN { + EXPECT_EQ(playerLeft->statStages[STAT_ATK], DEFAULT_STAT_STAGE - 2); + EXPECT_EQ(playerRight->statStages[STAT_ATK], DEFAULT_STAT_STAGE - 2); + } +} + +DOUBLE_BATTLE_TEST("Receiver copies ally's ability when they faint and can activate it on future moves") +{ + GIVEN { + ASSUME(!gAbilitiesInfo[ABILITY_WATER_ABSORB].cantBeCopied); + ASSUME(GetMoveType(MOVE_WATER_GUN) == TYPE_WATER); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_PASSIMIAN) { Ability(ABILITY_RECEIVER); } + OPPONENT(SPECIES_LANTURN) { Ability(ABILITY_WATER_ABSORB); HP(1); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_SCRATCH, target: opponentRight); MOVE(playerRight, MOVE_WATER_GUN, target: opponentLeft); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, playerLeft); + ABILITY_POPUP(opponentLeft, ABILITY_RECEIVER); + ABILITY_POPUP(opponentLeft, ABILITY_WATER_ABSORB); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, playerRight); + } +} + +DOUBLE_BATTLE_TEST("Receiver copies ally's Soul Heart and immediately activates it") +{ + GIVEN { + ASSUME(!gAbilitiesInfo[ABILITY_SOUL_HEART].cantBeCopied); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_PASSIMIAN) { Ability(ABILITY_RECEIVER); } + OPPONENT(SPECIES_MAGEARNA) { Ability(ABILITY_SOUL_HEART); HP(1); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_SCRATCH, target: opponentRight); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, playerLeft); + ABILITY_POPUP(opponentLeft, ABILITY_RECEIVER); + ABILITY_POPUP(opponentLeft, ABILITY_SOUL_HEART); + } THEN { + EXPECT_EQ(opponentLeft->statStages[STAT_SPATK], DEFAULT_STAT_STAGE + 1); + } +} + TO_DO_BATTLE_TEST("TODO: Write Receiver (Ability) test titles") diff --git a/test/battle/ability/sand_force.c b/test/battle/ability/sand_force.c index 7592c5afe..ba062f3fa 100644 --- a/test/battle/ability/sand_force.c +++ b/test/battle/ability/sand_force.c @@ -3,8 +3,8 @@ SINGLE_BATTLE_TEST("Sand Force prevents damage from sandstorm") { - u32 type1 = GetSpeciesType(SPECIES_SHELLOS, 0); - u32 type2 = GetSpeciesType(SPECIES_SHELLOS, 1); + enum Type type1 = GetSpeciesType(SPECIES_SHELLOS, 0); + enum Type type2 = GetSpeciesType(SPECIES_SHELLOS, 1); GIVEN { ASSUME(type1 != TYPE_ROCK && type2 != TYPE_ROCK); ASSUME(type1 != TYPE_GROUND && type2 != TYPE_GROUND); diff --git a/test/battle/ability/sand_rush.c b/test/battle/ability/sand_rush.c index 4d557348e..9d6ef9827 100644 --- a/test/battle/ability/sand_rush.c +++ b/test/battle/ability/sand_rush.c @@ -3,8 +3,8 @@ SINGLE_BATTLE_TEST("Sand Rush prevents damage from sandstorm") { - u32 type1 = GetSpeciesType(SPECIES_STOUTLAND, 0); - u32 type2 = GetSpeciesType(SPECIES_STOUTLAND, 1); + enum Type type1 = GetSpeciesType(SPECIES_STOUTLAND, 0); + enum Type type2 = GetSpeciesType(SPECIES_STOUTLAND, 1); GIVEN { ASSUME(type1 != TYPE_ROCK && type2 != TYPE_ROCK); ASSUME(type1 != TYPE_GROUND && type2 != TYPE_GROUND); diff --git a/test/battle/ability/sheer_force.c b/test/battle/ability/sheer_force.c index 1f861937a..abeee88ce 100644 --- a/test/battle/ability/sheer_force.c +++ b/test/battle/ability/sheer_force.c @@ -1363,15 +1363,16 @@ DOUBLE_BATTLE_TEST("Sheer Force only boosts the damage of moves it's supposed to AI_SINGLE_BATTLE_TEST("AI sees Sheer Force skips additional effects") { - u16 ability, expectedMove; + u16 ability, expectedMove, move; - PARAMETRIZE { ability = ABILITY_NONE; expectedMove = MOVE_POWER_UP_PUNCH; } - PARAMETRIZE { ability = ABILITY_SHEER_FORCE; expectedMove = MOVE_KARATE_CHOP; } + PARAMETRIZE { ability = ABILITY_ROUGH_SKIN; move = MOVE_KARATE_CHOP; expectedMove = MOVE_POWER_UP_PUNCH; } + PARAMETRIZE { ability = ABILITY_ROUGH_SKIN; move = MOVE_BRICK_BREAK; expectedMove = MOVE_POWER_UP_PUNCH; } + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; move = MOVE_BRICK_BREAK; expectedMove = MOVE_BRICK_BREAK; } GIVEN { AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET) { Ability(ability); Moves(MOVE_POWER_UP_PUNCH, MOVE_KARATE_CHOP); } + OPPONENT(SPECIES_DRUDDIGON) { Ability(ability); Moves(MOVE_POWER_UP_PUNCH, move); } } WHEN { TURN { EXPECT_MOVE(opponent, expectedMove); } } diff --git a/test/battle/ability/shield_dust.c b/test/battle/ability/shield_dust.c index 2d7358335..2fc4f51d5 100644 --- a/test/battle/ability/shield_dust.c +++ b/test/battle/ability/shield_dust.c @@ -188,3 +188,31 @@ SINGLE_BATTLE_TEST("Shield Dust does not prevent ability stat changes") MESSAGE("Vivillon's Speed fell!"); } } + +AI_SINGLE_BATTLE_TEST("AI will score secondary effects against shield dust correctly") +{ + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_OMNISCIENT); + GIVEN { + PLAYER(SPECIES_DUSTOX){ Ability(ABILITY_SHIELD_DUST); Moves(MOVE_GUST); } + OPPONENT(SPECIES_SUNFLORA){ Ability(ABILITY_EARLY_BIRD); Moves(MOVE_MYSTICAL_FIRE, MOVE_FIERY_DANCE); } + } WHEN { + TURN { + MOVE(player, MOVE_GUST); + EXPECT_MOVE(opponent, MOVE_FIERY_DANCE); + } + } +} + +AI_SINGLE_BATTLE_TEST("AI will score secondary effects against shield dust correctly when it has Mold Breaker") +{ + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_OMNISCIENT); + GIVEN { + PLAYER(SPECIES_DUSTOX){ Ability(ABILITY_SHIELD_DUST); Moves(MOVE_GUST); } + OPPONENT(SPECIES_SUNFLORA){ Ability(ABILITY_MOLD_BREAKER); Moves(MOVE_MYSTICAL_FIRE, MOVE_FIERY_DANCE); } + } WHEN { + TURN { + MOVE(player, MOVE_GUST); + EXPECT_MOVE(opponent, MOVE_MYSTICAL_FIRE); + } + } +} diff --git a/test/battle/ability/shields_down.c b/test/battle/ability/shields_down.c index f9def2991..554e67b0d 100644 --- a/test/battle/ability/shields_down.c +++ b/test/battle/ability/shields_down.c @@ -1,28 +1,30 @@ #include "global.h" #include "test/battle.h" -SINGLE_BATTLE_TEST("Minior Meteor transforms into Minior Core on switch-in if it has 1/2 or less health") +SINGLE_BATTLE_TEST("Minior Core doesn't transform into Minior Meteor on switch-in if it has 1/2 or less health") { GIVEN { PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET) { HP(1); } - OPPONENT(SPECIES_MINIOR_METEOR) { Ability(ABILITY_SHIELDS_DOWN); HP(1); } + OPPONENT(SPECIES_MINIOR_CORE) { Ability(ABILITY_SHIELDS_DOWN); HP(50); MaxHP(100); } } WHEN { TURN { MOVE(player, MOVE_SCRATCH); SEND_OUT(opponent, 1); } } SCENE { - ABILITY_POPUP(opponent, ABILITY_SHIELDS_DOWN); - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, opponent); + NONE_OF { + ABILITY_POPUP(opponent, ABILITY_SHIELDS_DOWN); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, opponent); + } } THEN { EXPECT_EQ(opponent->species, SPECIES_MINIOR_CORE); } } -SINGLE_BATTLE_TEST("Minior Core transforms into Minior Meteor on switch-in if it more then 1/2 health") +SINGLE_BATTLE_TEST("Minior Core transforms into Minior Meteor on switch-in if it has more than 1/2 health") { GIVEN { PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET) { HP(1); } - OPPONENT(SPECIES_MINIOR_CORE) { Ability(ABILITY_SHIELDS_DOWN); } + OPPONENT(SPECIES_MINIOR_CORE) { Ability(ABILITY_SHIELDS_DOWN); HP(51); MaxHP(101); } } WHEN { TURN { MOVE(player, MOVE_SCRATCH); SEND_OUT(opponent, 1); } } SCENE { @@ -32,3 +34,44 @@ SINGLE_BATTLE_TEST("Minior Core transforms into Minior Meteor on switch-in if it EXPECT_EQ(opponent->species, SPECIES_MINIOR_METEOR); } } + +SINGLE_BATTLE_TEST("Minior Core transforms into Minior Meteor on battle start if it has more than 1/2 health") +{ + GIVEN { + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_MINIOR_CORE) { Ability(ABILITY_SHIELDS_DOWN); HP(51); MaxHP(101); } + } WHEN { + TURN { } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_SHIELDS_DOWN); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, opponent); + } THEN { + EXPECT_EQ(opponent->species, SPECIES_MINIOR_METEOR); + } +} + +SINGLE_BATTLE_TEST("Shields Down protects Minior Meteor from status conditions") +{ + u32 species, hp; + PARAMETRIZE { species = SPECIES_MINIOR_METEOR; hp = 300; } + PARAMETRIZE { species = SPECIES_MINIOR_CORE; hp = 100; } + + GIVEN { + ASSUME(GetMoveEffect(MOVE_WILL_O_WISP) == EFFECT_NON_VOLATILE_STATUS); + ASSUME(GetMoveNonVolatileStatus(MOVE_WILL_O_WISP) == MOVE_EFFECT_BURN); + PLAYER(SPECIES_WYNAUT); + OPPONENT(species) { Ability(ABILITY_SHIELDS_DOWN); HP(hp); MaxHP(300); } + } WHEN { + TURN { MOVE(player, MOVE_WILL_O_WISP); } + } SCENE { + if (species == SPECIES_MINIOR_METEOR) + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_WILL_O_WISP, player); + else + ANIMATION(ANIM_TYPE_MOVE, MOVE_WILL_O_WISP, player); + } THEN { + if (species == SPECIES_MINIOR_METEOR) + EXPECT_EQ(opponent->status1, STATUS1_NONE); + else + EXPECT(opponent->status1 & STATUS1_BURN); + } +} diff --git a/test/battle/ability/soundproof.c b/test/battle/ability/soundproof.c index a7135942d..6af6231cc 100644 --- a/test/battle/ability/soundproof.c +++ b/test/battle/ability/soundproof.c @@ -1,4 +1,20 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("TODO: Write Soundproof (Ability) test titles") +SINGLE_BATTLE_TEST("Soundproof makes sound moves fail against the ability user") +{ + GIVEN { + ASSUME(IsSoundMove(MOVE_BOOMBURST)); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_EXPLOUD) { Ability(ABILITY_SOUNDPROOF); } + } WHEN { + TURN { MOVE(player, MOVE_BOOMBURST); } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_SOUNDPROOF); + MESSAGE("The opposing Exploud's Soundproof blocks Boomburst!"); + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_BOOMBURST, player); + HP_BAR(opponent); + } + } +} diff --git a/test/battle/ability/steadfast.c b/test/battle/ability/steadfast.c index fc35e9427..2d6fb5d90 100644 --- a/test/battle/ability/steadfast.c +++ b/test/battle/ability/steadfast.c @@ -1,4 +1,56 @@ #include "global.h" #include "test/battle.h" +SINGLE_BATTLE_TEST("Steadfast boosts Speed when the user attempts to move but is flinched") +{ + GIVEN { + ASSUME(MoveHasAdditionalEffectWithChance(MOVE_FAKE_OUT, MOVE_EFFECT_FLINCH, 100)); + PLAYER(SPECIES_LUCARIO) { Ability(ABILITY_STEADFAST); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_FAKE_OUT); MOVE(player, MOVE_CELEBRATE); } + } SCENE { + ABILITY_POPUP(player, ABILITY_STEADFAST); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + } THEN { + EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE + 1); + } +} + +SINGLE_BATTLE_TEST("Steadfast doesn't activate if the user wasn't flinched") +{ + GIVEN { + ASSUME(MoveHasAdditionalEffectWithChance(MOVE_FAKE_OUT, MOVE_EFFECT_FLINCH, 100)); + ASSUME(GetItemHoldEffect(ITEM_COVERT_CLOAK) == HOLD_EFFECT_COVERT_CLOAK); + PLAYER(SPECIES_LUCARIO) { Ability(ABILITY_STEADFAST); Item(ITEM_COVERT_CLOAK); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_FAKE_OUT); MOVE(player, MOVE_CELEBRATE); } + } SCENE { + NOT ABILITY_POPUP(player, ABILITY_STEADFAST); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + } THEN { + EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE); + } +} + +DOUBLE_BATTLE_TEST("Steadfast doesn't activate if the user has already moved") +{ + GIVEN { + ASSUME(MoveHasAdditionalEffect(MOVE_BITE, MOVE_EFFECT_FLINCH)); + ASSUME(GetMoveEffect(MOVE_INSTRUCT) == EFFECT_INSTRUCT); + PLAYER(SPECIES_LUCARIO) { Ability(ABILITY_STEADFAST); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_SWORDS_DANCE); MOVE(opponentLeft, MOVE_BITE, target: playerLeft); MOVE(playerRight, MOVE_INSTRUCT, target: playerLeft); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SWORDS_DANCE, playerLeft); + NOT ABILITY_POPUP(playerLeft, ABILITY_STEADFAST); + } THEN { + EXPECT_EQ(playerLeft->statStages[STAT_SPEED], DEFAULT_STAT_STAGE); + } +} + TO_DO_BATTLE_TEST("TODO: Write Steadfast (Ability) test titles") diff --git a/test/battle/ability/supersweet_syrup.c b/test/battle/ability/supersweet_syrup.c index 4ff8c462b..cd819eda7 100644 --- a/test/battle/ability/supersweet_syrup.c +++ b/test/battle/ability/supersweet_syrup.c @@ -56,11 +56,21 @@ SINGLE_BATTLE_TEST("Supersweet Syrup can not further lower opponents evasion if TURN { MOVE(opponent, MOVE_SWEET_SCENT); } TURN { MOVE(opponent, MOVE_SWEET_SCENT); } TURN { MOVE(opponent, MOVE_SWEET_SCENT); } + if (GetMoveEffect(MOVE_SWEET_SCENT) == EFFECT_EVASION_DOWN) { + TURN { MOVE(opponent, MOVE_SWEET_SCENT); } + TURN { MOVE(opponent, MOVE_SWEET_SCENT); } + TURN { MOVE(opponent, MOVE_SWEET_SCENT); } + } TURN { SWITCH(opponent, 1); } } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_SWEET_SCENT, opponent); ANIMATION(ANIM_TYPE_MOVE, MOVE_SWEET_SCENT, opponent); ANIMATION(ANIM_TYPE_MOVE, MOVE_SWEET_SCENT, opponent); + if (GetMoveEffect(MOVE_SWEET_SCENT) == EFFECT_EVASION_DOWN) { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SWEET_SCENT, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SWEET_SCENT, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SWEET_SCENT, opponent); + } ABILITY_POPUP(opponent, ABILITY_SUPERSWEET_SYRUP); NONE_OF { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); diff --git a/test/battle/ability/sword_of_ruin.c b/test/battle/ability/sword_of_ruin.c index 395cd3fd6..a891f7d5a 100644 --- a/test/battle/ability/sword_of_ruin.c +++ b/test/battle/ability/sword_of_ruin.c @@ -73,3 +73,118 @@ SINGLE_BATTLE_TEST("Sword of Ruin's message displays correctly after all battler MESSAGE("The opposing Chien-Pao's Sword of Ruin weakened the Defense of all surrounding Pokémon!"); } } + +DOUBLE_BATTLE_TEST("Sword of Ruin increases damage taken by special moves in Wonder Room", s16 damage) +{ + bool32 useWonderRoom; + u32 move; + + PARAMETRIZE { useWonderRoom = FALSE; move = MOVE_SCRATCH; } + PARAMETRIZE { useWonderRoom = FALSE; move = MOVE_ROUND; } + PARAMETRIZE { useWonderRoom = TRUE; move = MOVE_SCRATCH; } + PARAMETRIZE { useWonderRoom = TRUE; move = MOVE_ROUND; } + + GIVEN { + ASSUME(GetMoveEffect(MOVE_WONDER_ROOM) == EFFECT_WONDER_ROOM); + ASSUME(GetMoveCategory(MOVE_ROUND) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveEffect(MOVE_ROUND) != EFFECT_PSYSHOCK); + PLAYER(SPECIES_CHIEN_PAO) { Ability(ABILITY_SWORD_OF_RUIN); } + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + if (useWonderRoom) + TURN { MOVE(opponentLeft, MOVE_WONDER_ROOM); MOVE(playerRight, move, target: opponentLeft); } + else + TURN { MOVE(playerRight, move, target: opponentLeft); } + } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_SWORD_OF_RUIN); + MESSAGE("Chien-Pao's Sword of Ruin weakened the Defense of all surrounding Pokémon!"); + ANIMATION(ANIM_TYPE_MOVE, move, playerRight); + HP_BAR(opponentLeft, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_LT(results[2].damage, results[0].damage); // In Wonder Room, physical move deals less damage + EXPECT_GT(results[3].damage, results[1].damage); // In Wonder Room, special move deals more damage + } +} + +SINGLE_BATTLE_TEST("Sword of Ruin doesn't activate when dragged out by Mold Breaker attacker") +{ + u32 ability; + + PARAMETRIZE { ability = ABILITY_MOLD_BREAKER; } + PARAMETRIZE { ability = ABILITY_SAND_RUSH; } + + GIVEN { + ASSUME(GetMoveEffect(MOVE_DRAGON_TAIL) == EFFECT_HIT_SWITCH_TARGET); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_CHIEN_PAO) { Ability(ABILITY_SWORD_OF_RUIN); } + OPPONENT(SPECIES_EXCADRILL) { Ability(ability); } + } WHEN { + TURN { MOVE(opponent, MOVE_DRAGON_TAIL); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_TAIL, opponent); + if (ability == ABILITY_MOLD_BREAKER) + { + NONE_OF { + ABILITY_POPUP(player, ABILITY_SWORD_OF_RUIN); + MESSAGE("Chien-Pao's Sword of Ruin weakened the Defense of all surrounding Pokémon!"); + } + } + else + { + ABILITY_POPUP(player, ABILITY_SWORD_OF_RUIN); + MESSAGE("Chien-Pao's Sword of Ruin weakened the Defense of all surrounding Pokémon!"); + } + } +} + +DOUBLE_BATTLE_TEST("Sword of Ruin's Defense reduction is not ignored by Mold Breaker", s16 damage) +{ + u32 ability; + + PARAMETRIZE { ability = ABILITY_MOLD_BREAKER; } + PARAMETRIZE { ability = ABILITY_SAND_RUSH; } + + GIVEN { + PLAYER(SPECIES_CHIEN_PAO) { Ability(ABILITY_SWORD_OF_RUIN); } + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_EXCADRILL) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponentLeft, MOVE_SCRATCH, target: playerRight); } + } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_SWORD_OF_RUIN); + MESSAGE("Chien-Pao's Sword of Ruin weakened the Defense of all surrounding Pokémon!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponentLeft); + HP_BAR(playerRight, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + } +} + +DOUBLE_BATTLE_TEST("Sword of Ruin's Defense reduction is ignored by Gastro Acid", s16 damage) +{ + u32 move; + + PARAMETRIZE { move = MOVE_GASTRO_ACID; } + PARAMETRIZE { move = MOVE_CELEBRATE; } + + GIVEN { + ASSUME(GetMoveEffect(MOVE_GASTRO_ACID) == EFFECT_GASTRO_ACID); + PLAYER(SPECIES_CHIEN_PAO) { Ability(ABILITY_SWORD_OF_RUIN); } + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponentRight, move, target: playerLeft); MOVE(opponentLeft, MOVE_SCRATCH, target: playerRight); } + } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_SWORD_OF_RUIN); + MESSAGE("Chien-Pao's Sword of Ruin weakened the Defense of all surrounding Pokémon!"); + ANIMATION(ANIM_TYPE_MOVE, move, opponentRight); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponentLeft); + HP_BAR(playerRight, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_LT(results[0].damage, results[1].damage); + } +} diff --git a/test/battle/ability/tangling_hair.c b/test/battle/ability/tangling_hair.c index 13a0f27cb..fdae4de06 100644 --- a/test/battle/ability/tangling_hair.c +++ b/test/battle/ability/tangling_hair.c @@ -8,7 +8,6 @@ ASSUMPTIONS ASSUME(MoveMakesContact(MOVE_SCRATCH) == TRUE); } - SINGLE_BATTLE_TEST("Tangling Hair drops opposing mon's speed if ability user got hit by a contact move") { u32 move; @@ -85,3 +84,30 @@ SINGLE_BATTLE_TEST("Tangling Hair does not activate on confusion damage") } } } + +SINGLE_BATTLE_TEST("Tangling Hair does not trigger on Clear Body") +{ + GIVEN { + PLAYER(SPECIES_DUGTRIO) { Ability(ABILITY_TANGLING_HAIR); } + OPPONENT(SPECIES_BELDUM) { Ability(ABILITY_CLEAR_BODY); }; + } WHEN { + TURN { MOVE(opponent, MOVE_SCRATCH); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponent); + NOT ABILITY_POPUP(player, ABILITY_TANGLING_HAIR); + } +} + +SINGLE_BATTLE_TEST("Tangling Hair will trigger if move is boosted by Sheer Force") +{ + ASSUME(MoveIsAffectedBySheerForce(MOVE_POISON_JAB)); + GIVEN { + PLAYER(SPECIES_DUGTRIO) { Ability(ABILITY_TANGLING_HAIR); } + OPPONENT(SPECIES_NIDOKING) { Ability(ABILITY_SHEER_FORCE); }; + } WHEN { + TURN { MOVE(opponent, MOVE_POISON_JAB); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_POISON_JAB, opponent); + ABILITY_POPUP(player, ABILITY_TANGLING_HAIR); + } +} diff --git a/test/battle/ability/teraform_zero.c b/test/battle/ability/teraform_zero.c index 930404116..f6620d662 100644 --- a/test/battle/ability/teraform_zero.c +++ b/test/battle/ability/teraform_zero.c @@ -39,7 +39,7 @@ DOUBLE_BATTLE_TEST("Teraform Zero can be supressed") SINGLE_BATTLE_TEST("Teraform Zero can be replaced") { GIVEN { - ASSUME(GetMoveEffect(MOVE_WORRY_SEED) == EFFECT_WORRY_SEED); + ASSUME(GetMoveEffect(MOVE_WORRY_SEED) == EFFECT_OVERWRITE_ABILITY); ASSUME(GetMoveEffect(MOVE_REST) == EFFECT_REST); PLAYER(SPECIES_TERAPAGOS); OPPONENT(SPECIES_WHIMSICOTT) { Ability(ABILITY_PRANKSTER); } diff --git a/test/battle/ability/toxic_debris.c b/test/battle/ability/toxic_debris.c index 61e128e98..466184990 100644 --- a/test/battle/ability/toxic_debris.c +++ b/test/battle/ability/toxic_debris.c @@ -120,3 +120,23 @@ SINGLE_BATTLE_TEST("Air Balloon is popped after Toxic Debris activates") MESSAGE("Glimmora's Air Balloon popped!"); } } + +DOUBLE_BATTLE_TEST("Toxic Debris sets Toxic Spikes on the opposing side even when hit by an ally") +{ + struct BattlePokemon *user = NULL; + + PARAMETRIZE{ user = opponentLeft; } + PARAMETRIZE{ user = opponentRight; } + PARAMETRIZE{ user = playerRight; } + GIVEN { + PLAYER(SPECIES_GLIMMORA) { Ability(ABILITY_TOXIC_DEBRIS); } + PLAYER(SPECIES_WYNAUT) { } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT) { } + } WHEN { + TURN { MOVE(user, MOVE_SCRATCH, target: playerLeft); } + } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_TOXIC_DEBRIS); + MESSAGE("Poison spikes were scattered on the ground all around the opposing team!"); + } +} diff --git a/test/battle/ability/unburden.c b/test/battle/ability/unburden.c index 0ddce0f22..4498bb492 100644 --- a/test/battle/ability/unburden.c +++ b/test/battle/ability/unburden.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Unburden doubles speed once user uses item") { GIVEN { - ASSUME(GetItemHoldEffect(ITEM_GRASSY_SEED) == HOLD_EFFECT_SEEDS); + ASSUME(GetItemHoldEffect(ITEM_GRASSY_SEED) == HOLD_EFFECT_TERRAIN_SEED); ASSUME(GetMoveEffect(MOVE_U_TURN) == EFFECT_HIT_ESCAPE); PLAYER(SPECIES_DRIFBLIM) { Ability(ABILITY_UNBURDEN); Item(ITEM_GRASSY_SEED); Speed(5); } OPPONENT(SPECIES_WOBBUFFET) { Speed(7); } diff --git a/test/battle/ability/zero_to_hero.c b/test/battle/ability/zero_to_hero.c index dcac9b854..7df3f0770 100644 --- a/test/battle/ability/zero_to_hero.c +++ b/test/battle/ability/zero_to_hero.c @@ -84,8 +84,8 @@ SINGLE_BATTLE_TEST("Gastro Acid, Worry Seed, and Simple Beam fail if the target GIVEN { ASSUME(GetMoveEffect(MOVE_GASTRO_ACID) == EFFECT_GASTRO_ACID); - ASSUME(GetMoveEffect(MOVE_WORRY_SEED) == EFFECT_WORRY_SEED); - ASSUME(GetMoveEffect(MOVE_SIMPLE_BEAM) == EFFECT_SIMPLE_BEAM); + ASSUME(GetMoveEffect(MOVE_WORRY_SEED) == EFFECT_OVERWRITE_ABILITY); + ASSUME(GetMoveEffect(MOVE_SIMPLE_BEAM) == EFFECT_OVERWRITE_ABILITY); PLAYER(SPECIES_PALAFIN_ZERO) { Ability(ABILITY_ZERO_TO_HERO); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/ai/ai_check_viability.c b/test/battle/ai/ai_check_viability.c index 8b6fd9797..77de2ba1c 100644 --- a/test/battle/ai/ai_check_viability.c +++ b/test/battle/ai/ai_check_viability.c @@ -439,3 +439,22 @@ AI_DOUBLE_BATTLE_TEST("AI sees type-changing moves as the correct type") TURN { NOT_EXPECT_MOVE(opponentLeft, fieldStatus); } } } + +AI_SINGLE_BATTLE_TEST("AI uses Sparkling Aria to cure an enemy with Guts") +{ + u32 ability; + + PARAMETRIZE { ability = ABILITY_GUTS; } + PARAMETRIZE { ability = ABILITY_BULLETPROOF; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT); + PLAYER(SPECIES_URSALUNA) { Ability(ability); Moves(MOVE_HEADLONG_RUSH, MOVE_CELEBRATE); Status1(STATUS1_BURN); } + OPPONENT(SPECIES_PRIMARINA) { Moves(MOVE_SPARKLING_ARIA, MOVE_SCALD); } + } WHEN { + if (ability == ABILITY_GUTS) + TURN { EXPECT_MOVE(opponent, MOVE_SPARKLING_ARIA); } + else + TURN { EXPECT_MOVE(opponent, MOVE_SCALD); } + } +} diff --git a/test/battle/ai/ai_doubles.c b/test/battle/ai/ai_doubles.c index 1ffd90181..82e8d9537 100644 --- a/test/battle/ai/ai_doubles.c +++ b/test/battle/ai/ai_doubles.c @@ -338,7 +338,7 @@ AI_DOUBLE_BATTLE_TEST("AI will trigger its ally's Weakness Policy") } } -AI_DOUBLE_BATTLE_TEST("AI will only explode and kill everything on the field with Risky or Will Suicide") +AI_DOUBLE_BATTLE_TEST("AI will only explode and kill everything on the field with Risky or Will Suicide (doubles)") { ASSUME(GetMoveTarget(MOVE_EXPLOSION) == MOVE_TARGET_FOES_AND_ALLY); ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); @@ -363,6 +363,36 @@ AI_DOUBLE_BATTLE_TEST("AI will only explode and kill everything on the field wit } } +AI_DOUBLE_BATTLE_TEST("Battler 3 has Battler 1 AI flags set correctly (doubles)") +{ + ASSUME(GetMoveTarget(MOVE_EXPLOSION) == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); + + u32 aiFlags; + u32 battler; + + PARAMETRIZE { aiFlags = 0; battler = 1; } + PARAMETRIZE { aiFlags = 0; battler = 3; } + PARAMETRIZE { aiFlags = AI_FLAG_RISKY; battler = 3; } + PARAMETRIZE { aiFlags = AI_FLAG_RISKY; battler = 1; } + PARAMETRIZE { aiFlags = AI_FLAG_WILL_SUICIDE; battler = 1; } + PARAMETRIZE { aiFlags = AI_FLAG_WILL_SUICIDE; battler = 3; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + BATTLER_AI_FLAGS(battler, aiFlags); + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + OPPONENT(SPECIES_VOLTORB) { Moves(MOVE_EXPLOSION, MOVE_ELECTRO_BALL); HP(1); } + OPPONENT(SPECIES_ELECTRODE) { Moves(MOVE_EXPLOSION, MOVE_ELECTRO_BALL); HP(1); } + } WHEN { + if (aiFlags == 0 || battler == 3) + TURN { EXPECT_MOVE(opponentLeft, MOVE_ELECTRO_BALL, target: playerLeft); EXPECT_MOVE(opponentRight, MOVE_ELECTRO_BALL, target: playerLeft); } + else + TURN { EXPECT_MOVE(opponentLeft, MOVE_EXPLOSION, target: playerLeft); EXPECT_MOVE(opponentRight, MOVE_EXPLOSION); } + } +} + AI_DOUBLE_BATTLE_TEST("AI sees corresponding absorbing abilities on partners") { ASSUME(GetMoveTarget(MOVE_DISCHARGE) == MOVE_TARGET_FOES_AND_ALLY); diff --git a/test/battle/ai/ai_flag_predict_switch.c b/test/battle/ai/ai_flag_predict_switch.c index b64dea488..8530c4967 100644 --- a/test/battle/ai/ai_flag_predict_switch.c +++ b/test/battle/ai/ai_flag_predict_switch.c @@ -59,7 +59,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_PREDICT_SWITCH: Considers ShouldSwitch and GetMos // Switching in trapper is an advanced feature of ShouldSwitch that requires GetMostSuitableMonToSwitchInto to also return a specific mon; this passing means the AI can use both in prediction PASSES_RANDOMLY(5, 10, RNG_AI_PREDICT_SWITCH); GIVEN { - ASSUME(B_POWDER_GRASS >= GEN_6); + WITH_CONFIG(GEN_CONFIG_POWDER_GRASS, GEN_6); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_PREDICT_SWITCH | AI_FLAG_PREDICT_INCOMING_MON); PLAYER(SPECIES_SKARMORY) { Moves(MOVE_SCRATCH); } PLAYER(SPECIES_DUGTRIO) { Ability(ABILITY_ARENA_TRAP); Moves(MOVE_ACROBATICS); } diff --git a/test/battle/ai/ai_multi.c b/test/battle/ai/ai_multi.c new file mode 100644 index 000000000..ddbfdb49b --- /dev/null +++ b/test/battle/ai/ai_multi.c @@ -0,0 +1,127 @@ +#include "global.h" +#include "test/battle.h" +#include "battle_ai_util.h" + +AI_MULTI_BATTLE_TEST("AI will only explode and kill everything on the field with Risky or Will Suicide (multi)") +{ + ASSUME(GetMoveTarget(MOVE_EXPLOSION) == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); + + u32 aiFlags; + u32 battler; + + PARAMETRIZE { aiFlags = 0; battler = 1; } + PARAMETRIZE { aiFlags = 0; battler = 3; } + PARAMETRIZE { aiFlags = AI_FLAG_RISKY; battler = 1; } + PARAMETRIZE { aiFlags = AI_FLAG_RISKY; battler = 3; } + PARAMETRIZE { aiFlags = AI_FLAG_WILL_SUICIDE; battler = 1; } + PARAMETRIZE { aiFlags = AI_FLAG_WILL_SUICIDE; battler = 3; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + BATTLER_AI_FLAGS(battler, aiFlags); + MULTI_PLAYER(SPECIES_WOBBUFFET) { HP(1); } + MULTI_PARTNER(SPECIES_WOBBUFFET) { HP(1); } + MULTI_OPPONENT_A(SPECIES_ELECTRODE) { Moves(MOVE_EXPLOSION, MOVE_ELECTRO_BALL); HP(1); } + MULTI_OPPONENT_B(SPECIES_VOLTORB) { Moves(MOVE_EXPLOSION, MOVE_ELECTRO_BALL); HP(1); } + } WHEN { + if (aiFlags == 0) + TURN { EXPECT_MOVE(opponentLeft, MOVE_ELECTRO_BALL, target: playerLeft); EXPECT_MOVE(opponentRight, MOVE_ELECTRO_BALL, target: playerLeft); } + else + TURN { EXPECT_MOVE(&gBattleMons[BATTLE_PARTNER(battler)], MOVE_ELECTRO_BALL, target: playerLeft); EXPECT_MOVE(&gBattleMons[battler], MOVE_EXPLOSION); } + } +} + +AI_ONE_VS_TWO_BATTLE_TEST("AI will only explode and kill everything on the field with Risky or Will Suicide (1v2)") +{ + ASSUME(GetMoveTarget(MOVE_EXPLOSION) == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); + + u32 aiFlags; + u32 battler; + + PARAMETRIZE { aiFlags = 0; battler = 1; } + PARAMETRIZE { aiFlags = 0; battler = 3; } + PARAMETRIZE { aiFlags = AI_FLAG_RISKY; battler = 3; } + PARAMETRIZE { aiFlags = AI_FLAG_RISKY; battler = 1; } + PARAMETRIZE { aiFlags = AI_FLAG_WILL_SUICIDE; battler = 1; } + PARAMETRIZE { aiFlags = AI_FLAG_WILL_SUICIDE; battler = 3; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + BATTLER_AI_FLAGS(battler, aiFlags); + MULTI_PLAYER(SPECIES_WOBBUFFET) { HP(1); } + MULTI_PLAYER(SPECIES_WOBBUFFET) { HP(1); } + MULTI_OPPONENT_A(SPECIES_ELECTRODE) { Moves(MOVE_EXPLOSION, MOVE_ELECTRO_BALL); HP(1); } + MULTI_OPPONENT_B(SPECIES_VOLTORB) { Moves(MOVE_EXPLOSION, MOVE_ELECTRO_BALL); HP(1); } + } WHEN { + if (aiFlags == 0) + TURN { EXPECT_MOVE(opponentLeft, MOVE_ELECTRO_BALL, target: playerLeft); EXPECT_MOVE(opponentRight, MOVE_ELECTRO_BALL, target: playerLeft); } + else + TURN { EXPECT_MOVE(&gBattleMons[BATTLE_PARTNER(battler)], MOVE_ELECTRO_BALL, target: playerLeft); EXPECT_MOVE(&gBattleMons[battler], MOVE_EXPLOSION); } + } +} + +// Used to test EXPECT_MOVE only on partner +AI_MULTI_BATTLE_TEST("AI partner makes sensible move selections in battle (multi)") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + MULTI_PLAYER(SPECIES_HAUNTER); + MULTI_PLAYER(SPECIES_RATTATA); + // No moves to damage opponents. + MULTI_PARTNER(SPECIES_GENGAR) { Moves(MOVE_SHADOW_BALL, MOVE_AURA_SPHERE); } + MULTI_OPPONENT_A(SPECIES_RATTATA) { Moves(MOVE_CELEBRATE); HP(1); } + MULTI_OPPONENT_B(SPECIES_KANGASKHAN) { Moves(MOVE_CELEBRATE); } + + } WHEN { + TURN { MOVE(playerLeft, MOVE_AURA_SPHERE, target:opponentRight); EXPECT_MOVE(playerRight, MOVE_AURA_SPHERE, target:opponentLeft); }; + } +} + +// Used to test EXPECT_MOVE only on partner +AI_TWO_VS_ONE_BATTLE_TEST("AI partner makes sensible move selections in battle (2v1)") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + MULTI_PLAYER(SPECIES_HAUNTER); + MULTI_PLAYER(SPECIES_RATTATA); + // No moves to damage opponents. + MULTI_PARTNER(SPECIES_GENGAR) { Moves(MOVE_SHADOW_BALL, MOVE_AURA_SPHERE); } + MULTI_OPPONENT_A(SPECIES_RATTATA) { Moves(MOVE_CELEBRATE); HP(1); } + MULTI_OPPONENT_A(SPECIES_KANGASKHAN) { Moves(MOVE_CELEBRATE); } + + } WHEN { + TURN { MOVE(playerLeft, MOVE_AURA_SPHERE, target:opponentRight); EXPECT_MOVE(playerRight, MOVE_AURA_SPHERE, target:opponentLeft); }; + } +} + +AI_TWO_VS_ONE_BATTLE_TEST("Battler 3 has Battler 1 AI flags set correctly (2v1)") +{ + ASSUME(GetMoveTarget(MOVE_EXPLOSION) == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); + + u32 aiFlags; + u32 battler; + + PARAMETRIZE { aiFlags = 0; battler = 1; } + PARAMETRIZE { aiFlags = 0; battler = 3; } + PARAMETRIZE { aiFlags = AI_FLAG_RISKY; battler = 1; } + PARAMETRIZE { aiFlags = AI_FLAG_RISKY; battler = 3; } + PARAMETRIZE { aiFlags = AI_FLAG_WILL_SUICIDE; battler = 1; } + PARAMETRIZE { aiFlags = AI_FLAG_WILL_SUICIDE; battler = 3; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + BATTLER_AI_FLAGS(battler, aiFlags); + MULTI_PLAYER(SPECIES_WOBBUFFET) { HP(1); } + MULTI_PARTNER(SPECIES_WOBBUFFET) { HP(1); } + MULTI_OPPONENT_A(SPECIES_VOLTORB) { Moves(MOVE_EXPLOSION, MOVE_ELECTRO_BALL); HP(1); } + MULTI_OPPONENT_A(SPECIES_ELECTRODE) { Moves(MOVE_EXPLOSION, MOVE_ELECTRO_BALL); HP(1); } + } WHEN { + if (aiFlags == 0 || battler == 3) + TURN { EXPECT_MOVE(opponentLeft, MOVE_ELECTRO_BALL, target: playerLeft); EXPECT_MOVE(opponentRight, MOVE_ELECTRO_BALL, target: playerLeft); } + else + TURN { EXPECT_MOVE(opponentLeft, MOVE_EXPLOSION, target: playerLeft); EXPECT_MOVE(opponentRight, MOVE_EXPLOSION); } + } +} diff --git a/test/battle/ai/ai_switching.c b/test/battle/ai/ai_switching.c index f531f07f4..f3c8cb610 100644 --- a/test/battle/ai/ai_switching.c +++ b/test/battle/ai/ai_switching.c @@ -40,6 +40,28 @@ AI_SINGLE_BATTLE_TEST("AI switches if Perish Song is about to kill") } } +AI_SINGLE_BATTLE_TEST("AI sees on-field player ability correctly and does not see previous Pokémon's ability after player uses a pivot move when choosing a post-KO switch") +{ + u32 testAbility; + PARAMETRIZE { testAbility = ABILITY_WATER_ABSORB; } + PARAMETRIZE { testAbility = ABILITY_VOLT_ABSORB; } + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_OMNISCIENT); + PLAYER(SPECIES_PIKACHU) {Level(100); Moves(MOVE_VOLT_SWITCH, MOVE_SPARKLY_SWIRL); Ability(ABILITY_LIGHTNING_ROD); }; + PLAYER(SPECIES_LANTURN) {Level(44); Moves(MOVE_SCALD); Ability(testAbility); }; + OPPONENT(SPECIES_SOBBLE) {Level(44); Moves(MOVE_SCRATCH); } + OPPONENT(SPECIES_BOMBIRDIER) {Level(42); Moves(MOVE_ROCK_SLIDE); } + OPPONENT(SPECIES_IRON_THORNS) {Level(43); Moves(MOVE_SUPERCELL_SLAM, MOVE_ICE_PUNCH); } + } WHEN { + TURN { + MOVE(player, MOVE_VOLT_SWITCH); + SEND_OUT(player, 1); + EXPECT_MOVE(opponent, MOVE_SCRATCH); + testAbility == ABILITY_WATER_ABSORB ? EXPECT_SEND_OUT(opponent, 2) : EXPECT_SEND_OUT(opponent, 1); + } + } +} + AI_DOUBLE_BATTLE_TEST("AI will not try to switch for the same Pokémon for 2 spots in a double battle (all bad moves)") { u32 flags; @@ -69,6 +91,250 @@ AI_DOUBLE_BATTLE_TEST("AI will not try to switch for the same Pokémon for 2 spo } } +// Used to test EXPECT_SWITCH only on partner +AI_MULTI_BATTLE_TEST("AI partner will not switch mid-turn into a player Pokémon (multi)") +{ + u32 flags; + + PARAMETRIZE {flags = AI_FLAG_SMART_SWITCHING; } + PARAMETRIZE {flags = 0; } + + PASSES_RANDOMLY(SHOULD_SWITCH_ALL_MOVES_BAD_PERCENTAGE, 100, RNG_AI_SWITCH_ALL_MOVES_BAD); + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | flags); + MULTI_PLAYER(SPECIES_HAUNTER); + MULTI_PLAYER(SPECIES_RATTATA); + // No moves to damage opponents. + MULTI_PARTNER(SPECIES_GENGAR) { Moves(MOVE_SHADOW_BALL); } + MULTI_PARTNER(SPECIES_GASTLY) { Moves(MOVE_LICK); } + MULTI_PARTNER(SPECIES_RATICATE) { Moves(MOVE_HEADBUTT); } + MULTI_OPPONENT_A(SPECIES_RATTATA) { Moves(MOVE_CELEBRATE); } + MULTI_OPPONENT_B(SPECIES_KANGASKHAN) { Moves(MOVE_CELEBRATE); } + + } WHEN { + TURN { EXPECT_SWITCH(playerRight, 5); }; + } SCENE { + MESSAGE(AI_PARTNER_NAME " withdrew Gengar!"); + MESSAGE(AI_PARTNER_NAME " sent out Raticate!"); + NONE_OF { + MESSAGE(AI_PARTNER_NAME " withdrew Gengar!"); + MESSAGE(AI_PARTNER_NAME " sent out Rattata!"); + } + } +} + +// Used to test EXPECT_SWITCH only on partner +AI_TWO_VS_ONE_BATTLE_TEST("AI partner will not switch mid-turn into a player Pokémon (2v1)") +{ + u32 flags; + + PARAMETRIZE {flags = AI_FLAG_SMART_SWITCHING; } + PARAMETRIZE {flags = 0; } + + PASSES_RANDOMLY(SHOULD_SWITCH_ALL_MOVES_BAD_PERCENTAGE, 100, RNG_AI_SWITCH_ALL_MOVES_BAD); + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | flags); + MULTI_PLAYER(SPECIES_HAUNTER); + MULTI_PLAYER(SPECIES_RATTATA); + // No moves to damage opponents. + MULTI_PARTNER(SPECIES_GENGAR) { Moves(MOVE_SHADOW_BALL); } + MULTI_PARTNER(SPECIES_GASTLY) { Moves(MOVE_LICK); } + MULTI_PARTNER(SPECIES_RATICATE) { Moves(MOVE_HEADBUTT); } + MULTI_OPPONENT_A(SPECIES_RATTATA) { Moves(MOVE_CELEBRATE); } + MULTI_OPPONENT_A(SPECIES_KANGASKHAN) { Moves(MOVE_CELEBRATE); } + + } WHEN { + TURN { EXPECT_SWITCH(playerRight, 5); }; + } SCENE { + MESSAGE(AI_PARTNER_NAME " withdrew Gengar!"); + MESSAGE(AI_PARTNER_NAME " sent out Raticate!"); + NONE_OF { + MESSAGE(AI_PARTNER_NAME " withdrew Gengar!"); + MESSAGE(AI_PARTNER_NAME " sent out Rattata!"); + } + } +} + +// Used to test EXPECT_SEND_OUT only on partner +AI_MULTI_BATTLE_TEST("AI partner will not switch into a player Pokémon after fainting (multi)") +{ + u32 flags; + + PARAMETRIZE {flags = AI_FLAG_SMART_SWITCHING; } + PARAMETRIZE {flags = 0; } + + PASSES_RANDOMLY(SHOULD_SWITCH_ALL_MOVES_BAD_PERCENTAGE, 100, RNG_AI_SWITCH_ALL_MOVES_BAD); + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | flags); + MULTI_PLAYER(SPECIES_GENGAR); + MULTI_PLAYER(SPECIES_RATTATA); + // No moves to damage opponents. + MULTI_PARTNER(SPECIES_WOBBUFFET) { Status1(STATUS1_BURN); HP(1); } + MULTI_PARTNER(SPECIES_GASTLY); + MULTI_PARTNER(SPECIES_HAUNTER); + MULTI_OPPONENT_A(SPECIES_TRAPINCH) { Ability(ABILITY_ARENA_TRAP); Moves(MOVE_CELEBRATE); } + MULTI_OPPONENT_B(SPECIES_VIBRAVA) { Moves(MOVE_CELEBRATE); } + + } WHEN { + TURN { EXPECT_MOVE(playerRight, MOVE_CELEBRATE); EXPECT_SEND_OUT(playerRight, 5); }; + } SCENE { + MESSAGE(AI_PARTNER_NAME " sent out Haunter!"); + NONE_OF { + MESSAGE(AI_PARTNER_NAME " sent out Rattata!"); + } + } +} + +// Used to test EXPECT_SEND_OUT only on partner +AI_TWO_VS_ONE_BATTLE_TEST("AI partner will not switch into a player Pokémon after fainting (2v1)") +{ + u32 flags; + + PARAMETRIZE {flags = AI_FLAG_SMART_SWITCHING; } + PARAMETRIZE {flags = 0; } + + PASSES_RANDOMLY(SHOULD_SWITCH_ALL_MOVES_BAD_PERCENTAGE, 100, RNG_AI_SWITCH_ALL_MOVES_BAD); + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | flags); + MULTI_PLAYER(SPECIES_GENGAR); + MULTI_PLAYER(SPECIES_RATTATA); + // No moves to damage opponents. + MULTI_PARTNER(SPECIES_WOBBUFFET) { Status1(STATUS1_BURN); HP(1); } + MULTI_PARTNER(SPECIES_GASTLY); + MULTI_PARTNER(SPECIES_HAUNTER); + MULTI_OPPONENT_A(SPECIES_TRAPINCH) { Ability(ABILITY_ARENA_TRAP); Moves(MOVE_CELEBRATE); } + MULTI_OPPONENT_A(SPECIES_VIBRAVA) { Moves(MOVE_CELEBRATE); } + + } WHEN { + TURN { EXPECT_MOVE(playerRight, MOVE_CELEBRATE); EXPECT_SEND_OUT(playerRight, 5); }; + } SCENE { + MESSAGE(AI_PARTNER_NAME " sent out Haunter!"); + NONE_OF { + MESSAGE(AI_PARTNER_NAME " sent out Rattata!"); + } + } +} + +// Used to test EXPECT_SWITCH, EXPECT_SEND_OUT, and EXPECT_MOVE on partner +AI_MULTI_BATTLE_TEST("AI partner will not switch into a player Pokémon (multi)") +{ + u32 flags; + + PARAMETRIZE {flags = AI_FLAG_SMART_SWITCHING; } + PARAMETRIZE {flags = 0; } + + PASSES_RANDOMLY(SHOULD_SWITCH_ALL_MOVES_BAD_PERCENTAGE, 100, RNG_AI_SWITCH_ALL_MOVES_BAD); + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | flags); + MULTI_PLAYER(SPECIES_HAUNTER); + MULTI_PLAYER(SPECIES_RATTATA); + // No moves to damage opponents. + MULTI_PARTNER(SPECIES_GENGAR) { Moves(MOVE_SHADOW_BALL); } + MULTI_PARTNER(SPECIES_RATICATE) { Moves(MOVE_HEADBUTT); HP(1); } + MULTI_OPPONENT_A(SPECIES_RATTATA) { Moves(MOVE_CELEBRATE); } + MULTI_OPPONENT_B(SPECIES_KANGASKHAN) { Moves(MOVE_CELEBRATE); } + + } WHEN { + TURN { MOVE(playerLeft, MOVE_AURA_SPHERE, target:playerRight); EXPECT_SWITCH(playerRight, 4); EXPECT_SEND_OUT(playerRight, 3); }; + TURN { EXPECT_MOVE(playerRight, MOVE_SHADOW_BALL, target:opponentLeft); }; + } SCENE { + MESSAGE(AI_PARTNER_NAME " sent out Raticate!"); + NONE_OF { + MESSAGE(AI_PARTNER_NAME " sent out Rattata!"); + } + } +} + +// Used to test EXPECT_SWITCH, EXPECT_SEND_OUT, and EXPECT_MOVE on partner +AI_TWO_VS_ONE_BATTLE_TEST("AI partner will not switch into a player Pokémon (2v1)") +{ + u32 flags; + + PARAMETRIZE {flags = AI_FLAG_SMART_SWITCHING; } + PARAMETRIZE {flags = 0; } + + PASSES_RANDOMLY(SHOULD_SWITCH_ALL_MOVES_BAD_PERCENTAGE, 100, RNG_AI_SWITCH_ALL_MOVES_BAD); + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | flags); + MULTI_PLAYER(SPECIES_HAUNTER); + MULTI_PLAYER(SPECIES_RATTATA); + // No moves to damage opponents. + MULTI_PARTNER(SPECIES_GENGAR) { Moves(MOVE_SHADOW_BALL); } + MULTI_PARTNER(SPECIES_RATICATE) { Moves(MOVE_HEADBUTT); HP(1); } + MULTI_OPPONENT_A(SPECIES_RATTATA) { Moves(MOVE_CELEBRATE); } + MULTI_OPPONENT_A(SPECIES_KANGASKHAN) { Moves(MOVE_CELEBRATE); } + + } WHEN { + TURN { MOVE(playerLeft, MOVE_AURA_SPHERE, target:playerRight); EXPECT_SWITCH(playerRight, 4); EXPECT_SEND_OUT(playerRight, 3); }; + TURN { EXPECT_MOVE(playerRight, MOVE_SHADOW_BALL, target:opponentLeft); }; + } SCENE { + MESSAGE(AI_PARTNER_NAME " sent out Raticate!"); + NONE_OF { + MESSAGE(AI_PARTNER_NAME " sent out Rattata!"); + } + } +} + +AI_TWO_VS_ONE_BATTLE_TEST("AI will not try to switch for the same pokemon for 2 spots in a 2v1 battle (all bad moves)") +{ + u32 flags; + + PARAMETRIZE {flags = AI_FLAG_SMART_SWITCHING; } + PARAMETRIZE {flags = 0; } + + PASSES_RANDOMLY(SHOULD_SWITCH_ALL_MOVES_BAD_PERCENTAGE, 100, RNG_AI_SWITCH_ALL_MOVES_BAD); + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | flags); + MULTI_PLAYER(SPECIES_RATTATA); + MULTI_PLAYER(SPECIES_RATTATA); + MULTI_PARTNER(SPECIES_KANGASKHAN); + // No moves to damage player. + MULTI_OPPONENT_A(SPECIES_GENGAR) { Moves(MOVE_SHADOW_BALL); } + MULTI_OPPONENT_A(SPECIES_HAUNTER) { Moves(MOVE_SHADOW_BALL); } + MULTI_OPPONENT_A(SPECIES_GASTLY) { Moves(MOVE_LICK); } + MULTI_OPPONENT_A(SPECIES_RATICATE) { Moves(MOVE_HEADBUTT); } + } WHEN { + TURN { EXPECT_SWITCH(opponentLeft, 3); }; + } SCENE { + MESSAGE(AI_TRAINER_NAME " withdrew Gengar!"); + MESSAGE(AI_TRAINER_NAME " sent out Raticate!"); + NONE_OF { + MESSAGE(AI_TRAINER_NAME " withdrew Haunter!"); + MESSAGE(AI_TRAINER_NAME " sent out Raticate!"); + } + } +} + +AI_ONE_VS_TWO_BATTLE_TEST("AI will not switch into a partner Pokémon in a 1v2 battle (all bad moves)") +{ + u32 flags; + + PARAMETRIZE {flags = AI_FLAG_SMART_SWITCHING; } + PARAMETRIZE {flags = 0; } + + PASSES_RANDOMLY(SHOULD_SWITCH_ALL_MOVES_BAD_PERCENTAGE, 100, RNG_AI_SWITCH_ALL_MOVES_BAD); + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | flags); + MULTI_PLAYER(SPECIES_RATTATA); + MULTI_PLAYER(SPECIES_KANGASKHAN); + // No moves to damage player. + MULTI_OPPONENT_A(SPECIES_HAUNTER) { Moves(MOVE_SHADOW_BALL); } + MULTI_OPPONENT_B(SPECIES_GENGAR) { Moves(MOVE_SHADOW_BALL); } + MULTI_OPPONENT_B(SPECIES_GASTLY) { Moves(MOVE_LICK); } + MULTI_OPPONENT_B(SPECIES_RATICATE) { Moves(MOVE_HEADBUTT); } + + } WHEN { + TURN { EXPECT_SWITCH(opponentRight, 5); }; + } SCENE { + MESSAGE(AI_TRAINER_2_NAME " withdrew Gengar!"); + MESSAGE(AI_TRAINER_2_NAME " sent out Raticate!"); + NONE_OF { + MESSAGE(AI_TRAINER_NAME " withdrew Haunter!"); + MESSAGE(AI_TRAINER_NAME " sent out Raticate!"); + } + } +} + AI_SINGLE_BATTLE_TEST("AI will switch out if it has no move that affects the player") { PASSES_RANDOMLY(SHOULD_SWITCH_ALL_MOVES_BAD_PERCENTAGE, 100, RNG_AI_SWITCH_ALL_MOVES_BAD); @@ -1400,3 +1666,20 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: Fake Out style moves won't confu TURN { MOVE(player, MOVE_SCRATCH); EXPECT_MOVE(opponent, MOVE_CLOSE_COMBAT); } } } + +AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: AI will consider choice-locked player priority when determining which mon to send out") +{ + u32 item; + PARAMETRIZE { item = ITEM_NONE; } + PARAMETRIZE { item = ITEM_CHOICE_BAND; } + GIVEN { + ASSUME(gItemsInfo[ITEM_CHOICE_BAND].holdEffect == HOLD_EFFECT_CHOICE_BAND); + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_OMNISCIENT); + PLAYER(SPECIES_LYCANROC) { Speed(5); Moves(MOVE_ACCELEROCK, MOVE_MIGHTY_CLEAVE); Item(item); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(4); HP(1); Moves(MOVE_TACKLE); } + OPPONENT(SPECIES_DECIDUEYE_HISUI) { Speed(4); Moves(MOVE_LEAF_BLADE); } + OPPONENT(SPECIES_PHEROMOSA) { Speed(6); HP(1); Moves(MOVE_EARTHQUAKE); } + } WHEN { + TURN { MOVE(player, MOVE_MIGHTY_CLEAVE); EXPECT_MOVE(opponent, MOVE_TACKLE); item == ITEM_NONE ? EXPECT_SEND_OUT(opponent, 1) : EXPECT_SEND_OUT(opponent, 2); } + } +} diff --git a/test/battle/ai/ai_trytofaint.c b/test/battle/ai/ai_trytofaint.c index a1a23efde..50ab37650 100644 --- a/test/battle/ai/ai_trytofaint.c +++ b/test/battle/ai/ai_trytofaint.c @@ -59,3 +59,17 @@ AI_SINGLE_BATTLE_TEST("AI sees Loaded Dice damage increase from multi hit moves" MESSAGE("Wobbuffet fainted!"); } } + +AI_SINGLE_BATTLE_TEST("AI sees Parental Bond killing through sturdy") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY); + PLAYER(SPECIES_MAGNEZONE){Level(64); Ability(ABILITY_STURDY); Moves(MOVE_TACKLE, MOVE_LIGHT_SCREEN); } + OPPONENT(SPECIES_KANGASKHAN_MEGA){Level(64); Moves(MOVE_DRAIN_PUNCH, MOVE_TAUNT); } + } WHEN { + TURN{ MOVE(player, MOVE_TACKLE); + EXPECT_MOVE(opponent, MOVE_DRAIN_PUNCH); // AI should see drain punch as a kill due to multi hit, outscoring taunt + } + } +} + diff --git a/test/battle/badge_boost.c b/test/battle/badge_boost.c new file mode 100644 index 000000000..eb8cecb24 --- /dev/null +++ b/test/battle/badge_boost.c @@ -0,0 +1,166 @@ +#include "global.h" +#include "event_data.h" +#include "test/battle.h" + +WILD_BATTLE_TEST("Badge boost: B_FLAG_BADGE_BOOST_ATTACK boost Attack", s16 dmg) +{ + u32 badge = 0; + u32 genConfig = 0; + for (u32 gen = GEN_1; gen <= GEN_LATEST; gen++) + { + PARAMETRIZE{badge = FALSE; genConfig = gen;} + PARAMETRIZE{badge = TRUE; genConfig = gen;} + } + GIVEN { + if (badge) + FlagSet(B_FLAG_BADGE_BOOST_ATTACK); + else + FlagClear(B_FLAG_BADGE_BOOST_ATTACK); + WITH_CONFIG(GEN_CONFIG_BADGE_BOOST, genConfig); + PLAYER(SPECIES_WOBBUFFET) {} + OPPONENT(SPECIES_WOBBUFFET) {} + } WHEN { + TURN { MOVE(player, MOVE_SCRATCH); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].dmg); + } FINALLY { + for (u32 gen = GEN_1; gen <= GEN_LATEST; gen++) + { + if (gen <= GEN_3) + EXPECT_GT(results[2 * gen + 1].dmg, results[2 * gen].dmg); + else + EXPECT_EQ(results[2 * gen + 1].dmg, results[2 * gen].dmg); + } + } +} + +WILD_BATTLE_TEST("Badge boost: B_FLAG_BADGE_BOOST_SPATK boost Special Attack", s16 dmg) +{ + u32 badge = 0; + u32 genConfig = 0; + for (u32 gen = GEN_1; gen <= GEN_LATEST; gen++) + { + PARAMETRIZE{badge = FALSE; genConfig = gen;} + PARAMETRIZE{badge = TRUE; genConfig = gen;} + } + GIVEN { + if (badge) + FlagSet(B_FLAG_BADGE_BOOST_SPATK); + else + FlagClear(B_FLAG_BADGE_BOOST_SPATK); + WITH_CONFIG(GEN_CONFIG_BADGE_BOOST, genConfig); + PLAYER(SPECIES_WOBBUFFET) {} + OPPONENT(SPECIES_WOBBUFFET) {} + } WHEN { + TURN { MOVE(player, MOVE_THUNDER_SHOCK); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].dmg); + } FINALLY { + for (u32 gen = GEN_1; gen <= GEN_LATEST; gen++) + { + if (gen <= GEN_3) + EXPECT_GT(results[2 * gen + 1].dmg, results[2 * gen].dmg); + else + EXPECT_EQ(results[2 * gen + 1].dmg, results[2 * gen].dmg); + } + } +} + +WILD_BATTLE_TEST("Badge boost: B_FLAG_BADGE_BOOST_DEFENSE boost Defense", s16 dmg) +{ + u32 badge = 0; + u32 genConfig = 0; + for (u32 gen = GEN_1; gen <= GEN_LATEST; gen++) + { + PARAMETRIZE{badge = FALSE; genConfig = gen;} + PARAMETRIZE{badge = TRUE; genConfig = gen;} + } + + GIVEN { + if (badge) + FlagSet(B_FLAG_BADGE_BOOST_DEFENSE); + else + FlagClear(B_FLAG_BADGE_BOOST_DEFENSE); + WITH_CONFIG(GEN_CONFIG_BADGE_BOOST, genConfig); + PLAYER(SPECIES_WOBBUFFET) {} + OPPONENT(SPECIES_WOBBUFFET) {} + } WHEN { + TURN { MOVE(opponent, MOVE_SCRATCH); } + } SCENE { + HP_BAR(player, captureDamage: &results[i].dmg); + } FINALLY { + for (u32 gen = GEN_1; gen <= GEN_LATEST; gen++) + { + if (gen <= GEN_3) + EXPECT_LT(results[2 * gen + 1].dmg, results[2 * gen].dmg); + else + EXPECT_EQ(results[2 * gen + 1].dmg, results[2 * gen].dmg); + } + } +} + +WILD_BATTLE_TEST("Badge boost: B_FLAG_BADGE_BOOST_SPDEF boost Special Defense", s16 dmg) +{ + u32 badge = 0; + u32 genConfig = 0; + for (u32 gen = GEN_1; gen <= GEN_LATEST; gen++) + { + PARAMETRIZE{badge = FALSE; genConfig = gen;} + PARAMETRIZE{badge = TRUE; genConfig = gen;} + } + + GIVEN { + if (badge) + FlagSet(B_FLAG_BADGE_BOOST_SPDEF); + else + FlagClear(B_FLAG_BADGE_BOOST_SPDEF); + WITH_CONFIG(GEN_CONFIG_BADGE_BOOST, genConfig); + PLAYER(SPECIES_WOBBUFFET) {} + OPPONENT(SPECIES_WOBBUFFET) {} + } WHEN { + TURN { MOVE(opponent, MOVE_THUNDER_SHOCK); } + } SCENE { + HP_BAR(player, captureDamage: &results[i].dmg); + } FINALLY { + for (u32 gen = GEN_1; gen <= GEN_LATEST; gen++) + { + if (gen <= GEN_3) + EXPECT_LT(results[2 * gen + 1].dmg, results[2 * gen].dmg); + else + EXPECT_EQ(results[2 * gen + 1].dmg, results[2 * gen].dmg); + } + } +} + +WILD_BATTLE_TEST("Badge boost: B_FLAG_BADGE_BOOST_SPEED boost Speed", s16 dmg) +{ + u32 badge = 0; + u32 genConfig = 0; + for (u32 gen = GEN_1; gen <= GEN_LATEST; gen++) + { + PARAMETRIZE{badge = FALSE; genConfig = gen;} + PARAMETRIZE{badge = TRUE; genConfig = gen;} + } + GIVEN { + if (badge) + FlagSet(B_FLAG_BADGE_BOOST_SPEED); + else + FlagClear(B_FLAG_BADGE_BOOST_SPEED); + WITH_CONFIG(GEN_CONFIG_BADGE_BOOST, genConfig); + PLAYER(SPECIES_WOBBUFFET) { Speed(100); HP(1); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(101); HP(1); } + } WHEN { + TURN { MOVE(player, MOVE_SCRATCH); MOVE(opponent, MOVE_SCRATCH);} + } THEN { + if (badge && genConfig <= GEN_3) + { + EXPECT_EQ(opponent->hp, 0); + EXPECT_EQ(player->hp, 1); + } + else + { + EXPECT_EQ(opponent->hp, 1); + EXPECT_EQ(player->hp, 0); + } + } +} diff --git a/test/battle/damage_formula.c b/test/battle/damage_formula.c index f41f6a214..702feaa83 100644 --- a/test/battle/damage_formula.c +++ b/test/battle/damage_formula.c @@ -101,6 +101,7 @@ SINGLE_BATTLE_TEST("Damage calculation matches Gen5+ (Marshadow vs Mawile)") PARAMETRIZE { expectedDamage = 123; } GIVEN { ASSUME(GetMoveCategory(MOVE_SPECTRAL_THIEF) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(B_UPDATED_TYPE_MATCHUPS >= GEN_6); // Steel resists Ghost in Gen2-5 PLAYER(SPECIES_MARSHADOW) { Level(100); Attack(286); } OPPONENT(SPECIES_MAWILE) { Level(100); Defense(226); HP(241); } } WHEN { @@ -117,7 +118,7 @@ SINGLE_BATTLE_TEST("Damage calculation matches Gen5+ (Marshadow vs Mawile)") } } -DOUBLE_BATTLE_TEST("A spread move will do correct damage to the second mon if the first target faints from first hit of the spread move") +DOUBLE_BATTLE_TEST("A spread move will do correct damage to the second mon if the first target faints from first hit of the spread move (double battle)") { s16 damage[6]; GIVEN { @@ -151,6 +152,108 @@ DOUBLE_BATTLE_TEST("A spread move will do correct damage to the second mon if th } } +MULTI_BATTLE_TEST("A spread move will do correct damage to the second mon if the first target faints from first hit of the spread move (multibattle)") +{ + s16 damage[6]; + GIVEN { + MULTI_PLAYER(SPECIES_REGIROCK); + MULTI_PARTNER(SPECIES_REGIROCK); + MULTI_OPPONENT_A(SPECIES_WOBBUFFET) { HP(200); } + MULTI_OPPONENT_B(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_ROCK_SLIDE); } + TURN { MOVE(playerLeft, MOVE_ROCK_SLIDE); MOVE(playerRight, MOVE_ROCK_SLIDE); } + TURN { MOVE(playerLeft, MOVE_ROCK_SLIDE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROCK_SLIDE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[0]); + HP_BAR(opponentRight, captureDamage: &damage[1]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROCK_SLIDE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[2]); + HP_BAR(opponentRight, captureDamage: &damage[3]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROCK_SLIDE, playerRight); + HP_BAR(opponentRight, captureDamage: &damage[4]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROCK_SLIDE, playerLeft); + HP_BAR(opponentRight, captureDamage: &damage[5]); + } THEN { + EXPECT_EQ(damage[0], damage[1]); + EXPECT_EQ(damage[1], damage[3]); + EXPECT_MUL_EQ(damage[5], UQ_4_12(0.75), damage[3]); + EXPECT_EQ(damage[4], damage[5]); + } +} + +TWO_VS_ONE_BATTLE_TEST("A spread move will do correct damage to the second mon if the first target faints from first hit of the spread move (2v1)") +{ + s16 damage[6]; + GIVEN { + MULTI_PLAYER(SPECIES_REGIROCK); + MULTI_PARTNER(SPECIES_REGIROCK); + MULTI_OPPONENT_A(SPECIES_WOBBUFFET) { HP(200); } + MULTI_OPPONENT_A(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_ROCK_SLIDE); } + TURN { MOVE(playerLeft, MOVE_ROCK_SLIDE); MOVE(playerRight, MOVE_ROCK_SLIDE); } + TURN { MOVE(playerLeft, MOVE_ROCK_SLIDE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROCK_SLIDE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[0]); + HP_BAR(opponentRight, captureDamage: &damage[1]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROCK_SLIDE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[2]); + HP_BAR(opponentRight, captureDamage: &damage[3]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROCK_SLIDE, playerRight); + HP_BAR(opponentRight, captureDamage: &damage[4]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROCK_SLIDE, playerLeft); + HP_BAR(opponentRight, captureDamage: &damage[5]); + } THEN { + EXPECT_EQ(damage[0], damage[1]); + EXPECT_EQ(damage[1], damage[3]); + EXPECT_MUL_EQ(damage[5], UQ_4_12(0.75), damage[3]); + EXPECT_EQ(damage[4], damage[5]); + } +} + +ONE_VS_TWO_BATTLE_TEST("A spread move will do correct damage to the second mon if the first target faints from first hit of the spread move (1v2)") +{ + s16 damage[6]; + GIVEN { + MULTI_PLAYER(SPECIES_REGIROCK); + MULTI_PLAYER(SPECIES_REGIROCK); + MULTI_OPPONENT_A(SPECIES_WOBBUFFET) { HP(200); } + MULTI_OPPONENT_B(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_ROCK_SLIDE); } + TURN { MOVE(playerLeft, MOVE_ROCK_SLIDE); MOVE(playerRight, MOVE_ROCK_SLIDE); } + TURN { MOVE(playerLeft, MOVE_ROCK_SLIDE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROCK_SLIDE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[0]); + HP_BAR(opponentRight, captureDamage: &damage[1]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROCK_SLIDE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[2]); + HP_BAR(opponentRight, captureDamage: &damage[3]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROCK_SLIDE, playerRight); + HP_BAR(opponentRight, captureDamage: &damage[4]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROCK_SLIDE, playerLeft); + HP_BAR(opponentRight, captureDamage: &damage[5]); + } THEN { + EXPECT_EQ(damage[0], damage[1]); + EXPECT_EQ(damage[1], damage[3]); + EXPECT_MUL_EQ(damage[5], UQ_4_12(0.75), damage[3]); + EXPECT_EQ(damage[4], damage[5]); + } +} + SINGLE_BATTLE_TEST("Punching Glove vs Muscle Band Damage calculation") { s16 dmgPlayer, dmgOpponent; @@ -196,6 +299,7 @@ SINGLE_BATTLE_TEST("Gem boosted Damage calculation") { s16 dmg; s16 expectedDamage; +#if I_GEM_BOOST_POWER >= GEN_6 PARAMETRIZE { expectedDamage = 240; } PARAMETRIZE { expectedDamage = 237; } PARAMETRIZE { expectedDamage = 234; } @@ -212,6 +316,25 @@ SINGLE_BATTLE_TEST("Gem boosted Damage calculation") PARAMETRIZE { expectedDamage = 208; } PARAMETRIZE { expectedDamage = 205; } PARAMETRIZE { expectedDamage = 204; } +#else + KNOWN_FAILING; + PARAMETRIZE { expectedDamage = 273; } + PARAMETRIZE { expectedDamage = 270; } + PARAMETRIZE { expectedDamage = 267; } + PARAMETRIZE { expectedDamage = 264; } + PARAMETRIZE { expectedDamage = 261; } + PARAMETRIZE { expectedDamage = 258; } + PARAMETRIZE { expectedDamage = 256; } + PARAMETRIZE { expectedDamage = 253; } + PARAMETRIZE { expectedDamage = 250; } + PARAMETRIZE { expectedDamage = 247; } + PARAMETRIZE { expectedDamage = 244; } + PARAMETRIZE { expectedDamage = 241; } + PARAMETRIZE { expectedDamage = 240; } + PARAMETRIZE { expectedDamage = 237; } + PARAMETRIZE { expectedDamage = 234; } + PARAMETRIZE { expectedDamage = 231; } +#endif GIVEN { PLAYER(SPECIES_MAKUHITA) { Item(ITEM_FIGHTING_GEM); } OPPONENT(SPECIES_MAKUHITA); diff --git a/test/battle/end_turn_effects.c b/test/battle/end_turn_effects.c index 51aa1e79b..95ae96889 100644 --- a/test/battle/end_turn_effects.c +++ b/test/battle/end_turn_effects.c @@ -1,7 +1,7 @@ #include "global.h" #include "test/battle.h" -DOUBLE_BATTLE_TEST("End Turn Effects: First Event Block is executed correctly") +DOUBLE_BATTLE_TEST("End Turn Effects: First Event Block is executed correctly (double battle)") { s16 healed; s16 damage; @@ -29,3 +29,90 @@ DOUBLE_BATTLE_TEST("End Turn Effects: First Event Block is executed correctly") } } + +MULTI_BATTLE_TEST("End Turn Effects: First Event Block is executed correctly (multibattle)") +{ + s16 healed; + s16 damage; + + GIVEN { + MULTI_PLAYER(SPECIES_WYNAUT) { HP(100); Speed(1); } + MULTI_PARTNER(SPECIES_EKANS) { HP(100); Ability(ABILITY_SHED_SKIN); Status1(STATUS1_BURN); Speed(2); } + MULTI_OPPONENT_A(SPECIES_WYNAUT) { HP(100); Item(ITEM_LEFTOVERS); Speed(3); } + MULTI_OPPONENT_B(SPECIES_WOBBUFFET) { HP(100); Item(ITEM_BLACK_SLUDGE); Speed(4); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_GRASSY_TERRAIN); } + } SCENE { + MESSAGE("The opposing Wobbuffet is healed by the grassy terrain!"); + HP_BAR(opponentRight, captureDamage: &healed); + HP_BAR(opponentRight, captureDamage: &damage); + MESSAGE("The opposing Wobbuffet was hurt by the Black Sludge!"); + MESSAGE("The opposing Wynaut is healed by the grassy terrain!"); + MESSAGE("The opposing Wynaut restored a little HP using its Leftovers!"); + MESSAGE("Ekans is healed by the grassy terrain!"); + MESSAGE("Ekans's Shed Skin cured its burn problem!"); + MESSAGE("Wynaut is healed by the grassy terrain!"); + } THEN { + EXPECT_GT(0, healed); + EXPECT_GT(damage, 0); + } +} + + +TWO_VS_ONE_BATTLE_TEST("End Turn Effects: First Event Block is executed correctly (2v1)") +{ + s16 healed; + s16 damage; + + GIVEN { + MULTI_PLAYER(SPECIES_WYNAUT) { HP(100); Speed(1);} + MULTI_PARTNER(SPECIES_EKANS) { HP(100); Ability(ABILITY_SHED_SKIN); Status1(STATUS1_BURN); Speed(2); } + MULTI_OPPONENT_A(SPECIES_WYNAUT) { HP(100); Item(ITEM_LEFTOVERS); Speed(3); } + MULTI_OPPONENT_A(SPECIES_WOBBUFFET) { HP(100); Item(ITEM_BLACK_SLUDGE); Speed(4); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_GRASSY_TERRAIN); } + } SCENE { + MESSAGE("The opposing Wobbuffet is healed by the grassy terrain!"); + HP_BAR(opponentRight, captureDamage: &healed); + HP_BAR(opponentRight, captureDamage: &damage); + MESSAGE("The opposing Wobbuffet was hurt by the Black Sludge!"); + MESSAGE("The opposing Wynaut is healed by the grassy terrain!"); + MESSAGE("The opposing Wynaut restored a little HP using its Leftovers!"); + MESSAGE("Ekans is healed by the grassy terrain!"); + MESSAGE("Ekans's Shed Skin cured its burn problem!"); + MESSAGE("Wynaut is healed by the grassy terrain!"); + } THEN { + EXPECT_GT(0, healed); + EXPECT_GT(damage, 0); + } +} + + +ONE_VS_TWO_BATTLE_TEST("End Turn Effects: First Event Block is executed correctly (1v2)") +{ + s16 healed; + s16 damage; + + GIVEN { + MULTI_PLAYER(SPECIES_WYNAUT) { HP(100); Speed(1);} + MULTI_PLAYER(SPECIES_EKANS) { HP(100); Ability(ABILITY_SHED_SKIN); Status1(STATUS1_BURN); Speed(2); } + MULTI_OPPONENT_A(SPECIES_WYNAUT) { HP(100); Item(ITEM_LEFTOVERS); Speed(3); } + MULTI_OPPONENT_B(SPECIES_WOBBUFFET) { HP(100); Item(ITEM_BLACK_SLUDGE); Speed(4); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_GRASSY_TERRAIN); } + } SCENE { + MESSAGE("The opposing Wobbuffet is healed by the grassy terrain!"); + HP_BAR(opponentRight, captureDamage: &healed); + HP_BAR(opponentRight, captureDamage: &damage); + MESSAGE("The opposing Wobbuffet was hurt by the Black Sludge!"); + MESSAGE("The opposing Wynaut is healed by the grassy terrain!"); + MESSAGE("The opposing Wynaut restored a little HP using its Leftovers!"); + MESSAGE("Ekans is healed by the grassy terrain!"); + MESSAGE("Ekans's Shed Skin cured its burn problem!"); + MESSAGE("Wynaut is healed by the grassy terrain!"); + } THEN { + EXPECT_GT(0, healed); + EXPECT_GT(damage, 0); + } +} + diff --git a/test/battle/form_change/faint.c b/test/battle/form_change/faint.c index 8fc95cdc6..316ecca0b 100644 --- a/test/battle/form_change/faint.c +++ b/test/battle/form_change/faint.c @@ -1,9 +1,24 @@ #include "global.h" #include "test/battle.h" -SINGLE_BATTLE_TEST("Aegislash reverts to Shield Form upon fainting") +SINGLE_BATTLE_TEST("Aegislash reverts to Shield Form upon fainting (start as Shield)") +{ + GIVEN { + PLAYER(SPECIES_AEGISLASH_SHIELD) { HP(1); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_SCRATCH); MOVE(opponent, MOVE_GUST); SEND_OUT(player, 1); } + } SCENE { + MESSAGE("The opposing Wobbuffet used Gust!"); + MESSAGE("Aegislash fainted!"); + } THEN { + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPECIES), SPECIES_AEGISLASH_SHIELD); + } +} + +SINGLE_BATTLE_TEST("Aegislash reverts to Shield Form upon fainting (start as Blade)") { - KNOWN_FAILING; GIVEN { PLAYER(SPECIES_AEGISLASH_BLADE) { HP(1); } PLAYER(SPECIES_WOBBUFFET); @@ -14,7 +29,7 @@ SINGLE_BATTLE_TEST("Aegislash reverts to Shield Form upon fainting") MESSAGE("The opposing Wobbuffet used Gust!"); MESSAGE("Aegislash fainted!"); } THEN { - EXPECT_EQ(GetMonData(&PLAYER_PARTY[0], MON_DATA_SPECIES), SPECIES_AEGISLASH_SHIELD); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPECIES), SPECIES_AEGISLASH_SHIELD); } } diff --git a/test/battle/form_change/mega_evolution.c b/test/battle/form_change/mega_evolution.c index 8cce1a084..3e27a8460 100644 --- a/test/battle/form_change/mega_evolution.c +++ b/test/battle/form_change/mega_evolution.c @@ -75,10 +75,10 @@ SINGLE_BATTLE_TEST("Mega Evolution doesn't affect turn order (Gen6)") { GIVEN { WITH_CONFIG(GEN_CONFIG_MEGA_EVO_TURN_ORDER, GEN_6); - PLAYER(SPECIES_GARDEVOIR) { Item(ITEM_GARDEVOIRITE); Speed(105); } - OPPONENT(SPECIES_WOBBUFFET) { Speed(106); } + PLAYER(SPECIES_GARDEVOIR) { Item(ITEM_GARDEVOIRITE); } + OPPONENT(SPECIES_WOBBUFFET) {} } WHEN { - TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } + TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } } SCENE { MESSAGE("The opposing Wobbuffet used Celebrate!"); MESSAGE("Gardevoir used Celebrate!"); @@ -91,10 +91,10 @@ SINGLE_BATTLE_TEST("Mega Evolution affects turn order (Gen7+)") { GIVEN { WITH_CONFIG(GEN_CONFIG_MEGA_EVO_TURN_ORDER, GEN_7); - PLAYER(SPECIES_GARDEVOIR) { Item(ITEM_GARDEVOIRITE); Speed(105); } - OPPONENT(SPECIES_WOBBUFFET) { Speed(106); } + PLAYER(SPECIES_GARDEVOIR) { Item(ITEM_GARDEVOIRITE);} + OPPONENT(SPECIES_WOBBUFFET) {} } WHEN { - TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } + TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } } SCENE { MESSAGE("Gardevoir used Celebrate!"); MESSAGE("The opposing Wobbuffet used Celebrate!"); @@ -117,7 +117,7 @@ SINGLE_BATTLE_TEST("Abilities replaced by Mega Evolution do not affect turn orde MESSAGE("Sableye used Celebrate!"); MESSAGE("The opposing Wobbuffet used Celebrate!"); } THEN { - ASSUME(player->speed == 45); + ASSUME(player->speed == 105); } } diff --git a/test/battle/form_change/ultra_burst.c b/test/battle/form_change/ultra_burst.c index 9d7ec1c39..4b1bf6a8e 100644 --- a/test/battle/form_change/ultra_burst.c +++ b/test/battle/form_change/ultra_burst.c @@ -59,10 +59,10 @@ SINGLE_BATTLE_TEST("Ultra Burst affects turn order") { GIVEN { WITH_CONFIG(GEN_CONFIG_MEGA_EVO_TURN_ORDER, GEN_7); - PLAYER(SPECIES_NECROZMA_DUSK_MANE) { Item(ITEM_ULTRANECROZIUM_Z); Speed(105); } - OPPONENT(SPECIES_WOBBUFFET) { Speed(106); } + PLAYER(SPECIES_NECROZMA_DUSK_MANE) { Item(ITEM_ULTRANECROZIUM_Z);} + OPPONENT(SPECIES_WOBBUFFET) {} } WHEN { - TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_ULTRA_BURST); } + TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_ULTRA_BURST); } } SCENE { MESSAGE("Necrozma used Celebrate!"); MESSAGE("The opposing Wobbuffet used Celebrate!"); diff --git a/test/battle/gimmick/dynamax.c b/test/battle/gimmick/dynamax.c index a80f644d5..d97fb20f0 100644 --- a/test/battle/gimmick/dynamax.c +++ b/test/battle/gimmick/dynamax.c @@ -239,8 +239,8 @@ SINGLE_BATTLE_TEST("Dynamax: Dynamaxed Pokemon are affected by Grudge") } SCENE { MESSAGE("The opposing Wobbuffet used Grudge!"); MESSAGE("Wobbuffet used Max Strike!"); - MESSAGE("Wobbuffet's Scratch lost all its PP due to the grudge!"); MESSAGE("The opposing Wobbuffet fainted!"); + MESSAGE("Wobbuffet's Scratch lost all its PP due to the grudge!"); } } @@ -860,7 +860,7 @@ SINGLE_BATTLE_TEST("Dynamax: Max Hailstorm sets up hail") MESSAGE("It started to hail!"); MESSAGE("The opposing Wobbuffet used Celebrate!"); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HAIL_CONTINUES); -#endif +#endif } } @@ -1464,7 +1464,7 @@ DOUBLE_BATTLE_TEST("Dynamax: G-Max Chi Strike boosts allies' crit chance by 1 st { u32 j; GIVEN { - ASSUME(B_CRIT_CHANCE >= GEN_6); + WITH_CONFIG(GEN_CONFIG_CRIT_CHANCE, GEN_6); ASSUME(MoveHasAdditionalEffect(MOVE_G_MAX_CHI_STRIKE, MOVE_EFFECT_CRIT_PLUS_SIDE)); PLAYER(SPECIES_MACHAMP) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_MACHOP); diff --git a/test/battle/gimmick/terastal.c b/test/battle/gimmick/terastal.c index 56416663f..56adddee1 100644 --- a/test/battle/gimmick/terastal.c +++ b/test/battle/gimmick/terastal.c @@ -606,14 +606,14 @@ SINGLE_BATTLE_TEST("(TERA) Terastallizing into the Stellar type boosts all moves s16 damage[4]; GIVEN { ASSUME(GetMovePower(MOVE_MEGA_DRAIN) == 40); - ASSUME(GetMovePower(MOVE_BUBBLE) == 40); + ASSUME(GetMovePower(MOVE_WATER_GUN) == 40); PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_STELLAR); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { TURN { MOVE(player, MOVE_MEGA_DRAIN); } TURN { MOVE(player, MOVE_MEGA_DRAIN, gimmick: GIMMICK_TERA); } TURN { MOVE(player, MOVE_MEGA_DRAIN); } - TURN { MOVE(player, MOVE_BUBBLE); } + TURN { MOVE(player, MOVE_WATER_GUN); } } SCENE { // turn 1 MESSAGE("Wobbuffet used Mega Drain!"); @@ -628,8 +628,8 @@ SINGLE_BATTLE_TEST("(TERA) Terastallizing into the Stellar type boosts all moves ANIMATION(ANIM_TYPE_MOVE, MOVE_MEGA_DRAIN, player); HP_BAR(opponent, captureDamage: &damage[2]); // turn 4 - MESSAGE("Wobbuffet used Bubble!"); - ANIMATION(ANIM_TYPE_MOVE, MOVE_BUBBLE, player); + MESSAGE("Wobbuffet used Water Gun!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, player); HP_BAR(opponent, captureDamage: &damage[3]); } THEN { // The jump from 40 BP to 72 BP (60 * 1.2x) is a 1.8x boost. @@ -822,7 +822,7 @@ SINGLE_BATTLE_TEST("(TERA) Pokemon with Tera forms change upon Terastallizing") SINGLE_BATTLE_TEST("(TERA) All type indicators function correctly") { - u32 type; + enum Type type; PARAMETRIZE { type = TYPE_NONE; } PARAMETRIZE { type = TYPE_NORMAL; } PARAMETRIZE { type = TYPE_FIGHTING; } @@ -854,7 +854,7 @@ SINGLE_BATTLE_TEST("(TERA) All type indicators function correctly") SINGLE_BATTLE_TEST("(TERA) All type indicators function correctly - Opponent") { - u32 type; + enum Type type; PARAMETRIZE { type = TYPE_NONE; } PARAMETRIZE { type = TYPE_NORMAL; } PARAMETRIZE { type = TYPE_FIGHTING; } diff --git a/test/battle/gimmick/zmove.c b/test/battle/gimmick/zmove.c index 2495ec0b6..29538891e 100644 --- a/test/battle/gimmick/zmove.c +++ b/test/battle/gimmick/zmove.c @@ -579,7 +579,7 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Extreme Evoboost boosts all the user's stats by two SINGLE_BATTLE_TEST("(Z-MOVE) Genesis Supernova sets up psychic terrain") { GIVEN { - ASSUME(GetMoveEffect(MOVE_GENESIS_SUPERNOVA) == EFFECT_HIT_SET_TERRAIN); + ASSUME(MoveHasAdditionalEffect(MOVE_GENESIS_SUPERNOVA, MOVE_EFFECT_PSYCHIC_TERRAIN)); PLAYER(SPECIES_MEW) { Item(ITEM_MEWNIUM_Z); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/hazards.c b/test/battle/hazards.c index 9c974bb7b..ea0aef70e 100644 --- a/test/battle/hazards.c +++ b/test/battle/hazards.c @@ -38,3 +38,136 @@ SINGLE_BATTLE_TEST("Hazards are applied based on order of set up") EXPECT_EQ(gBattleStruct->hazardsQueue[0][5], HAZARDS_NONE); } } + +SINGLE_BATTLE_TEST("Hazards are applied correctly after a battler faints") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_FINAL_GAMBIT) == EFFECT_FINAL_GAMBIT); + PLAYER(SPECIES_WYNAUT); + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_STEALTH_ROCK); + MOVE(player, MOVE_FINAL_GAMBIT); + SEND_OUT(player, 1); + SEND_OUT(player, 2); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_FINAL_GAMBIT, player); + MESSAGE("Wynaut fainted!"); + MESSAGE("Pointed stones dug into Wobbuffet!"); + MESSAGE("Wobbuffet fainted!"); + MESSAGE("Pointed stones dug into Wynaut!"); + } +} + +SINGLE_BATTLE_TEST("Toxic Spikes can be removed after fainting to other hazards") +{ + KNOWN_FAILING; // tryfaintmon changes something that doesn't allow other switch-in effects on the battler + + GIVEN { + PLAYER(SPECIES_WYNAUT); + PLAYER(SPECIES_GRIMER) { HP(1); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_STEALTH_ROCK); } + TURN { MOVE(opponent, MOVE_TOXIC_SPIKES); } + TURN { MOVE(opponent, MOVE_STICKY_WEB); } + TURN { MOVE(opponent, MOVE_SPIKES); } + TURN { MOVE(opponent, MOVE_STEALTH_ROCK); SWITCH(player, 1); SEND_OUT(player, 0); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC_SPIKES, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SPIKES, opponent); + MESSAGE("Pointed stones dug into Grimer!"); + MESSAGE("Grimer fainted!"); + MESSAGE("The poison spikes disappeared from the ground around your team!"); + NONE_OF { + MESSAGE("Grimer was caught in a sticky web!"); + MESSAGE("Grimer was hurt by the spikes!"); + } + } THEN { + EXPECT_EQ(gBattleStruct->hazardsQueue[0][0], HAZARDS_STEALTH_ROCK); + EXPECT_EQ(gBattleStruct->hazardsQueue[0][1], HAZARDS_STICKY_WEB); + EXPECT_EQ(gBattleStruct->hazardsQueue[0][2], HAZARDS_SPIKES); + EXPECT_EQ(gBattleStruct->hazardsQueue[0][3], HAZARDS_NONE); + EXPECT_EQ(gBattleStruct->hazardsQueue[0][4], HAZARDS_NONE); + EXPECT_EQ(gBattleStruct->hazardsQueue[0][5], HAZARDS_NONE); + } +} + +SINGLE_BATTLE_TEST("Hazards can trigger Emergency Exit and other hazards don't activate") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_GOLISOPOD) { HP(105); MaxHP(200); Ability(ABILITY_EMERGENCY_EXIT); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_STEALTH_ROCK); } + TURN { MOVE(opponent, MOVE_TOXIC_SPIKES); } + TURN { MOVE(opponent, MOVE_STICKY_WEB); } + TURN { MOVE(opponent, MOVE_SPIKES); } + TURN { MOVE(opponent, MOVE_STEALTH_ROCK); SWITCH(player, 1); SEND_OUT(player, 0); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC_SPIKES, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SPIKES, opponent); + MESSAGE("Pointed stones dug into Golisopod!"); + ABILITY_POPUP(player, ABILITY_EMERGENCY_EXIT); + NONE_OF { + MESSAGE("Golisopod was poisoned!"); + MESSAGE("Golisopod was caught in a sticky web!"); + MESSAGE("Golisopod was hurt by the spikes!"); + } + MESSAGE("Pointed stones dug into Wobbuffet!"); + MESSAGE("Wobbuffet was poisoned!"); + MESSAGE("Wobbuffet was caught in a sticky web!"); + MESSAGE("Wobbuffet was hurt by the spikes!"); + NOT MESSAGE("Pointed stones dug into Wobbuffet!"); // Because the previous switch in effects instruction is still kept + } +} + +DOUBLE_BATTLE_TEST("Hazards can trigger Emergency Exit and hazards still activate for other battlers") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_FINAL_GAMBIT) == EFFECT_FINAL_GAMBIT); + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_GOLISOPOD) { HP(105); MaxHP(200); Ability(ABILITY_EMERGENCY_EXIT); } + PLAYER(SPECIES_WYNAUT); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(opponentLeft, MOVE_STEALTH_ROCK); MOVE(opponentRight, MOVE_TOXIC_SPIKES); } + TURN { MOVE(opponentLeft, MOVE_STICKY_WEB); MOVE(opponentRight, MOVE_SPIKES); } + TURN { MOVE(playerLeft, MOVE_FINAL_GAMBIT, target: opponentRight); + MOVE(playerRight, MOVE_FINAL_GAMBIT, target: opponentRight); + SEND_OUT(playerLeft, 2); + SEND_OUT(playerRight, 3); + SEND_OUT(playerLeft, 4); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponentLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC_SPIKES, opponentRight); + ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, opponentLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SPIKES, opponentRight); + MESSAGE("Pointed stones dug into Golisopod!"); + ABILITY_POPUP(playerLeft, ABILITY_EMERGENCY_EXIT); + NONE_OF { + MESSAGE("Golisopod was poisoned!"); + MESSAGE("Golisopod was caught in a sticky web!"); + MESSAGE("Golisopod was hurt by the spikes!"); + } + MESSAGE("Pointed stones dug into Wobbuffet!"); + MESSAGE("Wobbuffet was poisoned!"); + MESSAGE("Wobbuffet was caught in a sticky web!"); + MESSAGE("Wobbuffet was hurt by the spikes!"); + MESSAGE("Pointed stones dug into Wynaut!"); + MESSAGE("Wynaut was poisoned!"); + MESSAGE("Wynaut was caught in a sticky web!"); + MESSAGE("Wynaut was hurt by the spikes!"); + } +} diff --git a/test/battle/hold_effect/big_root.c b/test/battle/hold_effect/big_root.c index 41dd09adc..3d2256ea3 100644 --- a/test/battle/hold_effect/big_root.c +++ b/test/battle/hold_effect/big_root.c @@ -14,7 +14,7 @@ SINGLE_BATTLE_TEST("Big Root increases healing from absorbing moves", s16 damage PARAMETRIZE { item = ITEM_BIG_ROOT; } GIVEN { - PLAYER(SPECIES_WOBBUFFET) { HP(200); Item(item); } + PLAYER(SPECIES_XURKITREE) { HP(200); Item(item); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { TURN { MOVE(player, MOVE_ABSORB); } @@ -24,7 +24,7 @@ SINGLE_BATTLE_TEST("Big Root increases healing from absorbing moves", s16 damage HP_BAR(player, captureDamage: &results[i].heal); } FINALLY { EXPECT_EQ(results[0].damage, results[1].damage); // Damage is unaffected - EXPECT_MUL_EQ(results[1].heal, Q_4_12(5234 / 4096), results[0].heal); + EXPECT_MUL_EQ(results[0].heal, Q_4_12(1.3), results[1].heal); } } @@ -65,7 +65,7 @@ SINGLE_BATTLE_TEST("Big Root increases damage from absorbing Liquid Ooze", s16 d PARAMETRIZE { item = ITEM_BIG_ROOT; } GIVEN { - PLAYER(SPECIES_WOBBUFFET) { HP(200); Item(item); } + PLAYER(SPECIES_XURKITREE) { HP(200); Item(item); } OPPONENT(SPECIES_TENTACOOL) { Ability(ABILITY_LIQUID_OOZE); } } WHEN { TURN { MOVE(player, MOVE_ABSORB); } @@ -73,6 +73,6 @@ SINGLE_BATTLE_TEST("Big Root increases damage from absorbing Liquid Ooze", s16 d ANIMATION(ANIM_TYPE_MOVE, MOVE_ABSORB, player); HP_BAR(player, captureDamage: &results[i].damage); } FINALLY { - EXPECT_MUL_EQ(results[1].damage, Q_4_12(5234 / 4096), results[0].damage); + EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.3), results[1].damage); } } diff --git a/test/battle/hold_effect/booster_energy.c b/test/battle/hold_effect/booster_energy.c index 93e79e496..2cfd3a13c 100644 --- a/test/battle/hold_effect/booster_energy.c +++ b/test/battle/hold_effect/booster_energy.c @@ -38,6 +38,7 @@ SINGLE_BATTLE_TEST("Booster Energy will activate Quark Drive after Electric Terr SINGLE_BATTLE_TEST("Booster Energy will activate Protosynthesis after harsh sunlight ends") { GIVEN { + WITH_CONFIG(GEN_CONFIG_ABILITY_WEATHER, GEN_6); PLAYER(SPECIES_RAGING_BOLT) { Attack(100); Defense(100); Speed(100); SpAttack(110); SpDefense(100); Ability(ABILITY_PROTOSYNTHESIS); Item(ITEM_BOOSTER_ENERGY); } OPPONENT(SPECIES_TORKOAL) { Speed(100); Ability(ABILITY_DROUGHT); }; } WHEN { diff --git a/test/battle/hold_effect/destiny_knot.c b/test/battle/hold_effect/destiny_knot.c new file mode 100644 index 000000000..b8097c601 --- /dev/null +++ b/test/battle/hold_effect/destiny_knot.c @@ -0,0 +1,66 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gItemsInfo[ITEM_DESTINY_KNOT].holdEffect == HOLD_EFFECT_DESTINY_KNOT); +} + +SINGLE_BATTLE_TEST("Destiny Knot infatuates back when holder is targeted") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); } + OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_FEMALE); Item(ITEM_DESTINY_KNOT); } + } WHEN { + TURN { MOVE(player, MOVE_ATTRACT); } + } SCENE { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); + MESSAGE("Wobbuffet fell in love because of the Destiny Knot!"); + } THEN { + EXPECT(player->volatiles.infatuation); + } +} + +SINGLE_BATTLE_TEST("Destiny Knot infatuates back when holder is attacking") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); Item(ITEM_DESTINY_KNOT);} + OPPONENT(SPECIES_CLEFAIRY) { Gender(MON_FEMALE); Ability(ABILITY_CUTE_CHARM);} + } WHEN { + TURN { MOVE(player, MOVE_TACKLE); } + } SCENE { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + MESSAGE("The opposing Clefairy fell in love because of the Destiny Knot!"); + } THEN { + EXPECT(opponent->volatiles.infatuation); + } +} + + +SINGLE_BATTLE_TEST("Destiny Knot procs but fails if the target is already infatuated") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); } + OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_FEMALE); Item(ITEM_DESTINY_KNOT); } + } WHEN { + TURN { MOVE(opponent, MOVE_ATTRACT); MOVE(player, MOVE_ATTRACT, WITH_RNG(RNG_INFATUATION, FALSE)); } + } SCENE { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); + MESSAGE("But it failed!"); + } +} + +SINGLE_BATTLE_TEST("Destiny Knot procs but fails if the target is oblivious") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); Ability(ABILITY_OBLIVIOUS); } + OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_FEMALE); Item(ITEM_DESTINY_KNOT); } + } WHEN { + TURN { MOVE(player, MOVE_ATTRACT); } + } SCENE { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); + ABILITY_POPUP(player, ABILITY_OBLIVIOUS); + } THEN { + EXPECT(!player->volatiles.infatuation); + } +} diff --git a/test/battle/hold_effect/eject_pack.c b/test/battle/hold_effect/eject_pack.c index 600af0451..836f3d0fd 100644 --- a/test/battle/hold_effect/eject_pack.c +++ b/test/battle/hold_effect/eject_pack.c @@ -338,3 +338,26 @@ SINGLE_BATTLE_TEST("Eject Pack does not activate if mon is switched in due to Ej NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); } } + +DOUBLE_BATTLE_TEST("Eject Pack will trigger on the fastest mon at the end of the turn") +{ + GIVEN { + ASSUME(MoveHasAdditionalEffect(MOVE_SYRUP_BOMB, MOVE_EFFECT_SYRUP_BOMB) == TRUE); + PLAYER(SPECIES_WOBBUFFET) { Speed(1); Item(ITEM_EJECT_PACK); } + PLAYER(SPECIES_WYNAUT) { Speed(10); Item(ITEM_EJECT_PACK); } + PLAYER(SPECIES_WOBBUFFET) { Speed(2); } + OPPONENT(SPECIES_WYNAUT) { Speed(4); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(3); } + } WHEN { + TURN { + MOVE(opponentLeft, MOVE_SYRUP_BOMB, target: playerLeft); + MOVE(opponentRight, MOVE_SYRUP_BOMB, target: playerRight); + SEND_OUT(playerRight, 2); + } + } SCENE { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_SYRUP_BOMB_SPEED_DROP, playerRight); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_SYRUP_BOMB_SPEED_DROP, playerLeft); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, playerRight); + NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, playerLeft); + } +} diff --git a/test/battle/hold_effect/gems.c b/test/battle/hold_effect/gems.c index 52c85d7fb..b597beeab 100644 --- a/test/battle/hold_effect/gems.c +++ b/test/battle/hold_effect/gems.c @@ -26,13 +26,40 @@ SINGLE_BATTLE_TEST("Gem is consumed when it corresponds to the type of a move") } } +SINGLE_BATTLE_TEST("Gem is not consumed when using Struggle", s16 damage) +{ + u32 item = 0; + + PARAMETRIZE { item = ITEM_NONE; } + PARAMETRIZE { item = ITEM_NORMAL_GEM; } + + GIVEN { + if (item != ITEM_NONE) { + ASSUME(GetItemHoldEffect(item) == HOLD_EFFECT_GEMS); + ASSUME(GetItemSecondaryId(item) == GetMoveType(MOVE_STRUGGLE)); + } + PLAYER(SPECIES_WOBBUFFET) { Item(item); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_STRUGGLE); } + } SCENE { + NONE_OF { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + MESSAGE("The Normal Gem strengthened Wobbuffet's power!"); + } + ANIMATION(ANIM_TYPE_MOVE, MOVE_STRUGGLE, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + } +} + SINGLE_BATTLE_TEST("Gem boost is only applied once") { s16 boostedHit; s16 normalHit; GIVEN { - ASSUME(I_GEM_BOOST_POWER >= GEN_6); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMAL_GEM); }; OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -46,7 +73,10 @@ SINGLE_BATTLE_TEST("Gem boost is only applied once") ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, player); HP_BAR(opponent, captureDamage: &normalHit); } THEN { - EXPECT_MUL_EQ(normalHit, Q_4_12(1.3), boostedHit); + if (I_GEM_BOOST_POWER >= GEN_6) + EXPECT_MUL_EQ(normalHit, Q_4_12(1.3), boostedHit); + else + EXPECT_MUL_EQ(normalHit, Q_4_12(1.5), boostedHit); } } diff --git a/test/battle/hold_effect/kee_berry.c b/test/battle/hold_effect/kee_berry.c index c63da8684..d37a132be 100644 --- a/test/battle/hold_effect/kee_berry.c +++ b/test/battle/hold_effect/kee_berry.c @@ -89,3 +89,19 @@ DOUBLE_BATTLE_TEST("Kee Berry doesn't trigger if partner was hit") EXPECT(opponentRight->item == ITEM_KEE_BERRY); } } + +SINGLE_BATTLE_TEST("Kee Berry doesn't trigger if the move was boosted by Sheer Force") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_KEE_BERRY); } + OPPONENT(SPECIES_NIDOKING) { Ability(ABILITY_SHEER_FORCE); } + } WHEN { + TURN { MOVE(opponent, MOVE_EMBER); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, opponent); + HP_BAR(player); + NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + } THEN { + EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE); + } +} \ No newline at end of file diff --git a/test/battle/hold_effect/maranga_berry.c b/test/battle/hold_effect/maranga_berry.c index 22b72ba20..785e040ca 100644 --- a/test/battle/hold_effect/maranga_berry.c +++ b/test/battle/hold_effect/maranga_berry.c @@ -89,3 +89,19 @@ DOUBLE_BATTLE_TEST("Maranga Berry doesn't trigger if partner was hit") EXPECT(opponentRight->item == ITEM_MARANGA_BERRY); } } + +SINGLE_BATTLE_TEST("Maranga Berry doesn't trigger if the move was boosted by Sheer Force") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_MARANGA_BERRY); } + OPPONENT(SPECIES_NIDOKING) { Ability(ABILITY_SHEER_FORCE); } + } WHEN { + TURN { MOVE(opponent, MOVE_FIRE_PUNCH); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FIRE_PUNCH, opponent); + HP_BAR(player); + NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + } THEN { + EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE); + } +} diff --git a/test/battle/hold_effect/restore_hp.c b/test/battle/hold_effect/restore_hp.c index 9db149c02..ef96ead7e 100644 --- a/test/battle/hold_effect/restore_hp.c +++ b/test/battle/hold_effect/restore_hp.c @@ -63,20 +63,3 @@ DOUBLE_BATTLE_TEST("Restore HP Item effects do not miss timing after a recoil mo ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, playerRight); } } - -#if B_HP_BERRIES <= GEN_3 -SINGLE_BATTLE_TEST("Restore HP Berry triggers only during the end turn") -{ - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WYNAUT) { MaxHP(100); HP(51); Item(ITEM_ORAN_BERRY); } - } WHEN { - TURN { MOVE(player, MOVE_TACKLE); } - TURN {} - } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player); - ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); - } -} -#endif diff --git a/test/battle/hold_effect/seeds.c b/test/battle/hold_effect/seeds.c index eecb3846f..b54dd54f5 100644 --- a/test/battle/hold_effect/seeds.c +++ b/test/battle/hold_effect/seeds.c @@ -3,13 +3,13 @@ ASSUMPTIONS { - ASSUME(gItemsInfo[ITEM_ELECTRIC_SEED].holdEffect == HOLD_EFFECT_SEEDS); + ASSUME(gItemsInfo[ITEM_ELECTRIC_SEED].holdEffect == HOLD_EFFECT_TERRAIN_SEED); ASSUME(gItemsInfo[ITEM_ELECTRIC_SEED].holdEffectParam == HOLD_EFFECT_PARAM_ELECTRIC_TERRAIN); - ASSUME(gItemsInfo[ITEM_GRASSY_SEED].holdEffect == HOLD_EFFECT_SEEDS); + ASSUME(gItemsInfo[ITEM_GRASSY_SEED].holdEffect == HOLD_EFFECT_TERRAIN_SEED); ASSUME(gItemsInfo[ITEM_GRASSY_SEED].holdEffectParam == HOLD_EFFECT_PARAM_GRASSY_TERRAIN); - ASSUME(gItemsInfo[ITEM_MISTY_SEED].holdEffect == HOLD_EFFECT_SEEDS); + ASSUME(gItemsInfo[ITEM_MISTY_SEED].holdEffect == HOLD_EFFECT_TERRAIN_SEED); ASSUME(gItemsInfo[ITEM_MISTY_SEED].holdEffectParam == HOLD_EFFECT_PARAM_MISTY_TERRAIN); - ASSUME(gItemsInfo[ITEM_PSYCHIC_SEED].holdEffect == HOLD_EFFECT_SEEDS); + ASSUME(gItemsInfo[ITEM_PSYCHIC_SEED].holdEffect == HOLD_EFFECT_TERRAIN_SEED); ASSUME(gItemsInfo[ITEM_PSYCHIC_SEED].holdEffectParam == HOLD_EFFECT_PARAM_PSYCHIC_TERRAIN); } diff --git a/test/battle/hold_effect/sticky_barb.c b/test/battle/hold_effect/sticky_barb.c new file mode 100644 index 000000000..59c1e1227 --- /dev/null +++ b/test/battle/hold_effect/sticky_barb.c @@ -0,0 +1,51 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(GetItemHoldEffect(ITEM_STICKY_BARB) == HOLD_EFFECT_STICKY_BARB); +} + +SINGLE_BATTLE_TEST("Sticky Barb hurts its holder at the end of the turn") +{ + s16 damage; + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_STICKY_BARB); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { } + } SCENE { + HP_BAR(player, captureDamage: &damage); + } THEN { + EXPECT_EQ(damage, player->maxHP / 8); + } +} + +SINGLE_BATTLE_TEST("Sticky Barb gets transferred if its holder is hit by a contact move") +{ + u32 move; + PARAMETRIZE { move = MOVE_SCRATCH; } + PARAMETRIZE { move = MOVE_GROWL; } + PARAMETRIZE { move = MOVE_HYPER_VOICE; } + GIVEN { + ASSUME(MoveMakesContact(MOVE_SCRATCH)); + ASSUME(!MoveMakesContact(MOVE_GROWL)); + ASSUME(!MoveMakesContact(MOVE_HYPER_VOICE)); + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_STICKY_BARB); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, move); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, opponent); + if (MoveMakesContact(move)) + { + MESSAGE("The Sticky Barb attached itself to the opposing Wobbuffet!"); + MESSAGE("The opposing Wobbuffet was hurt by the Sticky Barb!"); + } + else + { + NOT MESSAGE("The Sticky Barb attached itself to the opposing Wobbuffet!"); + MESSAGE("Wobbuffet was hurt by the Sticky Barb!"); + } + } +} diff --git a/test/battle/hold_effect/type_power.c b/test/battle/hold_effect/type_power.c index 5afe2a39c..c03d2487d 100644 --- a/test/battle/hold_effect/type_power.c +++ b/test/battle/hold_effect/type_power.c @@ -53,3 +53,27 @@ SINGLE_BATTLE_TEST("Type-enhancing items increase the base power of moves by 20% } } } + +SINGLE_BATTLE_TEST("Type-enhancing items do not increase the power of Struggle", s16 damage) +{ + u32 item = 0; + + PARAMETRIZE { item = ITEM_NONE; } + PARAMETRIZE { item = ITEM_SILK_SCARF; } + + GIVEN { + if (item != ITEM_NONE) { + ASSUME(GetItemHoldEffect(item) == HOLD_EFFECT_TYPE_POWER); + ASSUME(GetItemSecondaryId(item) == GetMoveType(MOVE_STRUGGLE)); + } + PLAYER(SPECIES_WOBBUFFET) { Item(item); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_STRUGGLE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STRUGGLE, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + } +} diff --git a/test/battle/hold_effect/weakness_berry.c b/test/battle/hold_effect/weakness_berry.c new file mode 100644 index 000000000..4958c6781 --- /dev/null +++ b/test/battle/hold_effect/weakness_berry.c @@ -0,0 +1,126 @@ +#include "global.h" +#include "test/battle.h" + +static const u16 sMoveItemTable[][4] = +{ + { TYPE_NORMAL, MOVE_SCRATCH, ITEM_CHILAN_BERRY, SPECIES_WOBBUFFET }, + { TYPE_FIGHTING, MOVE_KARATE_CHOP, ITEM_CHOPLE_BERRY, SPECIES_RAMPARDOS }, + { TYPE_FLYING, MOVE_WING_ATTACK, ITEM_COBA_BERRY, SPECIES_HARIYAMA }, + { TYPE_POISON, MOVE_POISON_STING, ITEM_KEBIA_BERRY, SPECIES_GOGOAT }, + { TYPE_GROUND, MOVE_MUD_SHOT, ITEM_SHUCA_BERRY, SPECIES_RAMPARDOS }, + { TYPE_ROCK, MOVE_ROCK_THROW, ITEM_CHARTI_BERRY, SPECIES_CORVISQUIRE }, + { TYPE_BUG, MOVE_BUG_BITE, ITEM_TANGA_BERRY, SPECIES_WOBBUFFET }, + { TYPE_GHOST, MOVE_SHADOW_PUNCH, ITEM_KASIB_BERRY, SPECIES_WOBBUFFET }, + { TYPE_STEEL, MOVE_METAL_CLAW, ITEM_BABIRI_BERRY, SPECIES_RAMPARDOS }, + { TYPE_FIRE, MOVE_EMBER, ITEM_OCCA_BERRY, SPECIES_GOGOAT }, + { TYPE_WATER, MOVE_WATER_GUN, ITEM_PASSHO_BERRY, SPECIES_RAMPARDOS }, + { TYPE_GRASS, MOVE_VINE_WHIP, ITEM_RINDO_BERRY, SPECIES_RAMPARDOS }, + { TYPE_ELECTRIC, MOVE_THUNDER_SHOCK, ITEM_WACAN_BERRY, SPECIES_CORVISQUIRE }, + { TYPE_PSYCHIC, MOVE_CONFUSION, ITEM_PAYAPA_BERRY, SPECIES_HARIYAMA }, + { TYPE_ICE, MOVE_AURORA_BEAM, ITEM_YACHE_BERRY, SPECIES_DRAGONAIR }, + { TYPE_DRAGON, MOVE_DRAGON_BREATH, ITEM_HABAN_BERRY, SPECIES_DRAGONAIR }, + { TYPE_DARK, MOVE_BITE, ITEM_COLBUR_BERRY, SPECIES_WOBBUFFET }, + { TYPE_FAIRY, MOVE_DISARMING_VOICE, ITEM_ROSELI_BERRY, SPECIES_DRAGONAIR }, +}; + +SINGLE_BATTLE_TEST("Weakness berries decrease the base power of moves by half", s16 damage) +{ + u32 move = 0, item = 0, defender = 0; + enum Type type = TYPE_NONE; + + for (u32 j = 0; j < ARRAY_COUNT(sMoveItemTable); j++) + { + PARAMETRIZE { type = sMoveItemTable[j][0]; move = sMoveItemTable[j][1]; defender = sMoveItemTable[j][3]; item = ITEM_NONE; } + PARAMETRIZE { type = sMoveItemTable[j][0]; move = sMoveItemTable[j][1]; defender = sMoveItemTable[j][3]; item = sMoveItemTable[j][2]; } + } + + GIVEN { + ASSUME(GetMovePower(move) > 0); + ASSUME(GetMoveType(move) == type); + ASSUME(GetSpeciesType(defender, 0) == GetSpeciesType(defender, 1)); + if (type != TYPE_NORMAL) { + ASSUME(gTypeEffectivenessTable[type][GetSpeciesType(defender, 0)] > UQ_4_12(1.0)); + } + if (item != ITEM_NONE) { + ASSUME(GetItemHoldEffect(item) == HOLD_EFFECT_RESIST_BERRY); + ASSUME(GetItemHoldEffectParam(item) == type); + } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(defender) { Item(item); } + } WHEN { + TURN { MOVE(player, move); } + } SCENE { + if (1 == i % 2) { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); + } + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + for (u32 j = 0; j < ARRAY_COUNT(sMoveItemTable); j++) { + EXPECT_MUL_EQ(results[j*2].damage, Q_4_12(0.5), results[(j*2)+1].damage); + } + } +} + +SINGLE_BATTLE_TEST("Weakness berries do not activate unless a move is super effective", s16 damage) +{ + u32 move = 0, item = 0, defender = 0; + enum Type type = TYPE_NONE; + + for (u32 j = 0; j < ARRAY_COUNT(sMoveItemTable); j++) + { + if (TYPE_NORMAL == type) + { + // ITEM_CHILAN_BERRY activates without a weakness + } + else if (TYPE_FAIRY == type) + { + PARAMETRIZE { type = sMoveItemTable[j][0]; move = sMoveItemTable[j][1]; item = sMoveItemTable[j][2]; defender = SPECIES_WOBBUFFET; } + } + else + { + PARAMETRIZE { type = sMoveItemTable[j][0]; move = sMoveItemTable[j][1]; item = sMoveItemTable[j][2]; defender = SPECIES_SABLEYE; } + } + } + + GIVEN { + ASSUME(GetMovePower(move) > 0); + ASSUME(uq4_12_multiply(gTypeEffectivenessTable[type][GetSpeciesType(defender, 0)], + gTypeEffectivenessTable[type][GetSpeciesType(defender, 1)]) <= UQ_4_12(1.0)); + ASSUME(GetItemHoldEffect(item) == HOLD_EFFECT_RESIST_BERRY); + ASSUME(GetItemHoldEffectParam(item) == type); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(defender) { Item(item); } + } WHEN { + TURN { MOVE(player, move); } + } SCENE { + NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); + } +} + +SINGLE_BATTLE_TEST("Weakness berries do not decrease the power of Struggle", s16 damage) +{ + u32 item = 0; + + PARAMETRIZE { item = ITEM_NONE; } + PARAMETRIZE { item = ITEM_CHILAN_BERRY; } + + GIVEN { + if (item != ITEM_NONE) { + ASSUME(GetItemHoldEffect(item) == HOLD_EFFECT_RESIST_BERRY); + ASSUME(GetItemHoldEffectParam(item) == TYPE_NORMAL); + } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(item); } + } WHEN { + TURN { MOVE(player, MOVE_STRUGGLE); } + } SCENE { + NONE_OF { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); + MESSAGE("The Chilan Berry weakened the damage to the opposing Wobbuffet!"); + } + ANIMATION(ANIM_TYPE_MOVE, MOVE_STRUGGLE, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + } +} diff --git a/test/battle/item_effect/poke_flute.c b/test/battle/item_effect/poke_flute.c new file mode 100644 index 000000000..c9aebed5d --- /dev/null +++ b/test/battle/item_effect/poke_flute.c @@ -0,0 +1,43 @@ +#include "global.h" +#include "test/battle.h" +#include "constants/item_effects.h" + +DOUBLE_BATTLE_TEST("Poke Flute heals all battlers from being asleep") +{ + GIVEN { + ASSUME(gItemsInfo[ITEM_POKE_FLUTE].battleUsage == EFFECT_ITEM_USE_POKE_FLUTE); + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); } + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); } + OPPONENT(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); } + OPPONENT(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); } + } WHEN { + TURN { USE_ITEM(playerLeft, ITEM_POKE_FLUTE, partyIndex: 0); } + } SCENE { + MESSAGE("The Pokémon hearing the flute awoke!"); + } THEN { + EXPECT_EQ(playerLeft->status1, STATUS1_NONE); + EXPECT_EQ(playerRight->status1, STATUS1_NONE); + EXPECT_EQ(opponentLeft->status1, STATUS1_NONE); + EXPECT_EQ(opponentRight->status1, STATUS1_NONE); + } +} + +DOUBLE_BATTLE_TEST("Poke Flute does not heal battlers with Soundproof from being asleep") +{ + GIVEN { + ASSUME(gItemsInfo[ITEM_POKE_FLUTE].battleUsage == EFFECT_ITEM_USE_POKE_FLUTE); + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); } + PLAYER(SPECIES_EXPLOUD) { Ability(ABILITY_SOUNDPROOF); Status1(STATUS1_SLEEP); } + OPPONENT(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); } + OPPONENT(SPECIES_EXPLOUD) { Ability(ABILITY_SOUNDPROOF); Status1(STATUS1_SLEEP); } + } WHEN { + TURN { USE_ITEM(playerLeft, ITEM_POKE_FLUTE, partyIndex: 0); } + } SCENE { + MESSAGE("The Pokémon hearing the flute awoke!"); + } THEN { + EXPECT_EQ(playerLeft->status1, STATUS1_NONE); + EXPECT_NE(playerRight->status1, STATUS1_NONE); + EXPECT_EQ(opponentLeft->status1, STATUS1_NONE); + EXPECT_NE(opponentRight->status1, STATUS1_NONE); + } +} diff --git a/test/battle/move.c b/test/battle/move.c index f69c7b2eb..3efab260a 100644 --- a/test/battle/move.c +++ b/test/battle/move.c @@ -212,6 +212,50 @@ DOUBLE_BATTLE_TEST("Moves fail if they target the partner but they faint before } } +MULTI_BATTLE_TEST("Ally switch fails when used by either side in a multibattle") +{ + GIVEN { + MULTI_PLAYER(SPECIES_WOBBUFFET); + MULTI_PARTNER(SPECIES_WOBBUFFET); + MULTI_OPPONENT_A(SPECIES_WOBBUFFET); + MULTI_OPPONENT_B(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_ALLY_SWITCH); MOVE(playerRight, MOVE_ALLY_SWITCH); MOVE(opponentLeft, MOVE_ALLY_SWITCH); MOVE(opponentRight, MOVE_ALLY_SWITCH); } + } SCENE { + NONE_OF { ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, playerLeft); ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, playerRight); ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, opponentLeft); ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, opponentRight); } + } +} + +TWO_VS_ONE_BATTLE_TEST("Ally switch can only be used by the opponent in a 2v1 battle") +{ + GIVEN { + MULTI_PLAYER(SPECIES_WOBBUFFET); + MULTI_PARTNER(SPECIES_WOBBUFFET); + MULTI_OPPONENT_A(SPECIES_WOBBUFFET); + MULTI_OPPONENT_A(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_ALLY_SWITCH); MOVE(playerRight, MOVE_ALLY_SWITCH); MOVE(opponentLeft, MOVE_ALLY_SWITCH); } + } SCENE { + { ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, opponentLeft); } + NONE_OF { ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, playerLeft); ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, playerRight); } + } +} + +ONE_VS_TWO_BATTLE_TEST("Ally switch can only be used by the player in a 1v2 battle") +{ + GIVEN { + MULTI_PLAYER(SPECIES_WOBBUFFET); + MULTI_PLAYER(SPECIES_WOBBUFFET); + MULTI_OPPONENT_A(SPECIES_WOBBUFFET); + MULTI_OPPONENT_B(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_ALLY_SWITCH); MOVE(opponentLeft, MOVE_ALLY_SWITCH); MOVE(opponentRight, MOVE_ALLY_SWITCH); } + } SCENE { + { ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, playerLeft); } + NONE_OF { ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, opponentLeft); ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, opponentRight); } + } +} + DOUBLE_BATTLE_TEST("Moves do not fail if an alive partner is the target") { GIVEN { diff --git a/test/battle/move_effect/acrobatics.c b/test/battle/move_effect/acrobatics.c index 809b77f94..1229d4e2c 100644 --- a/test/battle/move_effect/acrobatics.c +++ b/test/battle/move_effect/acrobatics.c @@ -30,7 +30,6 @@ SINGLE_BATTLE_TEST("Acrobatics still doubles in power when Flying Gem is consume PARAMETRIZE { heldItem = ITEM_NONE; } PARAMETRIZE { heldItem = ITEM_FLYING_GEM; } GIVEN { - ASSUME(I_GEM_BOOST_POWER >= GEN_6); ASSUME(gItemsInfo[ITEM_FLYING_GEM].holdEffect == HOLD_EFFECT_GEMS); ASSUME(gItemsInfo[ITEM_FLYING_GEM].secondaryId == TYPE_FLYING); PLAYER(SPECIES_WOBBUFFET); diff --git a/test/battle/move_effect/belly_drum.c b/test/battle/move_effect/belly_drum.c index 20024f5b9..194ee5b9d 100644 --- a/test/battle/move_effect/belly_drum.c +++ b/test/battle/move_effect/belly_drum.c @@ -159,7 +159,6 @@ SINGLE_BATTLE_TEST("Belly Drum maximizes the user's Attack stat, even when below SINGLE_BATTLE_TEST("Belly Drum fails if the user's Attack is already at +6, even with Contrary") { - KNOWN_FAILING; GIVEN { ASSUME(GetMoveEffect(MOVE_CHARM) == EFFECT_ATTACK_DOWN_2); PLAYER(SPECIES_SERPERIOR) { Ability(ABILITY_CONTRARY); } @@ -190,7 +189,6 @@ SINGLE_BATTLE_TEST("Belly Drum fails if the user's Attack is already at +6, even SINGLE_BATTLE_TEST("Belly Drum deducts HP if the user has Contrary and is at -6") { - KNOWN_FAILING; GIVEN { ASSUME(GetMoveEffect(MOVE_SWORDS_DANCE) == EFFECT_ATTACK_UP_2); PLAYER(SPECIES_SERPERIOR) { Ability(ABILITY_CONTRARY); } @@ -215,6 +213,6 @@ SINGLE_BATTLE_TEST("Belly Drum deducts HP if the user has Contrary and is at -6" ANIMATION(ANIM_TYPE_MOVE, MOVE_BELLY_DRUM, player); s32 maxHP = GetMonData(&PLAYER_PARTY[0], MON_DATA_MAX_HP); HP_BAR(player, hp: maxHP / 2); - MESSAGE("Wobbuffet cut its own HP and maximized its Attack!"); + MESSAGE("Serperior cut its own HP and maximized its Attack!"); } } diff --git a/test/battle/move_effect/destiny_bond.c b/test/battle/move_effect/destiny_bond.c index ddebc6bb1..17cf65877 100644 --- a/test/battle/move_effect/destiny_bond.c +++ b/test/battle/move_effect/destiny_bond.c @@ -10,12 +10,18 @@ SINGLE_BATTLE_TEST("Destiny Bond faints the opposing mon if it fainted from the { GIVEN { PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { MOVE(player, MOVE_DESTINY_BOND); MOVE(opponent, MOVE_SCRATCH); } + TURN { + MOVE(player, MOVE_DESTINY_BOND); + MOVE(opponent, MOVE_SCRATCH); + SEND_OUT(player, 1); + } } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_DESTINY_BOND, player); ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponent); + MESSAGE("Wobbuffet fainted!"); MESSAGE("Wobbuffet took its attacker down with it!"); MESSAGE("The opposing Wobbuffet fainted!"); } diff --git a/test/battle/move_effect/dragon_darts.c b/test/battle/move_effect/dragon_darts.c index a06c61ec7..97694909f 100644 --- a/test/battle/move_effect/dragon_darts.c +++ b/test/battle/move_effect/dragon_darts.c @@ -4,7 +4,6 @@ ASSUMPTIONS { ASSUME(GetMoveEffect(MOVE_DRAGON_DARTS) == EFFECT_DRAGON_DARTS); - ASSUME(GetSpeciesType(SPECIES_CLEFAIRY, 0) == TYPE_FAIRY || GetSpeciesType(SPECIES_CLEFAIRY, 1) == TYPE_FAIRY); } SINGLE_BATTLE_TEST("Dragon Darts strikes twice") @@ -72,13 +71,13 @@ DOUBLE_BATTLE_TEST("Dragon Darts strikes an opponent twice if the other one is F struct BattlePokemon *chosenTarget = NULL; struct BattlePokemon *finalTarget = NULL; u32 speciesLeft, speciesRight; - PARAMETRIZE { chosenTarget = opponentLeft; finalTarget = opponentRight; speciesLeft = SPECIES_CLEFAIRY; speciesRight = SPECIES_WOBBUFFET; } - PARAMETRIZE { chosenTarget = opponentRight; finalTarget = opponentRight; speciesLeft = SPECIES_CLEFAIRY; speciesRight = SPECIES_WOBBUFFET; } - PARAMETRIZE { chosenTarget = opponentLeft; finalTarget = opponentLeft; speciesLeft = SPECIES_WOBBUFFET; speciesRight = SPECIES_CLEFAIRY; } - PARAMETRIZE { chosenTarget = opponentRight; finalTarget = opponentLeft; speciesLeft = SPECIES_WOBBUFFET; speciesRight = SPECIES_CLEFAIRY; } + PARAMETRIZE { chosenTarget = opponentLeft; finalTarget = opponentRight; speciesLeft = SPECIES_FIDOUGH; speciesRight = SPECIES_WOBBUFFET; } + PARAMETRIZE { chosenTarget = opponentRight; finalTarget = opponentRight; speciesLeft = SPECIES_FIDOUGH; speciesRight = SPECIES_WOBBUFFET; } + PARAMETRIZE { chosenTarget = opponentLeft; finalTarget = opponentLeft; speciesLeft = SPECIES_WOBBUFFET; speciesRight = SPECIES_FIDOUGH; } + PARAMETRIZE { chosenTarget = opponentRight; finalTarget = opponentLeft; speciesLeft = SPECIES_WOBBUFFET; speciesRight = SPECIES_FIDOUGH; } GIVEN { - ASSUME(GetSpeciesType(SPECIES_CLEFAIRY, 0) == TYPE_FAIRY || GetSpeciesType(SPECIES_CLEFAIRY, 1) == TYPE_FAIRY); + ASSUME(GetSpeciesType(SPECIES_FIDOUGH, 0) == TYPE_FAIRY || GetSpeciesType(SPECIES_FIDOUGH, 1) == TYPE_FAIRY); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(speciesLeft); @@ -257,7 +256,6 @@ DOUBLE_BATTLE_TEST("Dragon Darts strikes right ally twice if one strike misses") DOUBLE_BATTLE_TEST("Dragon Darts strikes will be both redirected to Follow Me user") { GIVEN { - ASSUME(GetSpeciesType(SPECIES_CLEFAIRY, 0) == TYPE_FAIRY || GetSpeciesType(SPECIES_CLEFAIRY, 1) == TYPE_FAIRY); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -273,14 +271,14 @@ DOUBLE_BATTLE_TEST("Dragon Darts strikes will be both redirected to Follow Me us } } -DOUBLE_BATTLE_TEST("Dragon Darts fails to strike any target if under a fairy type follow me user") +DOUBLE_BATTLE_TEST("Dragon Darts fails to strike any target if under a Fairy-type follow me user") { GIVEN { - ASSUME(GetSpeciesType(SPECIES_CLEFAIRY, 0) == TYPE_FAIRY || GetSpeciesType(SPECIES_CLEFAIRY, 1) == TYPE_FAIRY); + ASSUME(GetSpeciesType(SPECIES_FIDOUGH, 0) == TYPE_FAIRY || GetSpeciesType(SPECIES_FIDOUGH, 1) == TYPE_FAIRY); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_CLEFAIRY); + OPPONENT(SPECIES_FIDOUGH); } WHEN { TURN { MOVE(opponentRight, MOVE_FOLLOW_ME); MOVE(playerLeft, MOVE_DRAGON_DARTS, target: opponentLeft); } } SCENE { @@ -295,7 +293,6 @@ DOUBLE_BATTLE_TEST("Dragon Darts fails to strike any target if under a fairy typ DOUBLE_BATTLE_TEST("Dragon Darts fails to strike the second target if first target fainted and follow me was active") { GIVEN { - ASSUME(GetSpeciesType(SPECIES_CLEFAIRY, 0) == TYPE_FAIRY || GetSpeciesType(SPECIES_CLEFAIRY, 1) == TYPE_FAIRY); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/move_effect/echoed_voice.c b/test/battle/move_effect/echoed_voice.c index 3c3627045..29a2b6e48 100644 --- a/test/battle/move_effect/echoed_voice.c +++ b/test/battle/move_effect/echoed_voice.c @@ -1,7 +1,169 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("Echoed Voice's power is multiplied for every consecutive turn used, capped at 5"); -TO_DO_BATTLE_TEST("Echoed Voice's power is reset when using a different move"); -TO_DO_BATTLE_TEST("Echoed Voice's power is increased even if it misses"); -TO_DO_BATTLE_TEST("Echoed Voice's power is increased even if it's blocked by Protect"); +ASSUMPTIONS +{ + ASSUME(GetMoveEffect(MOVE_ECHOED_VOICE) == EFFECT_ECHOED_VOICE); +} + +SINGLE_BATTLE_TEST("Echoed Voice's power is multiplied for every consecutive turn used, capped at 5") +{ + s16 damage[6]; + + GIVEN { + ASSUME(GetMoveEffect(MOVE_SOFT_BOILED) == EFFECT_SOFTBOILED); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_BLISSEY); + } WHEN { + TURN { MOVE(player, MOVE_ECHOED_VOICE); } + TURN { MOVE(player, MOVE_ECHOED_VOICE); } + TURN { MOVE(player, MOVE_ECHOED_VOICE); MOVE(opponent, MOVE_SOFT_BOILED); } + TURN { MOVE(player, MOVE_ECHOED_VOICE); } + TURN { MOVE(player, MOVE_ECHOED_VOICE); MOVE(opponent, MOVE_SOFT_BOILED); } + TURN { MOVE(player, MOVE_ECHOED_VOICE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ECHOED_VOICE, player); + HP_BAR(opponent, captureDamage: &damage[0]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ECHOED_VOICE, player); + HP_BAR(opponent, captureDamage: &damage[1]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ECHOED_VOICE, player); + HP_BAR(opponent, captureDamage: &damage[2]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ECHOED_VOICE, player); + HP_BAR(opponent, captureDamage: &damage[3]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ECHOED_VOICE, player); + HP_BAR(opponent, captureDamage: &damage[4]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ECHOED_VOICE, player); + HP_BAR(opponent, captureDamage: &damage[5]); + } THEN { + EXPECT_MUL_EQ(damage[0], UQ_4_12(2.0), damage[1]); + EXPECT_MUL_EQ(damage[0], UQ_4_12(3.0), damage[2]); + EXPECT_MUL_EQ(damage[0], UQ_4_12(4.0), damage[3]); + EXPECT_MUL_EQ(damage[0], UQ_4_12(5.0), damage[4]); + EXPECT_EQ(damage[4], damage[5]); + } +} + +SINGLE_BATTLE_TEST("Echoed Voice's power increases even if used by another battler") +{ + s16 damage[2]; + + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_ECHOED_VOICE); } + TURN { MOVE(player, MOVE_ECHOED_VOICE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ECHOED_VOICE, opponent); + HP_BAR(player, captureDamage: &damage[0]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ECHOED_VOICE, player); + HP_BAR(opponent, captureDamage: &damage[1]); + } THEN { + EXPECT_MUL_EQ(damage[0], UQ_4_12(2.0), damage[1]); + } +} + +SINGLE_BATTLE_TEST("Echoed Voice's power does not change until the end of the turn") +{ + s16 damage[3]; + + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_ECHOED_VOICE); MOVE(opponent, MOVE_ECHOED_VOICE); } + TURN { MOVE(player, MOVE_ECHOED_VOICE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ECHOED_VOICE, player); + HP_BAR(opponent, captureDamage: &damage[0]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ECHOED_VOICE, opponent); + HP_BAR(player, captureDamage: &damage[1]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ECHOED_VOICE, player); + HP_BAR(opponent, captureDamage: &damage[2]); + } THEN { + EXPECT_EQ(damage[0], damage[1]); + EXPECT_MUL_EQ(damage[0], UQ_4_12(2.0), damage[2]); + } +} + +SINGLE_BATTLE_TEST("Echoed Voice's power increase is reset when no battler uses it successfully during a turn") +{ + s16 damage[3]; + + GIVEN { + ASSUME(MoveHasAdditionalEffect(MOVE_BITE, MOVE_EFFECT_FLINCH)); + PLAYER(SPECIES_WOBBUFFET) { Speed(5); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(10); } + } WHEN { + TURN { MOVE(opponent, MOVE_ECHOED_VOICE); } + TURN { MOVE(player, MOVE_ECHOED_VOICE); } + TURN { MOVE(opponent, MOVE_BITE); MOVE(player, MOVE_ECHOED_VOICE); } + TURN { MOVE(player, MOVE_ECHOED_VOICE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ECHOED_VOICE, opponent); + HP_BAR(player, captureDamage: &damage[0]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ECHOED_VOICE, player); + HP_BAR(opponent, captureDamage: &damage[1]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, opponent); + MESSAGE("Wobbuffet flinched and couldn't move!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ECHOED_VOICE, player); + HP_BAR(opponent, captureDamage: &damage[2]); + } THEN { + EXPECT_EQ(damage[0], damage[2]); + EXPECT_NE(damage[1], damage[2]); + } +} + +SINGLE_BATTLE_TEST("Echoed Voice's power is increased even if it misses") +{ + s16 damage[3]; + + GIVEN { + ASSUME(GetMoveEffect(MOVE_SAND_ATTACK) == EFFECT_ACCURACY_DOWN); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_ECHOED_VOICE); } + TURN { MOVE(player, MOVE_ECHOED_VOICE); MOVE(opponent, MOVE_SAND_ATTACK); } + TURN { MOVE(player, MOVE_ECHOED_VOICE, hit: FALSE); } + TURN { MOVE(player, MOVE_ECHOED_VOICE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ECHOED_VOICE, player); + HP_BAR(opponent, captureDamage: &damage[0]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ECHOED_VOICE, player); + HP_BAR(opponent, captureDamage: &damage[1]); + MESSAGE("Wobbuffet's attack missed!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ECHOED_VOICE, player); + HP_BAR(opponent, captureDamage: &damage[2]); + } THEN { + EXPECT_MUL_EQ(damage[0], UQ_4_12(2.0), damage[1]); + EXPECT_MUL_EQ(damage[0], UQ_4_12(4.0), damage[2]); + } +} + +SINGLE_BATTLE_TEST("Echoed Voice's power is increased even if it's blocked by Protect") +{ + s16 damage[3]; + + GIVEN { + ASSUME(GetMoveEffect(MOVE_PROTECT) == EFFECT_PROTECT); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_ECHOED_VOICE); } + TURN { MOVE(player, MOVE_ECHOED_VOICE); } + TURN { MOVE(player, MOVE_ECHOED_VOICE); MOVE(opponent, MOVE_PROTECT); } + TURN { MOVE(player, MOVE_ECHOED_VOICE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ECHOED_VOICE, player); + HP_BAR(opponent, captureDamage: &damage[0]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ECHOED_VOICE, player); + HP_BAR(opponent, captureDamage: &damage[1]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_PROTECT, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ECHOED_VOICE, player); + HP_BAR(opponent, captureDamage: &damage[2]); + } THEN { + EXPECT_MUL_EQ(damage[0], UQ_4_12(2.0), damage[1]); + EXPECT_MUL_EQ(damage[0], UQ_4_12(4.0), damage[2]); + } +} diff --git a/test/battle/move_effect/endure.c b/test/battle/move_effect/endure.c index f332fc28d..2d66bc41e 100644 --- a/test/battle/move_effect/endure.c +++ b/test/battle/move_effect/endure.c @@ -1,13 +1,17 @@ #include "global.h" #include "test/battle.h" +ASSUMPTIONS +{ + ASSUME(GetMoveEffect(MOVE_ENDURE) == EFFECT_ENDURE); +} + TO_DO_BATTLE_TEST("Endure allows the user to survive any attack with 1 HP left"); SINGLE_BATTLE_TEST("Endure does not prevent multiple hits and stat changes occur at the end of the turn") { GIVEN { ASSUME(GetMoveEffect(MOVE_SCALE_SHOT) == EFFECT_MULTI_HIT); - ASSUME(GetMoveEffect(MOVE_ENDURE) == EFFECT_ENDURE); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { HP(1); } } WHEN { @@ -54,6 +58,23 @@ DOUBLE_BATTLE_TEST("Endure is not transferred to a mon that is switched in due t } } +SINGLE_BATTLE_TEST("Endure only lasts for one turn") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { HP(1); } + } WHEN { + TURN { MOVE(opponent, MOVE_ENDURE); MOVE(player, MOVE_POUND); } + TURN { MOVE(player, MOVE_POUND); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ENDURE, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, player); + MESSAGE("The opposing Wobbuffet endured the hit!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, player); + NOT MESSAGE("The opposing Wobbuffet endured the hit!"); + } +} + TO_DO_BATTLE_TEST("Endure's success rate decreases for every consecutively used turn"); TO_DO_BATTLE_TEST("Endure uses the same counter as Protect"); TO_DO_BATTLE_TEST("Endure doesn't trigger effects that require damage to be done to the Pokémon (Gen 2-4)"); // Eg. Rough Skin diff --git a/test/battle/move_effect/fickle_beam.c b/test/battle/move_effect/fickle_beam.c index 0313823aa..8554a29da 100644 --- a/test/battle/move_effect/fickle_beam.c +++ b/test/battle/move_effect/fickle_beam.c @@ -12,15 +12,14 @@ SINGLE_BATTLE_TEST("Fickle Beam deals double damage 30% of the time") PASSES_RANDOMLY(30, 100, RNG_FICKLE_BEAM); GIVEN { - ASSUME(GetMovePower(MOVE_POWER_GEM) == 80); - ASSUME(GetMovePower(MOVE_FICKLE_BEAM) == 80); + ASSUME(GetMovePower(MOVE_DAZZLING_GLEAM) == GetMovePower(MOVE_FICKLE_BEAM)); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { MOVE(player, MOVE_POWER_GEM); } + TURN { MOVE(player, MOVE_DAZZLING_GLEAM); } TURN { MOVE(player, MOVE_FICKLE_BEAM); } } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_POWER_GEM, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DAZZLING_GLEAM, player); HP_BAR(opponent, captureDamage: &damage[0]); ANIMATION(ANIM_TYPE_MOVE, MOVE_FICKLE_BEAM, player); HP_BAR(opponent, captureDamage: &damage[1]); diff --git a/test/battle/move_effect/fling.c b/test/battle/move_effect/fling.c index 1efbd3fce..05ccec70a 100644 --- a/test/battle/move_effect/fling.c +++ b/test/battle/move_effect/fling.c @@ -153,6 +153,23 @@ SINGLE_BATTLE_TEST("Fling - Item is lost when target protects itself") } } +SINGLE_BATTLE_TEST("Fling - Item does not get blocked by Unnerve if it isn't a berry") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_TAUNT) == EFFECT_TAUNT); + PLAYER(SPECIES_CALYREX) { Item(ITEM_MENTAL_HERB); Ability(ABILITY_UNNERVE); } + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_ORAN_BERRY); } + } WHEN { + TURN { MOVE(player, MOVE_TAUNT); MOVE(opponent, MOVE_SCRATCH); } + TURN { MOVE(player, MOVE_FLING); MOVE(opponent, MOVE_SCRATCH); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_TAUNT, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_FLING, player); + HP_BAR(opponent); + MESSAGE("The opposing Wobbuffet's Taunt wore off!"); + } +} + SINGLE_BATTLE_TEST("Fling doesn't consume the item if Pokémon is asleep/frozen/paralyzed") { u32 status; @@ -461,4 +478,25 @@ SINGLE_BATTLE_TEST("Fling deals damage based on items fling power") } } +SINGLE_BATTLE_TEST("Flinging a Mental Herb does not trigger the item if the target doesn't have anything that's cured by Mental Herb") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_MENTAL_HERB); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_FLING); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FLING, player); + NONE_OF { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); + MESSAGE("The opposing Wobbuffet got over its infatuation!"); + MESSAGE("The opposing Wobbuffet's Taunt wore off!"); + MESSAGE("The opposing Wobbuffet ended its encore!"); + MESSAGE("The opposing Wobbuffet is no longer tormented!"); + MESSAGE("The opposing Wobbuffet's move is no longer disabled!"); + MESSAGE("The opposing Wobbuffet is cured of its heal block!"); + } + } +} + TO_DO_BATTLE_TEST("Fling deals damage based on a TM's move power") diff --git a/test/battle/move_effect/focus_energy.c b/test/battle/move_effect/focus_energy.c index 48924132e..17a08ba7f 100644 --- a/test/battle/move_effect/focus_energy.c +++ b/test/battle/move_effect/focus_energy.c @@ -23,7 +23,34 @@ SINGLE_BATTLE_TEST("Focus Energy increases the user's critical hit ratio by 1 st } PASSES_RANDOMLY(1, chance, RNG_CRITICAL_HIT); GIVEN { - WITH_CONFIG(GEN_CONFIG_CRIT_CHANCE, genConfig); + WITH_CONFIG(GEN_CONFIG_CRIT_CHANCE, (genConfig == GEN_1)? GEN_2 : genConfig); + WITH_CONFIG(GEN_CONFIG_FOCUS_ENERGY_CRIT_RATIO, genConfig); + ASSUME(GetSpeciesBaseSpeed(SPECIES_WOBBUFFET) == 33); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + if (useFocusEnergy) + TURN { MOVE(player, MOVE_FOCUS_ENERGY); } + TURN { MOVE(player, MOVE_SCRATCH); } + } SCENE { + if (useFocusEnergy) + ANIMATION(ANIM_TYPE_MOVE, MOVE_FOCUS_ENERGY, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, player); + MESSAGE("A critical hit!"); + } +} + +SINGLE_BATTLE_TEST("Focus Energy multiplies crit chance by 4 with gen 1 crit chance") +{ + bool32 useFocusEnergy = 0; + u32 genConfig = 0, chance = 0; + for (u32 j = GEN_1; j <= GEN_9; j++) { + PARAMETRIZE { genConfig = j; useFocusEnergy = FALSE; chance = 16;} + PARAMETRIZE { genConfig = j; useFocusEnergy = TRUE; chance = 4;} + } + PASSES_RANDOMLY(1, chance, RNG_CRITICAL_HIT); + GIVEN { + WITH_CONFIG(GEN_CONFIG_CRIT_CHANCE, GEN_1); WITH_CONFIG(GEN_CONFIG_FOCUS_ENERGY_CRIT_RATIO, genConfig); ASSUME(GetSpeciesBaseSpeed(SPECIES_WOBBUFFET) == 33); PLAYER(SPECIES_WOBBUFFET); diff --git a/test/battle/move_effect/future_sight.c b/test/battle/move_effect/future_sight.c index 246c384a0..ee424c9bd 100644 --- a/test/battle/move_effect/future_sight.c +++ b/test/battle/move_effect/future_sight.c @@ -1,10 +1,18 @@ #include "global.h" #include "test/battle.h" +#if B_UPDATED_MOVE_DATA >= GEN_6 + #define FUTURE_SIGHT_EQUIVALENT MOVE_SEED_FLARE /* 120 power */ +#elif B_UPDATED_MOVE_DATA >= GEN_5 + #define FUTURE_SIGHT_EQUIVALENT MOVE_DYNAMAX_CANNON /* 100 power */ +#else + #define FUTURE_SIGHT_EQUIVALENT MOVE_EXTRASENSORY /* 80 power */ +#endif + ASSUMPTIONS { - ASSUME(GetMovePower(MOVE_SEED_FLARE) == GetMovePower(MOVE_FUTURE_SIGHT)); - ASSUME(GetMoveCategory(MOVE_SEED_FLARE) == GetMoveCategory(MOVE_FUTURE_SIGHT)); + ASSUME(GetMovePower(FUTURE_SIGHT_EQUIVALENT) == GetMovePower(MOVE_FUTURE_SIGHT)); + ASSUME(GetMoveCategory(FUTURE_SIGHT_EQUIVALENT) == GetMoveCategory(MOVE_FUTURE_SIGHT)); ASSUME(GetMoveEffect(MOVE_FUTURE_SIGHT) == EFFECT_FUTURE_SIGHT); ASSUME(GetMovePower(MOVE_FUTURE_SIGHT) > 0); } @@ -23,13 +31,13 @@ SINGLE_BATTLE_TEST("Future Sight uses Sp. Atk stat of the original user without PLAYER(SPECIES_RAICHU) { Item(item); } OPPONENT(SPECIES_REGICE); } WHEN { - TURN { MOVE(player, MOVE_SEED_FLARE, WITH_RNG(RNG_SECONDARY_EFFECT, FALSE)); } + TURN { MOVE(player, FUTURE_SIGHT_EQUIVALENT, WITH_RNG(RNG_SECONDARY_EFFECT, FALSE)); } TURN { MOVE(player, MOVE_FUTURE_SIGHT); } TURN { SWITCH(player, 1); } TURN { } TURN { } } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_SEED_FLARE, player); + ANIMATION(ANIM_TYPE_MOVE, FUTURE_SIGHT_EQUIVALENT, player); HP_BAR(opponent, captureDamage: &seedFlareDmg); ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, player); MESSAGE("The opposing Regice took the Future Sight attack!"); @@ -49,13 +57,13 @@ SINGLE_BATTLE_TEST("Future Sight is not boosted by Life Orb is original user if PLAYER(SPECIES_RAICHU) { Item(ITEM_LIFE_ORB); } OPPONENT(SPECIES_REGICE); } WHEN { - TURN { MOVE(player, MOVE_SEED_FLARE, WITH_RNG(RNG_SECONDARY_EFFECT, FALSE)); } + TURN { MOVE(player, FUTURE_SIGHT_EQUIVALENT, WITH_RNG(RNG_SECONDARY_EFFECT, FALSE)); } TURN { MOVE(player, MOVE_FUTURE_SIGHT); } TURN { SWITCH(player, 1); } TURN { } TURN { } } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_SEED_FLARE, player); + ANIMATION(ANIM_TYPE_MOVE, FUTURE_SIGHT_EQUIVALENT, player); HP_BAR(opponent, captureDamage: &seedFlareDmg); ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, player); MESSAGE("The opposing Regice took the Future Sight attack!"); @@ -77,13 +85,13 @@ SINGLE_BATTLE_TEST("Future Sight receives STAB from party mon (Gen 5+)") PLAYER(SPECIES_RAICHU); OPPONENT(SPECIES_REGICE); } WHEN { - TURN { MOVE(player, MOVE_SEED_FLARE, WITH_RNG(RNG_SECONDARY_EFFECT, FALSE)); } + TURN { MOVE(player, FUTURE_SIGHT_EQUIVALENT, WITH_RNG(RNG_SECONDARY_EFFECT, FALSE)); } TURN { MOVE(player, MOVE_FUTURE_SIGHT); } TURN { SWITCH(player, 1); } TURN { } TURN { } } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_SEED_FLARE, player); + ANIMATION(ANIM_TYPE_MOVE, FUTURE_SIGHT_EQUIVALENT, player); HP_BAR(opponent, captureDamage: &seedFlareDmg); ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, player); HP_BAR(opponent, captureDamage: &futureSightDmg); @@ -100,13 +108,13 @@ SINGLE_BATTLE_TEST("Future Sight is affected by type effectiveness (Gen 5+)") PLAYER(SPECIES_RAICHU); OPPONENT(SPECIES_HOUNDOOM); } WHEN { - TURN { MOVE(player, MOVE_SEED_FLARE, WITH_RNG(RNG_SECONDARY_EFFECT, FALSE)); } + TURN { MOVE(player, FUTURE_SIGHT_EQUIVALENT, WITH_RNG(RNG_SECONDARY_EFFECT, FALSE)); } TURN { MOVE(player, MOVE_FUTURE_SIGHT); } TURN { SWITCH(player, 1); } TURN { } TURN { } } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_SEED_FLARE, player); + ANIMATION(ANIM_TYPE_MOVE, FUTURE_SIGHT_EQUIVALENT, player); HP_BAR(opponent); ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, player); MESSAGE("The opposing Houndoom took the Future Sight attack!"); diff --git a/test/battle/move_effect/grudge.c b/test/battle/move_effect/grudge.c index f0e0e53b6..870d39c20 100644 --- a/test/battle/move_effect/grudge.c +++ b/test/battle/move_effect/grudge.c @@ -2,3 +2,52 @@ #include "test/battle.h" TO_DO_BATTLE_TEST("TODO: Write Grudge (Move Effect) test titles") + +SINGLE_BATTLE_TEST("Grudge depletes all pp of the move that fainted the target") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_SCRATCH, MOVE_POUND, MOVE_SURF); }; + } WHEN { + TURN { + MOVE(player, MOVE_GRUDGE); + MOVE(opponent, MOVE_SCRATCH); + SEND_OUT(player, 1); + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_GRUDGE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponent); + MESSAGE("Wobbuffet fainted!"); + } THEN { + EXPECT_GT(opponent->pp[0], 0); + EXPECT_EQ(opponent->pp[1], 0); + EXPECT_GT(opponent->pp[2], 0); + EXPECT_GT(opponent->pp[3], 0); + } +} + +SINGLE_BATTLE_TEST("Grudge does not depletes pp of a z-move") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); Moves(MOVE_CELEBRATE, MOVE_SCRATCH, MOVE_POUND, MOVE_SURF); }; + } WHEN { + TURN { + MOVE(player, MOVE_GRUDGE); + MOVE(opponent, MOVE_SCRATCH, gimmick: GIMMICK_Z_MOVE); + SEND_OUT(player, 1); + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_GRUDGE, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ZMOVE_ACTIVATE, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BREAKNECK_BLITZ, opponent); + MESSAGE("Wobbuffet fainted!"); + } THEN { + EXPECT_GT(opponent->pp[0], 0); + EXPECT_GT(opponent->pp[1], 0); + EXPECT_GT(opponent->pp[2], 0); + EXPECT_GT(opponent->pp[3], 0); + } +} diff --git a/test/battle/move_effect/hidden_power.c b/test/battle/move_effect/hidden_power.c index a04482eb2..9ac88e687 100644 --- a/test/battle/move_effect/hidden_power.c +++ b/test/battle/move_effect/hidden_power.c @@ -31,7 +31,8 @@ ASSUMPTIONS // IV combinations sourced from https://www.smogon.com/forums/threads/hidden-power-iv-combinations.78083/ SINGLE_BATTLE_TEST("Hidden Power's type is determined by IVs") { - u32 type, j, foeType, foeSpecies, foeItem; + enum Type type, foeType, j; + u32 foeSpecies, foeItem; u32 hp, atk, def, spAtk, spDef, speed; bool32 hidden; diff --git a/test/battle/move_effect/hit_escape.c b/test/battle/move_effect/hit_escape.c index 0ced64d7e..f587d078a 100644 --- a/test/battle/move_effect/hit_escape.c +++ b/test/battle/move_effect/hit_escape.c @@ -113,7 +113,7 @@ SINGLE_BATTLE_TEST("Hit Escape: U-turn switches the user out after Ice Face acti } } -SINGLE_BATTLE_TEST("Hit Escape: Held items are consumed immediately after a mon switched in by U-turn and Intimidate activates after it: player side") +SINGLE_BATTLE_TEST("Hit Escape: Held items are consumed immediately after a mon switched in by U-turn: player side") { GIVEN { PLAYER(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); }; @@ -126,7 +126,6 @@ SINGLE_BATTLE_TEST("Hit Escape: Held items are consumed immediately after a mon ABILITY_POPUP(player, ABILITY_ELECTRIC_SURGE); ANIMATION(ANIM_TYPE_MOVE, MOVE_U_TURN, player); HP_BAR(opponent); - ABILITY_POPUP(player, ABILITY_INTIMIDATE); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); MESSAGE("2 sent out Wynaut!"); @@ -136,7 +135,7 @@ SINGLE_BATTLE_TEST("Hit Escape: Held items are consumed immediately after a mon } } -SINGLE_BATTLE_TEST("Hit Escape: Held items are consumed immediately after a mon switched in by U-turn and Intimidate activates after it: opposing side") +SINGLE_BATTLE_TEST("Hit Escape: Held items are consumed immediately after a mon switched in by U-turn: opposing side") { GIVEN { PLAYER(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); }; @@ -149,7 +148,6 @@ SINGLE_BATTLE_TEST("Hit Escape: Held items are consumed immediately after a mon ABILITY_POPUP(player, ABILITY_ELECTRIC_SURGE); ANIMATION(ANIM_TYPE_MOVE, MOVE_U_TURN, player); HP_BAR(opponent); - ABILITY_POPUP(player, ABILITY_INTIMIDATE); MESSAGE("2 sent out Wynaut!"); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); diff --git a/test/battle/move_effect/instruct.c b/test/battle/move_effect/instruct.c index 03a39fe15..070b6ba31 100644 --- a/test/battle/move_effect/instruct.c +++ b/test/battle/move_effect/instruct.c @@ -280,6 +280,7 @@ DOUBLE_BATTLE_TEST("Instructed move will be redirected by Rage Powder after inst PARAMETRIZE { moveTarget = opponentLeft; } PARAMETRIZE { moveTarget = opponentRight; } GIVEN { + WITH_CONFIG(GEN_CONFIG_POWDER_GRASS, GEN_6); ASSUME(GetMoveEffect(MOVE_RAGE_POWDER) == EFFECT_FOLLOW_ME); ASSUME(IsPowderMove(MOVE_RAGE_POWDER) == TRUE); ASSUME(GetMoveEffect(MOVE_SOAK) == EFFECT_SOAK); diff --git a/test/battle/move_effect/knock_off.c b/test/battle/move_effect/knock_off.c index 3fdeadcec..eb0874d7b 100644 --- a/test/battle/move_effect/knock_off.c +++ b/test/battle/move_effect/knock_off.c @@ -6,6 +6,33 @@ ASSUMPTIONS ASSUME(GetMoveEffect(MOVE_KNOCK_OFF) == EFFECT_KNOCK_OFF); } +WILD_BATTLE_TEST("Knock Off does not remove item when used by Wild Pokemon (Gen 5+)") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_LEFTOVERS); } + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_EVIOLITE); } + } WHEN { + TURN { MOVE(opponent, MOVE_KNOCK_OFF); } + TURN { MOVE(player, MOVE_KNOCK_OFF); } + } SCENE { + // Turn 1 + ANIMATION(ANIM_TYPE_MOVE, MOVE_KNOCK_OFF, opponent); + if (B_KNOCK_OFF_REMOVAL >= GEN_5) + NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ITEM_KNOCKOFF, player); + else + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ITEM_KNOCKOFF, player); + // Turn 2 + ANIMATION(ANIM_TYPE_MOVE, MOVE_KNOCK_OFF, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ITEM_KNOCKOFF, opponent); + } THEN { + EXPECT(player->item == ITEM_LEFTOVERS); + if (B_KNOCK_OFF_REMOVAL >= GEN_5) + EXPECT(opponent->item == ITEM_NONE); + else + EXPECT(opponent->item == ITEM_EVIOLITE); + } +} + SINGLE_BATTLE_TEST("Knock Off knocks a healing berry before it has the chance to activate") { GIVEN { diff --git a/test/battle/move_effect/last_resort.c b/test/battle/move_effect/last_resort.c index 602f4ad2a..089a72330 100644 --- a/test/battle/move_effect/last_resort.c +++ b/test/battle/move_effect/last_resort.c @@ -117,7 +117,7 @@ SINGLE_BATTLE_TEST("Last Resort works with Sleep Talk") AI_SINGLE_BATTLE_TEST("AI uses Last Resort - 2 moves") { - KNOWN_FAILING; + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); GIVEN { PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_LAST_RESORT, MOVE_SCRATCH); } @@ -129,10 +129,10 @@ AI_SINGLE_BATTLE_TEST("AI uses Last Resort - 2 moves") AI_SINGLE_BATTLE_TEST("AI uses Last Resort - 3 moves") { - KNOWN_FAILING; + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); GIVEN { PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_LAST_RESORT, MOVE_QUICK_ATTACK, MOVE_SCRATCH); } + OPPONENT(SPECIES_WOBBUFFET) { MovesWithPP({MOVE_LAST_RESORT, 5}, {MOVE_QUICK_ATTACK, 1}, {MOVE_SCRATCH, 35}); } } WHEN { TURN { NOT_EXPECT_MOVE(opponent, MOVE_LAST_RESORT); } TURN { NOT_EXPECT_MOVE(opponent, MOVE_LAST_RESORT); } @@ -142,10 +142,10 @@ AI_SINGLE_BATTLE_TEST("AI uses Last Resort - 3 moves") AI_SINGLE_BATTLE_TEST("AI uses Last Resort - 4 moves") { - KNOWN_FAILING; + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); GIVEN { PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_LAST_RESORT, MOVE_QUICK_ATTACK, MOVE_SCRATCH, MOVE_GUST); } + OPPONENT(SPECIES_WOBBUFFET) { MovesWithPP({MOVE_LAST_RESORT, 5}, {MOVE_QUICK_ATTACK, 1}, {MOVE_SCRATCH, 1}, {MOVE_GUST, 35}); } } WHEN { TURN { NOT_EXPECT_MOVE(opponent, MOVE_LAST_RESORT); } TURN { NOT_EXPECT_MOVE(opponent, MOVE_LAST_RESORT); } diff --git a/test/battle/move_effect/magic_room.c b/test/battle/move_effect/magic_room.c index cffd6034d..02953f533 100644 --- a/test/battle/move_effect/magic_room.c +++ b/test/battle/move_effect/magic_room.c @@ -36,4 +36,43 @@ DOUBLE_BATTLE_TEST("Magic Room prevents item hold effects") } } +SINGLE_BATTLE_TEST("Magic Room: An item that can activate will activate once Magic Room is over") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_WHITE_HERB); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_MAGIC_ROOM); MOVE(opponent, MOVE_GROWL); } + TURN {} + TURN {} + TURN {} + TURN {} + TURN {} + } SCENE { + // Turn 1 + ANIMATION(ANIM_TYPE_MOVE, MOVE_MAGIC_ROOM, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_GROWL, opponent); + // Turn 2 + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); + // Turn 3 + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); + // Turn 4 + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); + // Turn 5 + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); + + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); + } + + MESSAGE("Magic Room wore off, and held items' effects returned to normal!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + } +} + TO_DO_BATTLE_TEST("TODO: Write Magic Room (Move Effect) test titles") diff --git a/test/battle/move_effect/misty_terrain.c b/test/battle/move_effect/misty_terrain.c index b96f0c650..cd9a92eb3 100644 --- a/test/battle/move_effect/misty_terrain.c +++ b/test/battle/move_effect/misty_terrain.c @@ -87,3 +87,16 @@ SINGLE_BATTLE_TEST("Misty Terrain lasts for 5 turns") MESSAGE("The mist disappeared from the battlefield."); } } + +SINGLE_BATTLE_TEST("Misty Terrain will fail if there is one already on the field") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_MISTY_TERRAIN); MOVE(opponent, MOVE_MISTY_TERRAIN); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_MISTY_TERRAIN, player); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_MISTY_TERRAIN, opponent); + } +} diff --git a/test/battle/move_effect/multi_hit.c b/test/battle/move_effect/multi_hit.c index 7052a52cb..291c78efd 100644 --- a/test/battle/move_effect/multi_hit.c +++ b/test/battle/move_effect/multi_hit.c @@ -177,14 +177,14 @@ SINGLE_BATTLE_TEST("Scale Shot is immune to Fairy types and will end the move co GIVEN { ASSUME(GetMoveEffect(MOVE_SCALE_SHOT) == EFFECT_MULTI_HIT); ASSUME(GetMoveType(MOVE_SCALE_SHOT) == TYPE_DRAGON); - ASSUME(GetSpeciesType(SPECIES_CLEFAIRY, 0) == TYPE_FAIRY || GetSpeciesType(SPECIES_CLEFAIRY, 1) == TYPE_FAIRY); + ASSUME(GetSpeciesType(SPECIES_FIDOUGH, 0) == TYPE_FAIRY || GetSpeciesType(SPECIES_FIDOUGH, 1) == TYPE_FAIRY); PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_CLEFAIRY) { HP(1); } + OPPONENT(SPECIES_FIDOUGH) { HP(1); } } WHEN { TURN { MOVE(player, MOVE_SCALE_SHOT); } } SCENE { NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_SCALE_SHOT, player); - MESSAGE("It doesn't affect the opposing Clefairy…"); + MESSAGE("It doesn't affect the opposing Fidough…"); } } diff --git a/test/battle/move_effect/nature_power.c b/test/battle/move_effect/nature_power.c index 1e9692f88..53aa68442 100644 --- a/test/battle/move_effect/nature_power.c +++ b/test/battle/move_effect/nature_power.c @@ -1,4 +1,27 @@ #include "global.h" #include "test/battle.h" +#include "battle_environment.h" -TO_DO_BATTLE_TEST("TODO: Write Nature Power (Move Effect) test titles") +//TO_DO_BATTLE_TEST("TODO: Write Nature Power (Move Effect) test titles") + +SINGLE_BATTLE_TEST("Nature power plays a move correctly in any background") +{ + u32 environment = 0; + u32 move = MOVE_TRI_ATTACK; + for (u32 j = 0; j < BATTLE_ENVIRONMENT_COUNT; j++) + { + PARAMETRIZE {environment = i;} + } + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + Environment(environment); + if (gBattleEnvironmentInfo[environment].naturePower) + move = gBattleEnvironmentInfo[environment].naturePower; + } WHEN { + TURN { MOVE(player, MOVE_NATURE_POWER); } + } SCENE { + NOT MESSAGE("Nature Power turned into Nature Power!"); + ANIMATION(ANIM_TYPE_MOVE, move, player); + } +} diff --git a/test/battle/move_effect/powder.c b/test/battle/move_effect/powder.c index c4e053db8..da8eba4ca 100644 --- a/test/battle/move_effect/powder.c +++ b/test/battle/move_effect/powder.c @@ -149,9 +149,10 @@ DOUBLE_BATTLE_TEST("Powder fails if target is already affected by Powder") } } -SINGLE_BATTLE_TEST("Powder fails if the target is Grass type") +SINGLE_BATTLE_TEST("Powder fails if the target is Grass type (Gen6+)") { GIVEN { + WITH_CONFIG(GEN_CONFIG_POWDER_GRASS, GEN_6); ASSUME(GetSpeciesType(SPECIES_VENUSAUR, 0) == TYPE_GRASS || GetSpeciesType(SPECIES_VENUSAUR, 1) == TYPE_GRASS); PLAYER(SPECIES_VENUSAUR); OPPONENT(SPECIES_VIVILLON); @@ -164,9 +165,10 @@ SINGLE_BATTLE_TEST("Powder fails if the target is Grass type") } } -SINGLE_BATTLE_TEST("Powder fails if the target has Overcoat") +SINGLE_BATTLE_TEST("Powder fails if the target has Overcoat (Gen6+)") { GIVEN { + WITH_CONFIG(GEN_CONFIG_POWDER_GRASS, GEN_6); PLAYER(SPECIES_FORRETRESS) { Ability(ABILITY_OVERCOAT); } OPPONENT(SPECIES_VIVILLON); } WHEN { diff --git a/test/battle/move_effect/psychic_terrain.c b/test/battle/move_effect/psychic_terrain.c index 40df878a1..e17964464 100644 --- a/test/battle/move_effect/psychic_terrain.c +++ b/test/battle/move_effect/psychic_terrain.c @@ -114,6 +114,38 @@ SINGLE_BATTLE_TEST("Psychic Terrain doesn't block priority field moves") } } +SINGLE_BATTLE_TEST("Psychic Terrain doesn't block priority moves against semi-invulnerable targets") +{ + u32 move = 0, shouldWork = 0; + PARAMETRIZE { move = MOVE_SOLAR_BEAM; shouldWork = FALSE;} + PARAMETRIZE { move = MOVE_FLY; shouldWork = TRUE;} + GIVEN { + PLAYER(SPECIES_SHROODLE) { Ability(ABILITY_PRANKSTER); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_PSYCHIC_TERRAIN); MOVE(opponent,move);} + TURN { MOVE(player, MOVE_TOXIC); SKIP_TURN(opponent);} + } SCENE { + if (shouldWork) + { + ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC, player); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent); + } + else + { + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC, player); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent); + } + } + } THEN { + if (shouldWork) + EXPECT(opponent->status1 & STATUS1_TOXIC_POISON); + else + EXPECT(!(opponent->status1 & STATUS1_TOXIC_POISON)); + } +} + SINGLE_BATTLE_TEST("Psychic Terrain lasts for 5 turns") { GIVEN { diff --git a/test/battle/move_effect/purify.c b/test/battle/move_effect/purify.c index 5f1651e96..425d0a99a 100644 --- a/test/battle/move_effect/purify.c +++ b/test/battle/move_effect/purify.c @@ -22,5 +22,45 @@ AI_DOUBLE_BATTLE_TEST("AI uses Purify") } } +AI_SINGLE_BATTLE_TEST("AI uses Purify to heal an enemy with Guts") +{ + u32 ability; + + PARAMETRIZE { ability = ABILITY_GUTS; } + PARAMETRIZE { ability = ABILITY_BULLETPROOF; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT); + PLAYER(SPECIES_URSALUNA) { Ability(ability); Moves(MOVE_HEADLONG_RUSH, MOVE_CELEBRATE); Status1(STATUS1_BURN); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_HEADBUTT, MOVE_PURIFY); } + } WHEN { + if (ability == ABILITY_GUTS) + TURN { EXPECT_MOVE(opponent, MOVE_PURIFY); } + else + TURN { NOT_EXPECT_MOVE(opponent, MOVE_PURIFY); } + } +} + +AI_DOUBLE_BATTLE_TEST("AI does not use Purify to heal an ally with Guts") +{ + u32 ability; + + PARAMETRIZE { ability = ABILITY_GUTS; } + PARAMETRIZE { ability = ABILITY_BULLETPROOF; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_HEADBUTT, MOVE_PURIFY); } + OPPONENT(SPECIES_URSALUNA) { Ability(ability); Moves(MOVE_HEADLONG_RUSH); Status1(STATUS1_BURN); } + } WHEN { + if (ability == ABILITY_GUTS) + TURN { NOT_EXPECT_MOVE(opponentLeft, MOVE_PURIFY); } + else + TURN { EXPECT_MOVE(opponentLeft, MOVE_PURIFY, target: opponentRight); } + } +} + TO_DO_BATTLE_TEST("TODO: Write Purify (Move Effect) test titles") TO_DO_BATTLE_TEST("Purify doesn't heal HP if the target has Comatose") diff --git a/test/battle/move_effect/rest.c b/test/battle/move_effect/rest.c index 4d0d85b56..fcf2b1556 100644 --- a/test/battle/move_effect/rest.c +++ b/test/battle/move_effect/rest.c @@ -1,4 +1,121 @@ #include "global.h" #include "test/battle.h" +ASSUMPTIONS +{ + ASSUME(GetMoveEffect(MOVE_REST) == EFFECT_REST); +} + +SINGLE_BATTLE_TEST("Rest causes the user to fall asleep and restores HP to full") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(1); MaxHP(300); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_REST); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_REST, player); + } THEN { + EXPECT(player->status1 & STATUS1_SLEEP); + EXPECT_EQ(player->hp, player->maxHP); + } +} + +SINGLE_BATTLE_TEST("Rest fails if the user is at full HP") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(300); MaxHP(300); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_REST); } + } SCENE { + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_REST, player); + } THEN { + EXPECT(!(player->status1 & STATUS1_SLEEP)); + } +} + +SINGLE_BATTLE_TEST("Rest fails if the user is protected by Leaf Guard") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_SUNNY_DAY) == EFFECT_SUNNY_DAY); + ASSUME(B_LEAF_GUARD_PREVENTS_REST >= GEN_5); + PLAYER(SPECIES_CHIKORITA) { Ability(ABILITY_LEAF_GUARD); HP(1); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SUNNY_DAY); MOVE(player, MOVE_REST); } + } SCENE { + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_REST, player); + } THEN { + EXPECT(!(player->status1 & STATUS1_SLEEP)); + } +} + +SINGLE_BATTLE_TEST("Rest fails if the user is protected by Shields Down") +{ + GIVEN { + PLAYER(SPECIES_MINIOR_METEOR) { Ability(ABILITY_SHIELDS_DOWN); HP(299); MaxHP(300); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_REST); } + } SCENE { + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_REST, player); + } THEN { + EXPECT(!(player->status1 & STATUS1_SLEEP)); + } +} + +SINGLE_BATTLE_TEST("Rest fails if the user is protected by Electric/Misty Terrain") +{ + u32 move; + PARAMETRIZE { move = MOVE_ELECTRIC_TERRAIN; } + PARAMETRIZE { move = MOVE_MISTY_TERRAIN; } + GIVEN { + ASSUME(GetMoveEffect(MOVE_ELECTRIC_TERRAIN) == EFFECT_ELECTRIC_TERRAIN); + ASSUME(GetMoveEffect(MOVE_MISTY_TERRAIN) == EFFECT_MISTY_TERRAIN); + ASSUME(GetSpeciesType(SPECIES_WYNAUT, 0) != TYPE_FLYING && GetSpeciesType(SPECIES_WYNAUT, 1) != TYPE_FLYING); + PLAYER(SPECIES_WYNAUT) { HP(1); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, move); MOVE(player, MOVE_REST); } + } SCENE { + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_REST, player); + } THEN { + EXPECT(!(player->status1 & STATUS1_SLEEP)); + } +} + +SINGLE_BATTLE_TEST("Rest doesn't fail if the user is protected by Safeguard") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_SAFEGUARD) == EFFECT_SAFEGUARD); + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_SAFEGUARD); } + TURN { MOVE(player, MOVE_REST); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_REST, player); + } THEN { + EXPECT(player->status1 & STATUS1_SLEEP); + } +} + +DOUBLE_BATTLE_TEST("Rest doesn't fail if the user is protected by Flower Veil") +{ + GIVEN { + ASSUME(GetSpeciesType(SPECIES_CHIKORITA, 0) == TYPE_GRASS || GetSpeciesType(SPECIES_CHIKORITA, 1) == TYPE_GRASS); + PLAYER(SPECIES_CHIKORITA) { HP(1); } + PLAYER(SPECIES_FLORGES) { Ability(ABILITY_FLOWER_VEIL); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(playerLeft, MOVE_REST); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_REST, playerLeft); + } THEN { + EXPECT(playerLeft->status1 & STATUS1_SLEEP); + } +} + TO_DO_BATTLE_TEST("TODO: Write Rest (Move Effect) test titles") diff --git a/test/battle/move_effect/revival_blessing.c b/test/battle/move_effect/revival_blessing.c index f1a0ad74b..eeb90d202 100644 --- a/test/battle/move_effect/revival_blessing.c +++ b/test/battle/move_effect/revival_blessing.c @@ -49,29 +49,36 @@ SINGLE_BATTLE_TEST("Revival Blessing fails if no party members are fainted") } } -DOUBLE_BATTLE_TEST("Revival Blessing cannot revive a partner's party member") +// Can only be tested through AI test, else test fails due to trying to force illegal action +AI_MULTI_BATTLE_TEST("Revival Blessing cannot revive a partner's party member") { - KNOWN_FAILING; struct BattlePokemon *user = NULL; - gBattleTypeFlags |= BATTLE_TYPE_TWO_OPPONENTS; - PARAMETRIZE { user = opponentLeft; } - PARAMETRIZE { user = opponentRight; } + u32 move1, move2, move3; + PARAMETRIZE { user = opponentLeft, move1 = MOVE_REVIVAL_BLESSING, move2 = MOVE_CELEBRATE, move3 = MOVE_CELEBRATE; } + PARAMETRIZE { user = playerRight, move1 = MOVE_CELEBRATE, move2 = MOVE_REVIVAL_BLESSING, move3 = MOVE_CELEBRATE; } + PARAMETRIZE { user = opponentRight, move1 = MOVE_CELEBRATE, move2 = MOVE_CELEBRATE, move3 = MOVE_REVIVAL_BLESSING; } GIVEN { - ASSUME((gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) != FALSE); - PLAYER(SPECIES_WOBBUFFET); - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WYNAUT); - OPPONENT(SPECIES_WYNAUT) { HP(0); } - OPPONENT(SPECIES_WYNAUT); + MULTI_PLAYER(SPECIES_CLEFABLE); + MULTI_PLAYER(SPECIES_CLEFABLE) { HP(0); } + MULTI_PLAYER(SPECIES_CLEFABLE); + MULTI_PARTNER(SPECIES_CLEFAIRY) { Moves(move2); } + MULTI_PARTNER(SPECIES_CLEFAIRY); + MULTI_PARTNER(SPECIES_CLEFAIRY); + MULTI_OPPONENT_A(SPECIES_WOBBUFFET) { Moves(move1); } + MULTI_OPPONENT_A(SPECIES_WOBBUFFET); + MULTI_OPPONENT_A(SPECIES_WOBBUFFET); + MULTI_OPPONENT_B(SPECIES_WYNAUT) { Moves(move3); } + MULTI_OPPONENT_B(SPECIES_WYNAUT) { HP(0); } + MULTI_OPPONENT_B(SPECIES_WYNAUT); } WHEN { - TURN { MOVE(user, MOVE_REVIVAL_BLESSING, partyIndex:4); } + TURN { EXPECT_MOVE(playerRight, move2); } // EXPECT_MOVE makes battler2 AI-controlled } SCENE { if (user == opponentLeft) { MESSAGE("The opposing Wobbuffet used Revival Blessing!"); MESSAGE("But it failed!"); + } else if (user == playerRight) { + MESSAGE("Clefairy used Revival Blessing!"); + MESSAGE("But it failed!"); } else { MESSAGE("The opposing Wynaut used Revival Blessing!"); MESSAGE("Wynaut was revived and is ready to fight again!"); diff --git a/test/battle/move_effect/simple_beam.c b/test/battle/move_effect/simple_beam.c index 54e8f4ca2..66d2a59fc 100644 --- a/test/battle/move_effect/simple_beam.c +++ b/test/battle/move_effect/simple_beam.c @@ -3,7 +3,8 @@ ASSUMPTIONS { - ASSUME(GetMoveEffect(MOVE_SIMPLE_BEAM) == EFFECT_SIMPLE_BEAM); + ASSUME(GetMoveEffect(MOVE_SIMPLE_BEAM) == EFFECT_OVERWRITE_ABILITY); + ASSUME(GetMoveOverwriteAbility(MOVE_SIMPLE_BEAM) == ABILITY_SIMPLE); } SINGLE_BATTLE_TEST("Simple Beam replaces target's ability with Simple") diff --git a/test/battle/move_effect/stomping_tantrum.c b/test/battle/move_effect/stomping_tantrum.c index 95d93e07e..06b29334d 100644 --- a/test/battle/move_effect/stomping_tantrum.c +++ b/test/battle/move_effect/stomping_tantrum.c @@ -90,6 +90,31 @@ SINGLE_BATTLE_TEST("Stomping Tantrum will not deal double damage if target prote } } +SINGLE_BATTLE_TEST("Stomping Tantrum will deal double damage if user failed a Protect") +{ + s16 damage[2]; + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_STOMPING_TANTRUM); } + TURN { MOVE(player, MOVE_PROTECT); } + TURN { MOVE(player, MOVE_PROTECT, WITH_RNG(RNG_PROTECT_FAIL, USHRT_MAX)); } + TURN { MOVE(player, MOVE_STOMPING_TANTRUM); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STOMPING_TANTRUM, player); + HP_BAR(opponent, captureDamage: &damage[0]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_PROTECT, player); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_PROTECT, player); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_STOMPING_TANTRUM, player); + HP_BAR(opponent, captureDamage: &damage[1]); + } THEN { + EXPECT_MUL_EQ(damage[0], Q_4_12(2.0), damage[1]); + } +} + SINGLE_BATTLE_TEST("Stomping Tantrum will not deal double if it missed") { s16 damage[2]; diff --git a/test/battle/move_effect/struggle.c b/test/battle/move_effect/struggle.c new file mode 100644 index 000000000..5bf9de620 --- /dev/null +++ b/test/battle/move_effect/struggle.c @@ -0,0 +1,75 @@ +#include "global.h" +#include "test/battle.h" + +TO_DO_BATTLE_TEST("Struggle deals recoil 1/4 of damage dealt (Gen 2-3)") + +SINGLE_BATTLE_TEST("Struggle deals recoil 1/4 of user's hp (Gen 4+)") +{ + ASSUME(GetMoveEffect(MOVE_STRUGGLE) == EFFECT_STRUGGLE); + + s16 recoil; + u32 atkStat = 0; + u32 hpStat = 0; + + PARAMETRIZE { atkStat = 100; hpStat = 200; } + PARAMETRIZE { atkStat = 50; hpStat = 200; } + PARAMETRIZE { atkStat = 100; hpStat = 300; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { MaxHP(hpStat); HP(hpStat); Attack(atkStat); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_STRUGGLE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STRUGGLE, player); + HP_BAR(player, captureDamage: &recoil); + } THEN { + EXPECT_MUL_EQ(hpStat, Q_4_12(0.25), recoil); + } +} + +SINGLE_BATTLE_TEST("Struggle can hit ghost types") +{ + ASSUME(GetSpeciesType(SPECIES_DRIFBLIM, 0) == TYPE_GHOST); + + s16 damage; + + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_DRIFBLIM); + } WHEN { + TURN { MOVE(player, MOVE_STRUGGLE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STRUGGLE, player); + HP_BAR(opponent, captureDamage: &damage); + } THEN { + EXPECT_NE(0, damage); + } +} + +SINGLE_BATTLE_TEST("Struggle does not receive normal-type STAB") +{ + // Compare with Cut, which does receive normal-type STAB + ASSUME(GetSpeciesType(SPECIES_ZANGOOSE, 0) == GetMoveType(MOVE_STRUGGLE)); + ASSUME(GetMovePower(MOVE_CUT) == GetMovePower(MOVE_STRUGGLE)); + ASSUME(GetMoveCategory(MOVE_CUT) == GetMoveCategory(MOVE_STRUGGLE)); + ASSUME(GetMoveType(MOVE_CUT) == GetMoveType(MOVE_STRUGGLE)); + + s16 cutDamage; + s16 struggleDamage; + + GIVEN { + PLAYER(SPECIES_ZANGOOSE); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_CUT); } + TURN { MOVE(player, MOVE_STRUGGLE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_CUT, player); + HP_BAR(opponent, captureDamage: &cutDamage); + ANIMATION(ANIM_TYPE_MOVE, MOVE_STRUGGLE, player); + HP_BAR(opponent, captureDamage: &struggleDamage); + } THEN { + EXPECT_MUL_EQ(struggleDamage, Q_4_12(1.5), cutDamage); + } +} diff --git a/test/battle/move_effect/tera_blast.c b/test/battle/move_effect/tera_blast.c index 060e28802..1e041dda9 100644 --- a/test/battle/move_effect/tera_blast.c +++ b/test/battle/move_effect/tera_blast.c @@ -24,7 +24,7 @@ SINGLE_BATTLE_TEST("Tera Blast changes from Normal-type to the user's Tera Type" SINGLE_BATTLE_TEST("Tera Blast has correct effectiveness for every Tera Type") { u32 species; - u32 type; + enum Type type; PARAMETRIZE { species = SPECIES_CHIKORITA; type = TYPE_FLYING; } PARAMETRIZE { species = SPECIES_CHIKORITA; type = TYPE_POISON; } diff --git a/test/battle/move_effect/toxic.c b/test/battle/move_effect/toxic.c index 52c5aa53c..045772db2 100644 --- a/test/battle/move_effect/toxic.c +++ b/test/battle/move_effect/toxic.c @@ -43,14 +43,16 @@ SINGLE_BATTLE_TEST("Toxic can't bad poison a poison or steel type") } } -SINGLE_BATTLE_TEST("Toxic cannot miss if used by a Poison-type") +SINGLE_BATTLE_TEST("Toxic cannot miss if used by a Poison-type (Gen6+)") { - u32 species; + u32 species, gen; bool32 hit; - PARAMETRIZE { species = SPECIES_WOBBUFFET; hit = FALSE; } - PARAMETRIZE { species = SPECIES_NIDORAN_M; hit = TRUE; } + PARAMETRIZE { species = SPECIES_WOBBUFFET; hit = FALSE; gen = GEN_5; } + PARAMETRIZE { species = SPECIES_NIDORAN_M; hit = FALSE; gen = GEN_5; } + PARAMETRIZE { species = SPECIES_WOBBUFFET; hit = FALSE; gen = GEN_6; } + PARAMETRIZE { species = SPECIES_NIDORAN_M; hit = TRUE; gen = GEN_6; } GIVEN { - ASSUME(B_TOXIC_NEVER_MISS >= GEN_6); + WITH_CONFIG(GEN_CONFIG_TOXIC_NEVER_MISS, gen); ASSUME(GetSpeciesType(SPECIES_NIDORAN_M, 0) == TYPE_POISON); PLAYER(species); OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/move_effect/worry_seed.c b/test/battle/move_effect/worry_seed.c index 1d87dc519..a53680208 100644 --- a/test/battle/move_effect/worry_seed.c +++ b/test/battle/move_effect/worry_seed.c @@ -3,7 +3,8 @@ ASSUMPTIONS { - ASSUME(GetMoveEffect(MOVE_WORRY_SEED) == EFFECT_WORRY_SEED); + ASSUME(GetMoveEffect(MOVE_WORRY_SEED) == EFFECT_OVERWRITE_ABILITY); + ASSUME(GetMoveOverwriteAbility(MOVE_WORRY_SEED) == ABILITY_INSOMNIA); } SINGLE_BATTLE_TEST("Worry Seed replaces target's ability with Insomnia") diff --git a/test/battle/move_effect_secondary/dire_claw.c b/test/battle/move_effect_secondary/dire_claw.c index 44cfd8ba1..17352fa70 100644 --- a/test/battle/move_effect_secondary/dire_claw.c +++ b/test/battle/move_effect_secondary/dire_claw.c @@ -38,11 +38,10 @@ SINGLE_BATTLE_TEST("Dire Claw cannot poison/paralyze poison/electric types respe u8 statusAnim; u16 species; u32 rng; - #if B_PARALYZE_ELECTRIC >= GEN_6 PARAMETRIZE { statusAnim = B_ANIM_STATUS_PRZ; rng = MOVE_EFFECT_PARALYSIS; species = SPECIES_RAICHU; } - #endif // B_PARALYZE_ELECTRIC PARAMETRIZE { statusAnim = B_ANIM_STATUS_PSN; rng = MOVE_EFFECT_POISON; species = SPECIES_ARBOK; } GIVEN { + WITH_CONFIG(GEN_CONFIG_PARALYZE_ELECTRIC, GEN_6); PLAYER(SPECIES_WOBBUFFET); OPPONENT(species); } WHEN { diff --git a/test/battle/move_effect_secondary/paralysis.c b/test/battle/move_effect_secondary/paralysis.c index baa218306..723309f01 100644 --- a/test/battle/move_effect_secondary/paralysis.c +++ b/test/battle/move_effect_secondary/paralysis.c @@ -21,19 +21,27 @@ SINGLE_BATTLE_TEST("Thunder Shock inflicts paralysis") } } -SINGLE_BATTLE_TEST("Thunder Shock cannot paralyze an Electric-type") +SINGLE_BATTLE_TEST("Thunder Shock cannot paralyze an Electric-type (Gen6+)") { + u32 gen = 0; + PARAMETRIZE { gen = GEN_5; } + PARAMETRIZE { gen = GEN_6; } GIVEN { - ASSUME(B_PARALYZE_ELECTRIC >= GEN_6); + WITH_CONFIG(GEN_CONFIG_PARALYZE_ELECTRIC, gen); ASSUME(GetSpeciesType(SPECIES_PIKACHU, 0) == TYPE_ELECTRIC); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_PIKACHU); } WHEN { - TURN { MOVE(player, MOVE_THUNDER_SHOCK); } + TURN { MOVE(player, MOVE_THUNDER_SHOCK, secondaryEffect: TRUE); } } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_THUNDER_SHOCK, player); HP_BAR(opponent); - NONE_OF { + if (gen == GEN_6) { + NONE_OF { + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, opponent); + STATUS_ICON(opponent, paralysis: TRUE); + } + } else { ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, opponent); STATUS_ICON(opponent, paralysis: TRUE); } diff --git a/test/battle/move_effect_secondary/recharge.c b/test/battle/move_effect_secondary/recharge.c new file mode 100644 index 000000000..914608367 --- /dev/null +++ b/test/battle/move_effect_secondary/recharge.c @@ -0,0 +1,52 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(MoveHasAdditionalEffectSelf(MOVE_METEOR_ASSAULT, MOVE_EFFECT_RECHARGE) == TRUE); +} + +SINGLE_BATTLE_TEST("Recharge moves make the user unable to attack for exactly one turn") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { } + OPPONENT(SPECIES_WOBBUFFET) { } + } WHEN { + TURN { MOVE(player, MOVE_METEOR_ASSAULT);} + TURN { SKIP_TURN(player);} + TURN { MOVE(player, MOVE_TACKLE);} + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_METEOR_ASSAULT, player); + MESSAGE("Wobbuffet must recharge!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player); + } +} + +SINGLE_BATTLE_TEST("Recharge moves don't timeout when all battlers are recharging") +{ + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { } + OPPONENT(SPECIES_WOBBUFFET) { } + } WHEN { + TURN { MOVE(player, MOVE_METEOR_ASSAULT); MOVE(opponent, MOVE_METEOR_ASSAULT);} + } +} + +DOUBLE_BATTLE_TEST("Recharge moves don't timeout when all battlers are recharging (doubles") +{ + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { } + PLAYER(SPECIES_WYNAUT) { } + OPPONENT(SPECIES_WOBBUFFET) { } + OPPONENT(SPECIES_WYNAUT) { } + } WHEN { + TURN { + MOVE(playerLeft, MOVE_METEOR_ASSAULT, target: opponentLeft); + MOVE(playerRight, MOVE_METEOR_ASSAULT, target: opponentRight); + MOVE(opponentLeft, MOVE_METEOR_ASSAULT, target: playerLeft); + MOVE(opponentRight, MOVE_METEOR_ASSAULT, target: playerRight); + } + } +} diff --git a/test/battle/move_effect_secondary/steal_item.c b/test/battle/move_effect_secondary/steal_item.c index 79c293757..e83d5c5cb 100644 --- a/test/battle/move_effect_secondary/steal_item.c +++ b/test/battle/move_effect_secondary/steal_item.c @@ -148,11 +148,12 @@ SINGLE_BATTLE_TEST("Thief and Covet can't steal target's held item if user faint } } -SINGLE_BATTLE_TEST("Thief and Covet: Berry activation happens before the item can be stolen") +SINGLE_BATTLE_TEST("Thief and Covet: Berries that activate on HP thresholds are stolen before they can activate") { u32 move; PARAMETRIZE { move = MOVE_THIEF; } PARAMETRIZE { move = MOVE_COVET; } + GIVEN { PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET) { MaxHP(200); HP(101); Item(ITEM_ORAN_BERRY); } @@ -161,6 +162,25 @@ SINGLE_BATTLE_TEST("Thief and Covet: Berry activation happens before the item ca } SCENE { ANIMATION(ANIM_TYPE_MOVE, move, player); HP_BAR(opponent); + NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ITEM_STEAL, opponent); + } +} + +SINGLE_BATTLE_TEST("Thief and Covet: Berries that activate on a Status activate before the item can be stolen") +{ + u32 move; + PARAMETRIZE { move = MOVE_THIEF; } + PARAMETRIZE { move = MOVE_COVET; } + + GIVEN { + PLAYER(SPECIES_TOXICROAK) { Ability(ABILITY_POISON_TOUCH); } + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_LUM_BERRY); } + } WHEN { + TURN { MOVE(player, move); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, player); + ABILITY_POPUP(player, ABILITY_POISON_TOUCH); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ITEM_STEAL, opponent); } diff --git a/test/battle/move_effect_secondary/tri_attack.c b/test/battle/move_effect_secondary/tri_attack.c index 860a84aa8..4ac69915e 100644 --- a/test/battle/move_effect_secondary/tri_attack.c +++ b/test/battle/move_effect_secondary/tri_attack.c @@ -46,12 +46,11 @@ SINGLE_BATTLE_TEST("Tri Attack cannot paralyze/burn/freeze electric/fire/ice typ u8 statusAnim; u16 species; u32 rng; - #if B_PARALYZE_ELECTRIC >= GEN_6 PARAMETRIZE { statusAnim = B_ANIM_STATUS_PRZ; rng = MOVE_EFFECT_PARALYSIS; species = SPECIES_RAICHU; } - #endif // B_PARALYZE_ELECTRIC PARAMETRIZE { statusAnim = B_ANIM_STATUS_BRN; rng = MOVE_EFFECT_BURN; species = SPECIES_ARCANINE; } PARAMETRIZE { statusAnim = B_ANIM_STATUS_FRZ; rng = MOVE_EFFECT_FREEZE_OR_FROSTBITE; species = SPECIES_GLALIE; } GIVEN { + WITH_CONFIG(GEN_CONFIG_PARALYZE_ELECTRIC, GEN_6); PLAYER(SPECIES_WOBBUFFET); OPPONENT(species); } WHEN { diff --git a/test/battle/move_flags/powder.c b/test/battle/move_flags/powder.c index bb0b1e3e4..989cfb642 100644 --- a/test/battle/move_flags/powder.c +++ b/test/battle/move_flags/powder.c @@ -1,9 +1,13 @@ #include "global.h" #include "test/battle.h" -SINGLE_BATTLE_TEST("Powder moves are blocked by Grass-type Pokémon") +SINGLE_BATTLE_TEST("Powder moves are blocked by Grass-type Pokémon (Gen6+)") { + u32 gen = 0; + PARAMETRIZE { gen = GEN_5; } + PARAMETRIZE { gen = GEN_6; } GIVEN { + WITH_CONFIG(GEN_CONFIG_POWDER_GRASS, gen); ASSUME(IsPowderMove(MOVE_STUN_SPORE)); ASSUME(GetSpeciesType(SPECIES_ODDISH, 0) == TYPE_GRASS); PLAYER(SPECIES_WYNAUT); @@ -11,7 +15,12 @@ SINGLE_BATTLE_TEST("Powder moves are blocked by Grass-type Pokémon") } WHEN { TURN { MOVE(player, MOVE_STUN_SPORE); } } SCENE { - NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_STUN_SPORE, player); - MESSAGE("It doesn't affect the opposing Oddish…"); + if (gen == GEN_6) { + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_STUN_SPORE, player); + MESSAGE("It doesn't affect the opposing Oddish…"); + } else { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STUN_SPORE, player); + NOT MESSAGE("It doesn't affect the opposing Oddish…"); + } } } diff --git a/test/battle/sleep_clause.c b/test/battle/sleep_clause.c index 7c4153836..e45945a29 100644 --- a/test/battle/sleep_clause.c +++ b/test/battle/sleep_clause.c @@ -1075,6 +1075,7 @@ SINGLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mo enum Ability ability; PARAMETRIZE { ability = ABILITY_VITAL_SPIRIT; } PARAMETRIZE { ability = ABILITY_INSOMNIA; } + GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_NON_VOLATILE_STATUS); diff --git a/test/battle/status1/paralysis.c b/test/battle/status1/paralysis.c index a93d350eb..0be8cf1ef 100644 --- a/test/battle/status1/paralysis.c +++ b/test/battle/status1/paralysis.c @@ -56,6 +56,7 @@ AI_SINGLE_BATTLE_TEST("AI avoids Thunder Wave when it can not paralyse target") PARAMETRIZE { species = SPECIES_PIKACHU; ability = ABILITY_STATIC; } GIVEN { + WITH_CONFIG(GEN_CONFIG_PARALYZE_ELECTRIC, GEN_6); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT); PLAYER(species) { Ability(ability); } OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_THUNDER_WAVE); } @@ -64,18 +65,30 @@ AI_SINGLE_BATTLE_TEST("AI avoids Thunder Wave when it can not paralyse target") } } -SINGLE_BATTLE_TEST("Thunder Wave doesn't affect Electric types in Gen6+") +SINGLE_BATTLE_TEST("Thunder Wave doesn't affect Electric types (Gen6+)") { + u32 gen = 0; + PARAMETRIZE { gen = GEN_5; } + PARAMETRIZE { gen = GEN_6; } GIVEN { + WITH_CONFIG(GEN_CONFIG_PARALYZE_ELECTRIC, gen); ASSUME(GetSpeciesType(SPECIES_PIKACHU, 0) == TYPE_ELECTRIC); - ASSUME(B_PARALYZE_ELECTRIC >= GEN_6); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_PIKACHU); } WHEN { TURN { MOVE(player, MOVE_THUNDER_WAVE); } } SCENE { MESSAGE("Wobbuffet used Thunder Wave!"); - MESSAGE("It doesn't affect the opposing Pikachu…"); + if (gen == GEN_6) { + NONE_OF { + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, opponent); + STATUS_ICON(opponent, paralysis: TRUE); + } + MESSAGE("It doesn't affect the opposing Pikachu…"); + } else { + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, opponent); + STATUS_ICON(opponent, paralysis: TRUE); + } } } diff --git a/test/battle/status1/sleep.c b/test/battle/status1/sleep.c index ea08a2ff5..a43daf8d6 100644 --- a/test/battle/status1/sleep.c +++ b/test/battle/status1/sleep.c @@ -22,11 +22,25 @@ SINGLE_BATTLE_TEST("Sleep prevents the battler from using a move") } } -SINGLE_BATTLE_TEST("Sleep: Spore doesn't affect grass types (Gen 6+)") +SINGLE_BATTLE_TEST("Sleep: Spore affects grass types (Gen1-5)") { GIVEN { + WITH_CONFIG(GEN_CONFIG_POWDER_GRASS, GEN_5); + ASSUME(IsPowderMove(MOVE_SPORE)); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_CHIKORITA); + } WHEN { + TURN { MOVE(player, MOVE_SPORE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SPORE, player); + } +} + +SINGLE_BATTLE_TEST("Sleep: Spore doesn't affect grass types (Gen6+)") +{ + GIVEN { + WITH_CONFIG(GEN_CONFIG_POWDER_GRASS, GEN_6); ASSUME(IsPowderMove(MOVE_SPORE)); - ASSUME(B_POWDER_GRASS >= GEN_6); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_CHIKORITA); } WHEN { diff --git a/test/battle/switch_in_abilities.c b/test/battle/switch_in_abilities.c index c8a8c54dd..4d125ddce 100644 --- a/test/battle/switch_in_abilities.c +++ b/test/battle/switch_in_abilities.c @@ -126,3 +126,124 @@ DOUBLE_BATTLE_TEST("Switch-in abilities trigger in Speed Order after post-KO swi } } } + +MULTI_BATTLE_TEST("Switch-in abilities trigger in Speed Order after post-KO switch - multibattle") +{ + u32 spdPlayer1, spdPlayer2, spdOpponent1, spdOpponent2; + + PARAMETRIZE { spdPlayer1 = 5; spdPlayer2 = 4; spdOpponent1 = 3; spdOpponent2 = 2; } + PARAMETRIZE { spdPlayer1 = 2; spdPlayer2 = 3; spdOpponent1 = 4; spdOpponent2 = 5; } + PARAMETRIZE { spdPlayer1 = 4; spdPlayer2 = 3; spdOpponent1 = 5; spdOpponent2 = 2; } + + GIVEN { + MULTI_PLAYER(SPECIES_WOBBUFFET) { HP(1); Speed(1); } + MULTI_PLAYER(SPECIES_TYRANITAR) { Speed(spdPlayer1); Ability(ABILITY_SAND_STREAM); } + MULTI_PARTNER(SPECIES_WOBBUFFET) { HP(1); Speed(1); } + MULTI_PARTNER(SPECIES_GYARADOS) { Speed(spdPlayer2); Ability(ABILITY_INTIMIDATE); } + MULTI_OPPONENT_A(SPECIES_WOBBUFFET) { HP(1); Speed(1); } + MULTI_OPPONENT_A(SPECIES_WEEZING_GALAR) { Speed(spdOpponent1); Ability(ABILITY_MISTY_SURGE); } + MULTI_OPPONENT_B(SPECIES_WOBBUFFET) { HP(1); Speed(1); } + MULTI_OPPONENT_B(SPECIES_VULPIX_ALOLA) { Speed(spdOpponent2); Ability(ABILITY_SNOW_WARNING); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_EXPLOSION); SEND_OUT(playerLeft, 1); SEND_OUT(opponentLeft, 1); SEND_OUT(playerRight, 4); SEND_OUT(opponentRight, 4); } + TURN { ; } + } SCENE { + MESSAGE("Wobbuffet used Explosion!"); + if (spdPlayer1 == 5) { + ABILITY_POPUP(playerLeft, ABILITY_SAND_STREAM); + ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE); + ABILITY_POPUP(opponentLeft, ABILITY_MISTY_SURGE); + ABILITY_POPUP(opponentRight, ABILITY_SNOW_WARNING); + } else if (spdOpponent2 == 5) { + ABILITY_POPUP(opponentRight, ABILITY_SNOW_WARNING); + ABILITY_POPUP(opponentLeft, ABILITY_MISTY_SURGE); + ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE); + ABILITY_POPUP(playerLeft, ABILITY_SAND_STREAM); + } else { + ABILITY_POPUP(opponentLeft, ABILITY_MISTY_SURGE); + ABILITY_POPUP(playerLeft, ABILITY_SAND_STREAM); + ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE); + ABILITY_POPUP(opponentRight, ABILITY_SNOW_WARNING); + } + } +} + +TWO_VS_ONE_BATTLE_TEST("Switch-in abilities trigger in Speed Order after post-KO switch - 2v1") +{ + u32 spdPlayer1, spdPlayer2, spdOpponent1, spdOpponent2; + + PARAMETRIZE { spdPlayer1 = 5; spdPlayer2 = 4; spdOpponent1 = 3; spdOpponent2 = 2; } + PARAMETRIZE { spdPlayer1 = 2; spdPlayer2 = 3; spdOpponent1 = 4; spdOpponent2 = 5; } + PARAMETRIZE { spdPlayer1 = 4; spdPlayer2 = 3; spdOpponent1 = 5; spdOpponent2 = 2; } + + GIVEN { + MULTI_PLAYER(SPECIES_WOBBUFFET) { HP(1); Speed(1); } + MULTI_PLAYER(SPECIES_TYRANITAR) { Speed(spdPlayer1); Ability(ABILITY_SAND_STREAM); } + MULTI_PARTNER(SPECIES_WYNAUT) { HP(1); Speed(1); } + MULTI_PARTNER(SPECIES_GYARADOS) { Speed(spdPlayer2); Ability(ABILITY_INTIMIDATE); } + MULTI_OPPONENT_A(SPECIES_WOBBUFFET) { HP(1); Speed(1); } + MULTI_OPPONENT_A(SPECIES_WYNAUT) { HP(1); Speed(1); } + MULTI_OPPONENT_A(SPECIES_WEEZING_GALAR) { Speed(spdOpponent1); Ability(ABILITY_MISTY_SURGE); } + MULTI_OPPONENT_A(SPECIES_VULPIX_ALOLA) { Speed(spdOpponent2); Ability(ABILITY_SNOW_WARNING); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_EXPLOSION); SEND_OUT(playerLeft, 1); SEND_OUT(opponentLeft, 2); SEND_OUT(playerRight, 4); SEND_OUT(opponentRight, 3); } + } SCENE { + MESSAGE("Wobbuffet used Explosion!"); + if (spdPlayer1 == 5) { + ABILITY_POPUP(playerLeft, ABILITY_SAND_STREAM); + ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE); + ABILITY_POPUP(opponentLeft, ABILITY_MISTY_SURGE); + ABILITY_POPUP(opponentRight, ABILITY_SNOW_WARNING); + } else if (spdOpponent2 == 5) { + ABILITY_POPUP(opponentRight, ABILITY_SNOW_WARNING); + ABILITY_POPUP(opponentLeft, ABILITY_MISTY_SURGE); + ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE); + ABILITY_POPUP(playerLeft, ABILITY_SAND_STREAM); + } else { + ABILITY_POPUP(opponentLeft, ABILITY_MISTY_SURGE); + ABILITY_POPUP(playerLeft, ABILITY_SAND_STREAM); + ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE); + ABILITY_POPUP(opponentRight, ABILITY_SNOW_WARNING); + } + } +} + +ONE_VS_TWO_BATTLE_TEST("Switch-in abilities trigger in Speed Order after post-KO switch - 1v2") +{ + u32 spdPlayer1, spdPlayer2, spdOpponent1, spdOpponent2; + + PARAMETRIZE { spdPlayer1 = 5; spdPlayer2 = 4; spdOpponent1 = 3; spdOpponent2 = 2; } + PARAMETRIZE { spdPlayer1 = 2; spdPlayer2 = 3; spdOpponent1 = 4; spdOpponent2 = 5; } + PARAMETRIZE { spdPlayer1 = 4; spdPlayer2 = 3; spdOpponent1 = 5; spdOpponent2 = 2; } + + GIVEN { + MULTI_PLAYER(SPECIES_WOBBUFFET) { HP(1); Speed(1); } + MULTI_PLAYER(SPECIES_WYNAUT) { HP(1); Speed(1); } + MULTI_PLAYER(SPECIES_TYRANITAR) { Speed(spdPlayer1); Ability(ABILITY_SAND_STREAM); } + MULTI_PLAYER(SPECIES_GYARADOS) { Speed(spdPlayer2); Ability(ABILITY_INTIMIDATE); } + MULTI_OPPONENT_A(SPECIES_WOBBUFFET) { HP(1); Speed(1); } + MULTI_OPPONENT_A(SPECIES_WEEZING_GALAR) { Speed(spdOpponent1); Ability(ABILITY_MISTY_SURGE); } + MULTI_OPPONENT_B(SPECIES_WYNAUT) { HP(1); Speed(1); } + MULTI_OPPONENT_B(SPECIES_VULPIX_ALOLA) { Speed(spdOpponent2); Ability(ABILITY_SNOW_WARNING); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_EXPLOSION); SEND_OUT(playerLeft, 2); SEND_OUT(opponentLeft, 1); SEND_OUT(playerRight, 3); SEND_OUT(opponentRight, 4); } + } SCENE { + MESSAGE("Wobbuffet used Explosion!"); + if (spdPlayer1 == 5) { + ABILITY_POPUP(playerLeft, ABILITY_SAND_STREAM); + ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE); + ABILITY_POPUP(opponentLeft, ABILITY_MISTY_SURGE); + ABILITY_POPUP(opponentRight, ABILITY_SNOW_WARNING); + } else if (spdOpponent2 == 5) { + ABILITY_POPUP(opponentRight, ABILITY_SNOW_WARNING); + ABILITY_POPUP(opponentLeft, ABILITY_MISTY_SURGE); + ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE); + ABILITY_POPUP(playerLeft, ABILITY_SAND_STREAM); + } else { + ABILITY_POPUP(opponentLeft, ABILITY_MISTY_SURGE); + ABILITY_POPUP(playerLeft, ABILITY_SAND_STREAM); + ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE); + ABILITY_POPUP(opponentRight, ABILITY_SNOW_WARNING); + } + } +} diff --git a/test/battle/test_runner_features.c b/test/battle/test_runner_features.c index bb4840799..2c6d73abc 100644 --- a/test/battle/test_runner_features.c +++ b/test/battle/test_runner_features.c @@ -25,3 +25,58 @@ SINGLE_BATTLE_TEST("Forced abilities activate on switch-in") MESSAGE("Kadabra's Sp. Atk was heightened!"); } } + +SINGLE_BATTLE_TEST("Setting level doesn't overwrite set stats") +{ + u32 level = 0; + + PARAMETRIZE{level = 1;} + PARAMETRIZE{level = 10;} + PARAMETRIZE{level = 50;} + PARAMETRIZE{level = 99;} + GIVEN { + PLAYER(SPECIES_WOBBUFFET) {HP(5); MaxHP(10); Attack(10); Defense(10); Speed(10); SpAttack(10); SpDefense(10); Level(level); }; + OPPONENT(SPECIES_WOBBUFFET) {Speed(1);} + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE);} + } THEN { + EXPECT_EQ(player->hp, 5); + EXPECT_EQ(player->maxHP, 10); + EXPECT_EQ(player->attack, 10); + EXPECT_EQ(player->defense, 10); + EXPECT_EQ(player->speed, 10); + EXPECT_EQ(player->spAttack, 10); + EXPECT_EQ(player->spDefense, 10); + } +} + +SINGLE_BATTLE_TEST("Changing forms doesn't overwrite set stats (not HP)") +{ + GIVEN { + PLAYER(SPECIES_DIANCIE) {Attack(10); Defense(10); Speed(10); SpAttack(10); SpDefense(10); Item(ITEM_DIANCITE);} + OPPONENT(SPECIES_WOBBUFFET) {Speed(1);} + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } + } SCENE { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_MEGA_EVOLUTION, player); + } THEN { + EXPECT_EQ(player->attack, 10); + EXPECT_EQ(player->defense, 10); + EXPECT_EQ(player->speed, 10); + EXPECT_EQ(player->spAttack, 10); + EXPECT_EQ(player->spDefense, 10); + } +} + +SINGLE_BATTLE_TEST("Changing forms doesn't overwrite set stats (HP)") +{ + GIVEN { + PLAYER(SPECIES_TERAPAGOS) {HP(5); MaxHP(10); TeraType(TYPE_STELLAR);} + OPPONENT(SPECIES_WOBBUFFET) {} + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_TERA); MOVE(opponent, MOVE_CELEBRATE);} + } THEN { + EXPECT_EQ(player->hp, 5); + EXPECT_EQ(player->maxHP, 10); + } +} diff --git a/test/battle/trainer_control.c b/test/battle/trainer_control.c index 663a720d3..1821cebcb 100644 --- a/test/battle/trainer_control.c +++ b/test/battle/trainer_control.c @@ -188,6 +188,7 @@ TEST("Difficulty default to Normal is the trainer doesn't have a member for the CreateNPCTrainerPartyFromTrainer(testParty, &sTestTrainers[GetTrainerDifficultyLevelTest(currTrainer)][currTrainer], TRUE, BATTLE_TYPE_TRAINER); EXPECT(GetMonData(&testParty[0], MON_DATA_SPECIES) == SPECIES_MEWTWO); Free(testParty); + SetCurrentDifficultyLevel(DIFFICULTY_NORMAL); } TEST("Difficulty changes which party if used for NPCs if defined for the difficulty (EASY)") @@ -199,6 +200,7 @@ TEST("Difficulty changes which party if used for NPCs if defined for the difficu EXPECT(GetMonData(&testParty[0], MON_DATA_SPECIES) == SPECIES_METAPOD); EXPECT(GetMonData(&testParty[0], MON_DATA_LEVEL) == 1); Free(testParty); + SetCurrentDifficultyLevel(DIFFICULTY_NORMAL); } TEST("Difficulty changes which party if used for NPCs if defined for the difficulty (HARD)") @@ -210,6 +212,7 @@ TEST("Difficulty changes which party if used for NPCs if defined for the difficu EXPECT(GetMonData(&testParty[0], MON_DATA_SPECIES) == SPECIES_ARCEUS); EXPECT(GetMonData(&testParty[0], MON_DATA_LEVEL) == 99); Free(testParty); + SetCurrentDifficultyLevel(DIFFICULTY_NORMAL); } TEST("Difficulty changes which party if used for NPCs if defined for the difficulty (NORMAL)") diff --git a/test/battle/weather/sandstorm.c b/test/battle/weather/sandstorm.c index 96a440a10..d01bd72ce 100644 --- a/test/battle/weather/sandstorm.c +++ b/test/battle/weather/sandstorm.c @@ -97,8 +97,8 @@ SINGLE_BATTLE_TEST("Sandstorm damage rounds properly when maxHP < 16") SINGLE_BATTLE_TEST("Sandstorm doesn't do damage when weather is negated") { - u32 type1 = GetSpeciesType(SPECIES_STOUTLAND, 0); - u32 type2 = GetSpeciesType(SPECIES_STOUTLAND, 1); + enum Type type1 = GetSpeciesType(SPECIES_STOUTLAND, 0); + enum Type type2 = GetSpeciesType(SPECIES_STOUTLAND, 1); GIVEN { ASSUME(type1 != TYPE_ROCK && type2 != TYPE_ROCK); ASSUME(type1 != TYPE_GROUND && type2 != TYPE_GROUND); diff --git a/test/daycare.c b/test/daycare.c index 1f142f115..379273703 100644 --- a/test/daycare.c +++ b/test/daycare.c @@ -51,7 +51,10 @@ TEST("(Daycare) Pokémon can breed with Ditto if they don't belong to the Ditto ZeroPlayerPartyMons(); for (j = 1; j < NUM_SPECIES; j++) - PARAMETRIZE { parentSpecies = j; } + { + if (IsSpeciesEnabled(j)) + PARAMETRIZE { parentSpecies = j; } + } VarSet(VAR_TEMP_C, parentSpecies); RUN_OVERWORLD_SCRIPT( givemon SPECIES_DITTO, 100; givemon VAR_TEMP_C, 100; diff --git a/test/pokemon.c b/test/pokemon.c index 60058407c..c902e56e4 100644 --- a/test/pokemon.c +++ b/test/pokemon.c @@ -5,6 +5,7 @@ #include "test/overworld_script.h" #include "test/test.h" #include "constants/characters.h" +#include "constants/move_relearner.h" TEST("Nature independent from Hidden Nature") { @@ -25,7 +26,8 @@ TEST("Nature independent from Hidden Nature") TEST("Terastallization type defaults to primary or secondary type") { - u32 i, teraType; + u32 i; + enum Type teraType; struct Pokemon mon; for (i = 0; i < 128; i++) PARAMETRIZE {} CreateMon(&mon, SPECIES_PIDGEY, 100, 0, FALSE, 0, OT_ID_PRESET, 0); @@ -36,7 +38,8 @@ TEST("Terastallization type defaults to primary or secondary type") TEST("Terastallization type can be set to any type except TYPE_NONE") { - u32 i, teraType; + u32 i; + enum Type teraType; struct Pokemon mon; for (i = 1; i < NUMBER_OF_MON_TYPES; i++) { @@ -49,7 +52,8 @@ TEST("Terastallization type can be set to any type except TYPE_NONE") TEST("Terastallization type is reset to the default types when setting Tera Type back to TYPE_NONE") { - u32 i, teraType, typeNone; + u32 i; + enum Type teraType, typeNone; struct Pokemon mon; for (i = 1; i < NUMBER_OF_MON_TYPES; i++) { @@ -288,7 +292,7 @@ TEST("givemon [moves]") ZeroPlayerPartyMons(); RUN_OVERWORLD_SCRIPT( - givemon SPECIES_WOBBUFFET, 100, move1=MOVE_SCRATCH, move2=MOVE_SPLASH, move3=MOVE_NONE, move4=MOVE_NONE; + givemon SPECIES_WOBBUFFET, 100, move1=MOVE_SCRATCH, move2=MOVE_SPLASH, move3=MOVE_NONE; ); EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPECIES), SPECIES_WOBBUFFET); @@ -304,7 +308,7 @@ TEST("givemon [all]") ZeroPlayerPartyMons(); RUN_OVERWORLD_SCRIPT( - givemon SPECIES_WOBBUFFET, 100, item=ITEM_LEFTOVERS, ball=ITEM_MASTER_BALL, nature=NATURE_BOLD, abilityNum=2, gender=MON_MALE, hpEv=1, atkEv=2, defEv=3, speedEv=4, spAtkEv=5, spDefEv=6, hpIv=7, atkIv=8, defIv=9, speedIv=10, spAtkIv=11, spDefIv=12, move1=MOVE_SCRATCH, move2=MOVE_SPLASH, move3=MOVE_CELEBRATE, move4=MOVE_EXPLOSION, isShiny=TRUE, gmaxFactor=TRUE, teraType=TYPE_FIRE, dmaxLevel=7; + givemon SPECIES_WOBBUFFET, 100, item=ITEM_LEFTOVERS, ball=ITEM_MASTER_BALL, nature=NATURE_BOLD, abilityNum=2, gender=MON_MALE, hpEv=1, atkEv=2, defEv=3, speedEv=4, spAtkEv=5, spDefEv=6, hpIv=7, atkIv=8, defIv=9, speedIv=10, spAtkIv=11, spDefIv=12, move1=MOVE_SCRATCH, move2=MOVE_SPLASH, move3=MOVE_CELEBRATE, move4=MOVE_EXPLOSION, shinyMode=SHINY_MODE_ALWAYS, gmaxFactor=TRUE, teraType=TYPE_FIRE, dmaxLevel=7; ); EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPECIES), SPECIES_WOBBUFFET); @@ -363,13 +367,13 @@ TEST("givemon [vars]") VarSet(VAR_TEMP_6, MOVE_SPLASH); VarSet(VAR_TEMP_7, MOVE_CELEBRATE); VarSet(VAR_TEMP_8, MOVE_EXPLOSION); - VarSet(VAR_TEMP_9, TRUE); + VarSet(VAR_TEMP_9, SHINY_MODE_ALWAYS); VarSet(VAR_TEMP_A, TRUE); VarSet(VAR_TEMP_B, TYPE_FIRE); VarSet(VAR_TEMP_E, 7); RUN_OVERWORLD_SCRIPT( - givemon VAR_TEMP_C, VAR_TEMP_D, item=VAR_0x8000, ball=VAR_0x8001, nature=VAR_0x8002, abilityNum=VAR_0x8003, gender=VAR_0x8004, hpEv=VAR_0x8005, atkEv=VAR_0x8006, defEv=VAR_0x8007, speedEv=VAR_0x8008, spAtkEv=VAR_0x8009, spDefEv=VAR_0x800A, hpIv=VAR_0x800B, atkIv=VAR_TEMP_0, defIv=VAR_TEMP_1, speedIv=VAR_TEMP_2, spAtkIv=VAR_TEMP_3, spDefIv=VAR_TEMP_4, move1=VAR_TEMP_5, move2=VAR_TEMP_6, move3=VAR_TEMP_7, move4=VAR_TEMP_8, isShiny=VAR_TEMP_9, gmaxFactor=VAR_TEMP_A, teraType=VAR_TEMP_B, dmaxLevel=VAR_TEMP_E; + givemon VAR_TEMP_C, VAR_TEMP_D, item=VAR_0x8000, ball=VAR_0x8001, nature=VAR_0x8002, abilityNum=VAR_0x8003, gender=VAR_0x8004, hpEv=VAR_0x8005, atkEv=VAR_0x8006, defEv=VAR_0x8007, speedEv=VAR_0x8008, spAtkEv=VAR_0x8009, spDefEv=VAR_0x800A, hpIv=VAR_0x800B, atkIv=VAR_TEMP_0, defIv=VAR_TEMP_1, speedIv=VAR_TEMP_2, spAtkIv=VAR_TEMP_3, spDefIv=VAR_TEMP_4, move1=VAR_TEMP_5, move2=VAR_TEMP_6, move3=VAR_TEMP_7, move4=VAR_TEMP_8, shinyMode=VAR_TEMP_9, gmaxFactor=VAR_TEMP_A, teraType=VAR_TEMP_B, dmaxLevel=VAR_TEMP_E; ); EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPECIES), SPECIES_WOBBUFFET); @@ -477,6 +481,24 @@ TEST("Optimised SetMonData") EXPECT_FASTER(optimised, vanilla); } +//Sanity check for a CalculateMonStats refactor (could be deleted or improved) +TEST("CalculateMonStats") +{ + ZeroPlayerPartyMons(); + + RUN_OVERWORLD_SCRIPT( + givemon SPECIES_WOBBUFFET, 100, item=ITEM_LEFTOVERS, ball=ITEM_MASTER_BALL, nature=NATURE_BOLD, abilityNum=2, gender=MON_MALE, hpEv=1, atkEv=2, defEv=3, speedEv=4, spAtkEv=5, spDefEv=6, hpIv=7, atkIv=8, defIv=9, speedIv=10, spAtkIv=11, spDefIv=12, move1=MOVE_SCRATCH, move2=MOVE_SPLASH, move3=MOVE_CELEBRATE, move4=MOVE_EXPLOSION, shinyMode=SHINY_MODE_ALWAYS, gmaxFactor=TRUE, teraType=TYPE_FIRE, dmaxLevel=7; + ); + + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_MAX_HP), 497); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_ATK), 71); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_DEF), 143); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPEED), 82); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPATK), 83); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPDEF), 134); + +} + TEST("BoxPokemon encryption works") { u32 raw[20] = diff --git a/test/save.c b/test/save.c new file mode 100644 index 000000000..4e06942f9 --- /dev/null +++ b/test/save.c @@ -0,0 +1,35 @@ +#include "global.h" +#include "pokemon_storage_system.h" +#include "test/test.h" + +// If you would like to ensure save compatibility, update the values below with those for your hack. You can find these through the debug menu. +// Please note that this simple check is not 100% foolproof, but should be able to catch most unintended shifts. +#define T_SAVEBLOCK1_SIZE 15808 +#define T_SAVEBLOCK2_SIZE 3968 +#define T_SAVEBLOCK3_SIZE 4 +#define T_POKEMONSTORAGE_SIZE 34144 + +TEST("SaveBlock1 is backwards compatible") +{ + EXPECT_EQ(sizeof(struct SaveBlock1), T_SAVEBLOCK1_SIZE); +} + +TEST("SaveBlock2 is backwards compatible") +{ + EXPECT_EQ(sizeof(struct SaveBlock2), T_SAVEBLOCK2_SIZE); +} + +TEST("SaveBlock3 is backwards compatible") +{ + EXPECT_EQ(sizeof(struct SaveBlock3), T_SAVEBLOCK3_SIZE); +} + +TEST("PokemonStorage is backwards compatible") +{ + EXPECT_EQ(sizeof(struct PokemonStorage), T_POKEMONSTORAGE_SIZE); +} + +#undef T_SAVEBLOCK1_SIZE +#undef T_SAVEBLOCK2_SIZE +#undef T_SAVEBLOCK3_SIZE +#undef T_POKEMONSTORAGE_SIZE diff --git a/test/species.c b/test/species.c index 06351f179..c4d91e60e 100644 --- a/test/species.c +++ b/test/species.c @@ -106,7 +106,7 @@ TEST("No species has two evolutions that use the evolution tracker") for (i = 0; i < NUM_SPECIES; i++) { - if (GetSpeciesEvolutions(i) != NULL) PARAMETRIZE { species = i; } + if (IsSpeciesEnabled(i) && GetSpeciesEvolutions(i) != NULL) PARAMETRIZE { species = i; } } evolutionTrackerEvolutions = 0; diff --git a/test/test_runner.c b/test/test_runner.c index 450283ab5..ef12e8d5f 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -1,4 +1,5 @@ #include +#include "fake_rtc.h" #include "global.h" #include "gpu_regs.h" #include "load_save.h" @@ -9,6 +10,7 @@ #include "constants/characters.h" #include "test_runner.h" #include "test/test.h" +#include "test/battle.h" #define TIMEOUT_SECONDS 60 @@ -184,6 +186,13 @@ void TestRunner_CheckMemory(void) } } +static void ClearSaveBlocks(void) +{ + ClearSav1(); + ClearSav2(); + ClearSav3(); +} + void CB2_TestRunner(void) { top: @@ -201,17 +210,13 @@ top: gTestRunnerState.filterMode = DetectFilterMode(gTestRunnerArgv); MoveSaveBlocks_ResetHeap(); - ClearSav1(); - ClearSav2(); - ClearSav3(); gIntrTable[7] = Intr_Timer2; - gSaveBlock2Ptr->optionsBattleStyle = OPTIONS_BATTLE_STYLE_SET; - // The current test restarted the ROM (e.g. by jumping to NULL). if (gPersistentTestRunnerState.address != 0) { + ClearSaveBlocks(); gTestRunnerState.test = __start_tests; while ((uintptr_t)gTestRunnerState.test != gPersistentTestRunnerState.address) { @@ -255,6 +260,7 @@ top: break; case STATE_ASSIGN_TEST: + ClearSaveBlocks(); while (1) { if (gTestRunnerState.test == __stop_tests) @@ -477,6 +483,7 @@ void Test_ExpectCrash(bool32 expectCrash) static void FunctionTest_SetUp(void *data) { (void)data; + ClearRiggedRng(); gFunctionTestRunnerState = AllocZeroed(sizeof(*gFunctionTestRunnerState)); SeedRng(0); } @@ -508,12 +515,84 @@ static bool32 FunctionTest_CheckProgress(void *data) return madeProgress; } +static u32 FunctionTest_RandomUniform(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32), void *caller) +{ + //rigged + for (u32 i = 0; i < RIGGED_RNG_COUNT; i++) + { + if (gFunctionTestRunnerState->rngList[i].tag == tag) + { + if (reject && reject(gFunctionTestRunnerState->rngList[i].value)) + Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":LWITH_RNG specified a rejected value (%d)", gFunctionTestRunnerState->rngList[i].value); + return gFunctionTestRunnerState->rngList[i].value; + } + } + //trials + /* + if (tag == STATE->rngTag) + return RandomUniformTrials(tag, lo, hi, reject); + */ + + //default + return RandomUniformDefaultValue(tag, lo, hi, reject, caller); +} + +static u32 FunctionTest_RandomWeightedArray(enum RandomTag tag, u32 sum, u32 n, const u8 *weights, void *caller) +{ + //rigged + for (u32 i = 0; i < RIGGED_RNG_COUNT; i++) + { + if (gFunctionTestRunnerState->rngList[i].tag == tag) + return gFunctionTestRunnerState->rngList[i].value; + } + + //trials + /* + if (tag == STATE->rngTag) + return RandomWeightedArrayTrials(tag, sum, n, weights); + */ + + //default + return RandomWeightedArrayDefaultValue(tag, n, weights, caller); +} + +static const void* FunctionTest_RandomElementArray(enum RandomTag tag, const void *array, size_t size, size_t count, void *caller) +{ + //rigged + for (u32 i = 0; i < RIGGED_RNG_COUNT; i++) + { + if (gFunctionTestRunnerState->rngList[i].tag == tag) + { + u32 element = 0; + for (u32 index = 0; index < count; index++) + { + memcpy(&element, (const u8 *)array + size * index, size); + if (element == gFunctionTestRunnerState->rngList[i].value) + return (const u8 *)array + size * index; + } + Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":L%s: RandomElement illegal value requested: %d", gTestRunnerState.test->filename, gFunctionTestRunnerState->rngList[i].value); + } + } + + //trials + /* + if (tag == STATE->rngTag) + return RandomElementTrials(tag, array, size, count); + */ + + //default + return RandomElementArrayDefaultValue(tag, array, size, count, caller); +} + const struct TestRunner gFunctionTestRunner = { .setUp = FunctionTest_SetUp, .run = FunctionTest_Run, .tearDown = FunctionTest_TearDown, .checkProgress = FunctionTest_CheckProgress, + .randomUniform = FunctionTest_RandomUniform, + .randomWeightedArray = FunctionTest_RandomWeightedArray, + .randomElementArray = FunctionTest_RandomElementArray, }; static void Assumptions_Run(void *data) @@ -821,3 +900,102 @@ u32 SourceLineOffset(u32 sourceLine) else return sourceLine - test->sourceLine; } + +u32 RandomUniform(enum RandomTag tag, u32 lo, u32 hi) +{ + void *caller = __builtin_extract_return_addr(__builtin_return_address(0)); + if (gTestRunnerState.test->runner->randomUniform) + return gTestRunnerState.test->runner->randomUniform(tag, lo, hi, NULL, caller); + else + return RandomUniformDefault(tag, lo, hi); +} + +u32 RandomUniformExcept(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32)) +{ + void *caller = __builtin_extract_return_addr(__builtin_return_address(0)); + if (gTestRunnerState.test->runner->randomUniform) + return gTestRunnerState.test->runner->randomUniform(tag, lo, hi, reject, caller); + else + return RandomUniformExceptDefault(tag, lo, hi, reject); +} + +u32 RandomWeightedArray(enum RandomTag tag, u32 sum, u32 n, const u8 *weights) +{ + void *caller = __builtin_extract_return_addr(__builtin_return_address(0)); + if (gTestRunnerState.test->runner->randomWeightedArray) + return gTestRunnerState.test->runner->randomWeightedArray(tag, sum, n, weights, caller); + else + return RandomWeightedArrayDefault(tag, sum, n, weights); +} + +const void *RandomElementArray(enum RandomTag tag, const void *array, size_t size, size_t count) +{ + void *caller = __builtin_extract_return_addr(__builtin_return_address(0)); + if (gTestRunnerState.test->runner->randomElementArray) + return gTestRunnerState.test->runner->randomElementArray(tag, array, size, count, caller); + else + return RandomElementArrayDefault(tag, array, size, count); +} + +u32 RandomUniformDefaultValue(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32), void *caller) +{ + u32 default_ = hi; + if (reject) + { + while (reject(default_)) + { + if (default_ == lo) + Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomUniformExcept called from %p with tag %d rejected all values", caller, tag); + default_--; + } + } + return default_; +} + +u32 RandomWeightedArrayDefaultValue(enum RandomTag tag, u32 n, const u8 *weights, void *caller) +{ + while (weights[n-1] == 0) + { + if (n == 1) + Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomWeightedArray called from %p with tag %d and all zero weights", caller, tag); + n--; + } + return n-1; +} + +const void *RandomElementArrayDefaultValue(enum RandomTag tag, const void *array, size_t size, size_t count, void *caller) +{ + return (const u8 *)array + size * (count - 1); +} + +void ClearRiggedRng(void) +{ + struct RiggedRNG zeroRng = {.tag = RNG_NONE, .value = 0}; + for (u32 i = 0; i < RIGGED_RNG_COUNT; i++) + memcpy(&gFunctionTestRunnerState->rngList[i], &zeroRng, sizeof(zeroRng)); +} + +void SetupRiggedRng(u32 sourceLine, enum RandomTag randomTag, u32 value) +{ + struct RiggedRNG rng = {.tag = randomTag, .value = value}; + u32 i; + for (i = 0; i < RIGGED_RNG_COUNT; i++) + { + if (gFunctionTestRunnerState->rngList[i].tag == randomTag) + { + memcpy(&gFunctionTestRunnerState->rngList[i], &rng, sizeof(rng)); + break; + } + else if (gFunctionTestRunnerState->rngList[i].tag > RNG_NONE) + { + continue; + } + else + { + memcpy(&gFunctionTestRunnerState->rngList[i], &rng, sizeof(rng)); + break; + } + } + if (i == RIGGED_RNG_COUNT) + Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: Too many rigged RNGs to set up", gTestRunnerState.test->filename, sourceLine); +} diff --git a/test/test_runner_battle.c b/test/test_runner_battle.c index 0deaf7b43..48034526f 100644 --- a/test/test_runner_battle.c +++ b/test/test_runner_battle.c @@ -3,6 +3,7 @@ #include "battle_ai_util.h" #include "battle_anim.h" #include "battle_controllers.h" +#include "battle_setup.h" #include "battle_gimmick.h" #include "battle_z_move.h" #include "event_data.h" @@ -10,6 +11,7 @@ #include "item_menu.h" #include "main.h" #include "malloc.h" +#include "party_menu.h" #include "random.h" #include "test/battle.h" #include "window.h" @@ -76,7 +78,7 @@ NAKED static void InvokeSingleTestFunctionWithStack(void *results, u32 i, struct .pool"); } -NAKED static void InvokeDoubleTestFunctionWithStack(void *results, u32 i, struct BattlePokemon *playerLeft, struct BattlePokemon *opponentLeft, struct BattlePokemon *playerRight, struct BattlePokemon *opponentRight, SingleBattleTestFunction function, void *stack) +NAKED static void InvokeDoubleTestFunctionWithStack(void *results, u32 i, struct BattlePokemon *playerLeft, struct BattlePokemon *opponentLeft, struct BattlePokemon *playerRight, struct BattlePokemon *opponentRight, DoubleBattleTestFunction function, void *stack) { asm("push {r4-r7,lr}\n\ ldr r4, [sp, #28] @ function\n\ @@ -100,6 +102,78 @@ NAKED static void InvokeDoubleTestFunctionWithStack(void *results, u32 i, struct .pool"); } +NAKED static void InvokeMultiTestFunctionWithStack(void *results, u32 i, struct BattlePokemon *playerLeft, struct BattlePokemon *opponentLeft, struct BattlePokemon *playerRight, struct BattlePokemon *opponentRight, MultiBattleTestFunction function, void *stack) +{ + asm("push {r4-r7,lr}\n\ + ldr r4, [sp, #28] @ function\n\ + ldr r5, [sp, #32] @ stack\n\ + mov r6, sp\n\ + mov sp, r5\n\ + push {r6}\n\ + add r6, #20\n\ + ldmia r6, {r6, r7} @ playerRight, opponentRight\n\ + push {r6, r7}\n\ + ldr r6, =MultiRestoreSP + 1\n\ + mov lr, r6\n\ + bx r4\n\ + MultiRestoreSP:\n\ + add sp, #8\n\ + pop {r0}\n\ + mov sp, r0\n\ + pop {r4-r7}\n\ + pop {r0}\n\ + bx r0\n\ + .pool"); +} + +NAKED static void InvokeTwoVsOneTestFunctionWithStack(void *results, u32 i, struct BattlePokemon *playerLeft, struct BattlePokemon *opponentLeft, struct BattlePokemon *playerRight, struct BattlePokemon *opponentRight, TwoVsOneBattleTestFunction function, void *stack) +{ + asm("push {r4-r7,lr}\n\ + ldr r4, [sp, #28] @ function\n\ + ldr r5, [sp, #32] @ stack\n\ + mov r6, sp\n\ + mov sp, r5\n\ + push {r6}\n\ + add r6, #20\n\ + ldmia r6, {r6, r7} @ playerRight, opponentRight\n\ + push {r6, r7}\n\ + ldr r6, =TwoVsOneRestoreSP + 1\n\ + mov lr, r6\n\ + bx r4\n\ + TwoVsOneRestoreSP:\n\ + add sp, #8\n\ + pop {r0}\n\ + mov sp, r0\n\ + pop {r4-r7}\n\ + pop {r0}\n\ + bx r0\n\ + .pool"); +} + +NAKED static void InvokeOneVsTwoTestFunctionWithStack(void *results, u32 i, struct BattlePokemon *playerLeft, struct BattlePokemon *opponentLeft, struct BattlePokemon *playerRight, struct BattlePokemon *opponentRight, OneVsTwoBattleTestFunction function, void *stack) +{ + asm("push {r4-r7,lr}\n\ + ldr r4, [sp, #28] @ function\n\ + ldr r5, [sp, #32] @ stack\n\ + mov r6, sp\n\ + mov sp, r5\n\ + push {r6}\n\ + add r6, #20\n\ + ldmia r6, {r6, r7} @ playerRight, opponentRight\n\ + push {r6, r7}\n\ + ldr r6, =OneVsTwoRestoreSP + 1\n\ + mov lr, r6\n\ + bx r4\n\ + OneVsTwoRestoreSP:\n\ + add sp, #8\n\ + pop {r0}\n\ + mov sp, r0\n\ + pop {r4-r7}\n\ + pop {r0}\n\ + bx r0\n\ + .pool"); +} + // Calls test->function, but pointing its stack at DATA.stack so that // local variables are live after the function returns (and so can be // referenced by HP_BAR, or the next call, etc). @@ -118,7 +192,19 @@ static void InvokeTestFunction(const struct BattleTest *test) break; case BATTLE_TEST_DOUBLES: case BATTLE_TEST_AI_DOUBLES: - InvokeDoubleTestFunctionWithStack(STATE->results, STATE->runParameter, &gBattleMons[B_POSITION_PLAYER_LEFT], &gBattleMons[B_POSITION_OPPONENT_LEFT], &gBattleMons[B_POSITION_PLAYER_RIGHT], &gBattleMons[B_POSITION_OPPONENT_RIGHT], test->function.singles, &DATA.stack[BATTLE_TEST_STACK_SIZE]); + InvokeDoubleTestFunctionWithStack(STATE->results, STATE->runParameter, &gBattleMons[B_POSITION_PLAYER_LEFT], &gBattleMons[B_POSITION_OPPONENT_LEFT], &gBattleMons[B_POSITION_PLAYER_RIGHT], &gBattleMons[B_POSITION_OPPONENT_RIGHT], test->function.doubles, &DATA.stack[BATTLE_TEST_STACK_SIZE]); + break; + case BATTLE_TEST_MULTI: + case BATTLE_TEST_AI_MULTI: + InvokeMultiTestFunctionWithStack(STATE->results, STATE->runParameter, &gBattleMons[B_POSITION_PLAYER_LEFT], &gBattleMons[B_POSITION_OPPONENT_LEFT], &gBattleMons[B_POSITION_PLAYER_RIGHT], &gBattleMons[B_POSITION_OPPONENT_RIGHT], test->function.multi, &DATA.stack[BATTLE_TEST_STACK_SIZE]); + break; + case BATTLE_TEST_TWO_VS_ONE: + case BATTLE_TEST_AI_TWO_VS_ONE: + InvokeTwoVsOneTestFunctionWithStack(STATE->results, STATE->runParameter, &gBattleMons[B_POSITION_PLAYER_LEFT], &gBattleMons[B_POSITION_OPPONENT_LEFT], &gBattleMons[B_POSITION_PLAYER_RIGHT], &gBattleMons[B_POSITION_OPPONENT_RIGHT], test->function.two_vs_one, &DATA.stack[BATTLE_TEST_STACK_SIZE]); + break; + case BATTLE_TEST_ONE_VS_TWO: + case BATTLE_TEST_AI_ONE_VS_TWO: + InvokeOneVsTwoTestFunctionWithStack(STATE->results, STATE->runParameter, &gBattleMons[B_POSITION_PLAYER_LEFT], &gBattleMons[B_POSITION_OPPONENT_LEFT], &gBattleMons[B_POSITION_PLAYER_RIGHT], &gBattleMons[B_POSITION_OPPONENT_RIGHT], test->function.one_vs_two, &DATA.stack[BATTLE_TEST_STACK_SIZE]); break; } } @@ -135,6 +221,9 @@ static bool32 IsAITest(void) { case BATTLE_TEST_AI_SINGLES: case BATTLE_TEST_AI_DOUBLES: + case BATTLE_TEST_AI_MULTI: + case BATTLE_TEST_AI_TWO_VS_ONE: + case BATTLE_TEST_AI_ONE_VS_TWO: return TRUE; } return FALSE; @@ -179,6 +268,12 @@ static void BattleTest_SetUp(void *data) break; case BATTLE_TEST_DOUBLES: case BATTLE_TEST_AI_DOUBLES: + case BATTLE_TEST_MULTI: + case BATTLE_TEST_AI_MULTI: + case BATTLE_TEST_TWO_VS_ONE: + case BATTLE_TEST_AI_TWO_VS_ONE: + case BATTLE_TEST_ONE_VS_TWO: + case BATTLE_TEST_AI_ONE_VS_TWO: STATE->battlersCount = 4; break; } @@ -263,26 +358,97 @@ static void BattleTest_Run(void *data) { case BATTLE_TEST_WILD: DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER; + for (i = 0; i < STATE->battlersCount; i++) + DATA.currentMonIndexes[i] = i / 2; break; case BATTLE_TEST_AI_SINGLES: DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_TRAINER; DATA.recordedBattle.opponentA = TRAINER_PLAYER_LEAF; DATA.hasAI = TRUE; + for (i = 0; i < STATE->battlersCount; i++) + DATA.currentMonIndexes[i] = i / 2; break; case BATTLE_TEST_AI_DOUBLES: DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_TRAINER | BATTLE_TYPE_DOUBLE; DATA.recordedBattle.opponentA = TRAINER_PLAYER_LEAF; + DATA.recordedBattle.opponentB = TRAINER_NONE; + DATA.hasAI = TRUE; + for (i = 0; i < STATE->battlersCount; i++) + DATA.currentMonIndexes[i] = i / 2; + break; + case BATTLE_TEST_AI_MULTI: + DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_TRAINER | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS; + DATA.recordedBattle.partnerId = TRAINER_PARTNER(PARTNER_STEVEN); + DATA.recordedBattle.opponentA = TRAINER_PLAYER_LEAF; DATA.recordedBattle.opponentB = TRAINER_PLAYER_RED; DATA.hasAI = TRUE; + DATA.currentMonIndexes[0] = 0; // Player first mon + DATA.currentMonIndexes[1] = 0; // Opponent A first mon + DATA.currentMonIndexes[2] = 3; // Player partner first mon + DATA.currentMonIndexes[3] = 3; // Opponent B first mon + break; + case BATTLE_TEST_AI_TWO_VS_ONE: + DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_TRAINER | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_MULTI; + DATA.recordedBattle.partnerId = TRAINER_PARTNER(PARTNER_STEVEN); + DATA.recordedBattle.opponentA = TRAINER_PLAYER_LEAF; + DATA.recordedBattle.opponentB = 0xFFFF; + DATA.currentMonIndexes[0] = 0; // Player first mon + DATA.currentMonIndexes[1] = 0; // Opponent first mon + DATA.currentMonIndexes[2] = 3; // Player partner first mon + DATA.currentMonIndexes[3] = 1; // Opponent second mon + DATA.hasAI = TRUE; + break; + case BATTLE_TEST_AI_ONE_VS_TWO: + DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_TRAINER | BATTLE_TYPE_DOUBLE | BATTLE_TYPE_TWO_OPPONENTS; + DATA.recordedBattle.opponentA = TRAINER_PLAYER_LEAF; + DATA.recordedBattle.opponentB = TRAINER_PLAYER_RED; + DATA.currentMonIndexes[0] = 0; // Player first mon + DATA.currentMonIndexes[1] = 0; // Opponent A first mon + DATA.currentMonIndexes[2] = 1; // Player second mon + DATA.currentMonIndexes[3] = 3; // Opponent B first mon + DATA.hasAI = TRUE; break; case BATTLE_TEST_SINGLES: DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_RECORDED_IS_MASTER | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_TRAINER; DATA.recordedBattle.opponentA = TRAINER_LINK_OPPONENT; + for (i = 0; i < STATE->battlersCount; i++) + DATA.currentMonIndexes[i] = i / 2; break; case BATTLE_TEST_DOUBLES: DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_RECORDED_IS_MASTER | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_TRAINER | BATTLE_TYPE_DOUBLE; DATA.recordedBattle.opponentA = TRAINER_LINK_OPPONENT; + DATA.recordedBattle.opponentB = TRAINER_NONE; + for (i = 0; i < STATE->battlersCount; i++) + DATA.currentMonIndexes[i] = i / 2; + break; + case BATTLE_TEST_MULTI: + DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_RECORDED_IS_MASTER | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_TRAINER | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS; + DATA.recordedBattle.partnerId = TRAINER_PARTNER(PARTNER_STEVEN); + DATA.recordedBattle.opponentA = TRAINER_LINK_OPPONENT; DATA.recordedBattle.opponentB = TRAINER_LINK_OPPONENT; + DATA.currentMonIndexes[0] = 0; // Player first mon + DATA.currentMonIndexes[1] = 0; // Opponent A first mon + DATA.currentMonIndexes[2] = 3; // Player partner first mon + DATA.currentMonIndexes[3] = 3; // Opponent B first mon + break; + case BATTLE_TEST_TWO_VS_ONE: + DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_RECORDED_IS_MASTER | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_TRAINER | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_MULTI; + DATA.recordedBattle.partnerId = TRAINER_PARTNER(PARTNER_STEVEN); + DATA.recordedBattle.opponentA = TRAINER_LINK_OPPONENT; + DATA.recordedBattle.opponentB = 0xFFFF; + DATA.currentMonIndexes[0] = 0; // Player first mon + DATA.currentMonIndexes[1] = 0; // Opponent first mon + DATA.currentMonIndexes[2] = 3; // Player partner first mon + DATA.currentMonIndexes[3] = 1; // Opponent second mon + break; + case BATTLE_TEST_ONE_VS_TWO: + DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_RECORDED_IS_MASTER | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_TRAINER | BATTLE_TYPE_DOUBLE | BATTLE_TYPE_TWO_OPPONENTS; + DATA.recordedBattle.opponentA = TRAINER_LINK_OPPONENT; + DATA.recordedBattle.opponentB = TRAINER_LINK_OPPONENT; + DATA.currentMonIndexes[0] = 0; // Player first mon + DATA.currentMonIndexes[1] = 0; // Opponent A first mon + DATA.currentMonIndexes[2] = 1; // Player second mon + DATA.currentMonIndexes[3] = 3; // Opponent B first mon break; } @@ -294,9 +460,6 @@ static void BattleTest_Run(void *data) DATA.recordedBattle.playersBattlers[i] = i; } - for (i = 0; i < STATE->battlersCount; i++) - DATA.currentMonIndexes[i] = i / 2; - STATE->runRandomly = TRUE; STATE->runGiven = TRUE; STATE->runWhen = TRUE; @@ -326,10 +489,46 @@ static void BattleTest_Run(void *data) if (DATA.hasExplicitSpeeds) { - // TODO: If a battler is taking the default action maybe it - // should not require an explicit speed? - if (DATA.explicitSpeeds[B_SIDE_PLAYER] != (1 << DATA.playerPartySize) - 1 - || DATA.explicitSpeeds[B_SIDE_OPPONENT] != (1 << DATA.opponentPartySize) - 1) + u8 revisedPlayerExplicitSpeeds = 0; + u8 revisedPartnerExplicitSpeeds = 0; + u8 revisedOpponentAExplicitSpeeds = 0; + u8 revisedOpponentBExplicitSpeeds = 0; + + for (i = 0; i < 3; i++) + { + if(GetMonData(&DATA.recordedBattle.playerParty[i], MON_DATA_SPECIES, NULL) != SPECIES_NONE) + revisedPlayerExplicitSpeeds |= 1 << i; + } + for (i = 3; i < PARTY_SIZE; i++) + { + if(GetMonData(&DATA.recordedBattle.playerParty[i], MON_DATA_SPECIES, NULL) != SPECIES_NONE) + { + if(DATA.currentPosition == B_POSITION_PLAYER_LEFT) + revisedPlayerExplicitSpeeds |= 1 << i; + else + revisedPartnerExplicitSpeeds |= 1 << i; + } + } + + for (i = 0; i < 3; i++) + { + if(GetMonData(&DATA.recordedBattle.opponentParty[i], MON_DATA_SPECIES, NULL) != SPECIES_NONE) + revisedOpponentAExplicitSpeeds |= 1 << i; + } + for (i = 3; i < PARTY_SIZE; i++) + { + if(GetMonData(&DATA.recordedBattle.opponentParty[i], MON_DATA_SPECIES, NULL) != SPECIES_NONE) + { + if(DATA.currentPosition == B_POSITION_OPPONENT_LEFT) + revisedOpponentAExplicitSpeeds |= 1 << i; + else + revisedOpponentBExplicitSpeeds |= 1 << i; + } + } + + if (((DATA.explicitSpeeds[B_POSITION_PLAYER_LEFT] + DATA.explicitSpeeds[B_POSITION_PLAYER_RIGHT]) != (revisedPlayerExplicitSpeeds + revisedPartnerExplicitSpeeds) + || (DATA.explicitSpeeds[B_POSITION_OPPONENT_LEFT] + DATA.explicitSpeeds[B_POSITION_OPPONENT_RIGHT]) != (revisedOpponentAExplicitSpeeds + revisedOpponentBExplicitSpeeds))) + { Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":LSpeed required for all PLAYERs and OPPONENTs"); } @@ -355,96 +554,113 @@ static void BattleTest_Run(void *data) PrintTestName(); } -u32 RandomUniform(enum RandomTag tag, u32 lo, u32 hi) +u32 RandomUniformTrials(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32), void *caller) { - const struct BattlerTurn *turn = NULL; - - if (gCurrentTurnActionNumber < gBattlersCount) + STATE->didRunRandomly = TRUE; + if (STATE->trials == 1) { - u32 battlerId = gBattlerByTurnOrder[gCurrentTurnActionNumber]; - turn = &DATA.battleRecordTurns[gBattleResults.battleTurnCounter][battlerId]; - if (turn && turn->rng.tag == tag) - return turn->rng.value; - } - - if (tag == STATE->rngTag) - { - STATE->didRunRandomly = TRUE; - u32 n = hi - lo + 1; - if (STATE->trials == 1) + u32 n = 0, i; + if (reject) { - STATE->trials = n; - PrintTestName(); - } - else if (STATE->trials != n) - { - Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomUniform called from %p with tag %d and inconsistent trials %d and %d", __builtin_extract_return_addr(__builtin_return_address(0)), tag, STATE->trials, n); - } - STATE->trialRatio = Q_4_12(1) / STATE->trials; - return STATE->runTrial + lo; - } - - return hi; -} - -u32 RandomUniformExcept(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32)) -{ - const struct BattlerTurn *turn = NULL; - u32 default_; - - if (gCurrentTurnActionNumber < gBattlersCount) - { - u32 battlerId = gBattlerByTurnOrder[gCurrentTurnActionNumber]; - turn = &DATA.battleRecordTurns[gBattleResults.battleTurnCounter][battlerId]; - if (turn && turn->rng.tag == tag) - { - if (reject(turn->rng.value)) - Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":LWITH_RNG specified a rejected value (%d)", turn->rng.value); - return turn->rng.value; - } - } - - if (tag == STATE->rngTag) - { - STATE->didRunRandomly = TRUE; - if (STATE->trials == 1) - { - u32 n = 0, i; for (i = lo; i <= hi; i++) if (!reject(i)) n++; STATE->trials = n; - PrintTestName(); } - STATE->trialRatio = Q_4_12(1) / STATE->trials; - - while (reject(STATE->runTrial + lo + STATE->rngTrialOffset)) - { - if (STATE->runTrial + lo + STATE->rngTrialOffset > hi) - Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomUniformExcept called from %p with tag %d and inconsistent reject", __builtin_extract_return_addr(__builtin_return_address(0)), tag); - STATE->rngTrialOffset++; - } - - return STATE->runTrial + lo + STATE->rngTrialOffset; + else + STATE->trials = hi - lo + 1; + PrintTestName(); } + STATE->trialRatio = Q_4_12(1) / STATE->trials; - default_ = hi; - while (reject(default_)) + if (!reject) { - if (default_ == lo) - Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomUniformExcept called from %p with tag %d rejected all values", __builtin_extract_return_addr(__builtin_return_address(0)), tag); - default_--; + if (STATE->trials != (hi - lo + 1)) + Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomUniform called from %p with tag %d and inconsistent trials %d and %d", caller, tag, STATE->trials, hi - lo + 1); + return STATE->runTrial + lo; } - return default_; + + while (reject(STATE->runTrial + lo + STATE->rngTrialOffset)) + { + if (STATE->runTrial + lo + STATE->rngTrialOffset > hi) + Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomUniformExcept called from %p with tag %d and inconsistent reject", caller, tag); + STATE->rngTrialOffset++; + } + + return STATE->runTrial + lo + STATE->rngTrialOffset; + } -u32 RandomWeightedArray(enum RandomTag tag, u32 sum, u32 n, const u8 *weights) +u32 RandomWeightedArrayTrials(enum RandomTag tag, u32 sum, u32 n, const u8 *weights, void *caller) { + //Detect inconsistent sum + u32 weightSum = 0; + if (STATE->runTrial == 0) + { + for (u32 i = 0; i < n; i++) + weightSum += weights[i]; + if (weightSum != sum) + Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomWeighted called from %p has weights not matching its sum", caller); + } + + STATE->didRunRandomly = TRUE; + if (STATE->trials == 1) + { + STATE->trials = n; + PrintTestName(); + } + else if (STATE->trials != n) + { + Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomWeighted called from %p with tag %d and inconsistent trials %d and %d", caller, tag, STATE->trials, n); + } + + STATE->trialRatio = Q_4_12(weights[STATE->runTrial]) / sum; + return STATE->runTrial; +} + +const void *RandomElementArrayTrials(enum RandomTag tag, const void *array, size_t size, size_t count, void *caller) +{ + STATE->didRunRandomly = TRUE; + if (STATE->trials == 1) + { + STATE->trials = count; + PrintTestName(); + } + else if (STATE->trials != count) + { + Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomElement called from %p with tag %d and inconsistent trials %d and %d", caller, tag, STATE->trials, count); + } + STATE->trialRatio = Q_4_12(1) / count; + return (const u8 *)array + size * STATE->runTrial; +} + +static u32 BattleTest_RandomUniform(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32), void *caller) +{ + //rigged const struct BattlerTurn *turn = NULL; + if (gCurrentTurnActionNumber < gBattlersCount) + { + u32 battlerId = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + turn = &DATA.battleRecordTurns[gBattleResults.battleTurnCounter][battlerId]; + if (turn && turn->rng.tag == tag) + { + if (reject && reject(turn->rng.value)) + Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":LWITH_RNG specified a rejected value (%d)", turn->rng.value); + return turn->rng.value; + } + } + //trials + if (tag == STATE->rngTag) + return RandomUniformTrials(tag, lo, hi, reject, caller); - if (sum == 0) - Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomWeightedArray called with zero sum"); + //default + return RandomUniformDefaultValue(tag, lo, hi, reject, caller); +} +static u32 BattleTest_RandomWeightedArray(enum RandomTag tag, u32 sum, u32 n, const u8 *weights, void *caller) +{ + //rigged + const struct BattlerTurn *turn = NULL; if (gCurrentTurnActionNumber < gBattlersCount || tag == RNG_SHELL_SIDE_ARM) { u32 battlerId = gBattlerByTurnOrder[gCurrentTurnActionNumber]; @@ -453,23 +669,11 @@ u32 RandomWeightedArray(enum RandomTag tag, u32 sum, u32 n, const u8 *weights) return turn->rng.value; } + //trials if (tag == STATE->rngTag) - { - STATE->didRunRandomly = TRUE; - if (STATE->trials == 1) - { - STATE->trials = n; - PrintTestName(); - } - else if (STATE->trials != n) - { - Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomWeighted called from %p with tag %d and inconsistent trials %d and %d", __builtin_extract_return_addr(__builtin_return_address(0)), tag, STATE->trials, n); - } - // TODO: Detect inconsistent sum. - STATE->trialRatio = Q_4_12(weights[STATE->runTrial]) / sum; - return STATE->runTrial; - } + return RandomWeightedArrayTrials(tag, sum, n, weights, caller); + //default switch (tag) { case RNG_ACCURACY: @@ -494,21 +698,14 @@ u32 RandomWeightedArray(enum RandomTag tag, u32 sum, u32 n, const u8 *weights) return TRUE; default: - while (weights[n-1] == 0) - { - if (n == 1) - Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomWeightedArray called from %p with tag %d and all zero weights", __builtin_extract_return_addr(__builtin_return_address(0)), tag); - n--; - } - return n-1; + return RandomWeightedArrayDefaultValue(tag, n, weights, caller); } } -const void *RandomElementArray(enum RandomTag tag, const void *array, size_t size, size_t count) +static const void *BattleTest_RandomElementArray(enum RandomTag tag, const void *array, size_t size, size_t count, void *caller) { + //rigged const struct BattlerTurn *turn = NULL; - u32 index = count-1; - if (gCurrentTurnActionNumber < gBattlersCount) { u32 battlerId = gBattlerByTurnOrder[gCurrentTurnActionNumber]; @@ -516,33 +713,23 @@ const void *RandomElementArray(enum RandomTag tag, const void *array, size_t siz if (turn && turn->rng.tag == tag) { u32 element = 0; - for (index = 0; index < count; index++) + for (u32 index = 0; index < count; index++) { memcpy(&element, (const u8 *)array + size * index, size); if (element == turn->rng.value) return (const u8 *)array + size * index; } - // TODO: Incorporate the line number. Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":L%s: RandomElement illegal value requested: %d", gTestRunnerState.test->filename, turn->rng.value); } } + + //trials if (tag == STATE->rngTag) - { - STATE->didRunRandomly = TRUE; - if (STATE->trials == 1) - { - STATE->trials = count; - PrintTestName(); - } - else if (STATE->trials != count) - { - Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomElement called from %p with tag %d and inconsistent trials %d and %d", __builtin_extract_return_addr(__builtin_return_address(0)), tag, STATE->trials, count); - } - STATE->trialRatio = Q_4_12(1) / count; - return (const u8 *)array + size * STATE->runTrial; - } - return (const u8 *)array + size * index; + return RandomElementArrayTrials(tag, array, size, count, caller); + + //default + return RandomElementArrayDefaultValue(tag, array, size, count, caller); } static s32 TryAbilityPopUp(s32 i, s32 n, u32 battlerId, enum Ability ability) @@ -1358,6 +1545,7 @@ static void TearDownBattle(void) // Zero out the parties, data in them could potentially carry over ZeroPlayerPartyMons(); ZeroEnemyPartyMons(); + SetCurrentDifficultyLevel(DIFFICULTY_NORMAL); FreeMonSpritesGfx(); FreeBattleSpritesData(); @@ -1509,14 +1697,24 @@ void RNGSeed_(u32 sourceLine, rng_value_t seed) void AIFlags_(u32 sourceLine, u64 flags) { - INVALID_IF(!IsAITest(), "AI_FLAGS is usable only in AI_SINGLE_BATTLE_TEST & AI_DOUBLE_BATTLE_TEST"); - DATA.recordedBattle.AI_scripts = flags; + INVALID_IF(!IsAITest(), "AI_FLAGS is usable only in AI_SINGLE_BATTLE_TEST, AI_DOUBLE_BATTLE_TEST, AI_MULTI_BATTLE_TEST, and AI_TWO_VS_ONE_TEST"); + for (u32 i = 0; i < MAX_BATTLERS_COUNT; i++) + { + DATA.recordedBattle.AI_scripts[i] = flags; + } + DATA.hasAI = TRUE; +} + +void BattlerAIFlags_(u32 sourceLine, u32 battler, u64 flags) +{ + INVALID_IF(!IsAITest(), "AI_FLAGS is usable only in AI_SINGLE_BATTLE_TEST, AI_DOUBLE_BATTLE_TEST, AI_MULTI_BATTLE_TEST, and AI_TWO_VS_ONE_TEST"); + DATA.recordedBattle.AI_scripts[battler] |= flags; DATA.hasAI = TRUE; } void AILogScores(u32 sourceLine) { - INVALID_IF(!IsAITest(), "AI_LOG is usable only in AI_SINGLE_BATTLE_TEST & AI_DOUBLE_BATTLE_TEST"); + INVALID_IF(!IsAITest(), "AI_LOG is usable only in AI_SINGLE_BATTLE_TEST, AI_DOUBLE_BATTLE_TEST, AI_MULTI_BATTLE_TEST, and AI_TWO_VS_ONE_TEST"); DATA.logAI = TRUE; } @@ -1528,6 +1726,9 @@ const struct TestRunner gBattleTestRunner = .tearDown = BattleTest_TearDown, .checkProgress = BattleTest_CheckProgress, .handleExitWithResult = BattleTest_HandleExitWithResult, + .randomUniform = BattleTest_RandomUniform, + .randomWeightedArray = BattleTest_RandomWeightedArray, + .randomElementArray = BattleTest_RandomElementArray, }; void SetFlagForTest(u32 sourceLine, u16 flagId) @@ -1552,14 +1753,14 @@ void ClearFlagAfterTest(void) } } -void OpenPokemon(u32 sourceLine, u32 side, u32 species) +void OpenPokemon(u32 sourceLine, enum BattlerPosition position, u32 species) { s32 i, data; u8 *partySize; struct Pokemon *party; INVALID_IF(species >= SPECIES_EGG, "Invalid species: %d", species); ASSUMPTION_FAIL_IF(!IsSpeciesEnabled(species), "Species disabled: %d", species); - if (side == B_SIDE_PLAYER) + if ((position & BIT_SIDE) == B_SIDE_PLAYER) { partySize = &DATA.playerPartySize; party = DATA.recordedBattle.playerParty; @@ -1570,7 +1771,60 @@ void OpenPokemon(u32 sourceLine, u32 side, u32 species) party = DATA.recordedBattle.opponentParty; } INVALID_IF(*partySize >= PARTY_SIZE, "Too many Pokemon in party"); - DATA.currentSide = side; + DATA.currentPosition = position; + DATA.currentPartyIndex = *partySize; + DATA.currentMon = &party[DATA.currentPartyIndex]; + DATA.gender = 0xFF; // Male + DATA.nature = NATURE_HARDY; + (*partySize)++; + + CreateMon(DATA.currentMon, species, 100, 0, TRUE, 0, OT_ID_PRESET, 0); + data = MOVE_NONE; + for (i = 0; i < MAX_MON_MOVES; i++) + SetMonData(DATA.currentMon, MON_DATA_MOVE1 + i, &data); + data = 0; + if (B_FRIENDSHIP_BOOST) + { + // This way, we avoid the boost affecting tests unless explicitly stated. + SetMonData(DATA.currentMon, MON_DATA_FRIENDSHIP, &data); + CalculateMonStats(DATA.currentMon); + } +} + +void OpenPokemonMulti(u32 sourceLine, enum BattlerPosition position, u32 species) +{ + + s32 i, data; + u8 *partySize; + struct Pokemon *party; + INVALID_IF(species >= SPECIES_EGG, "Invalid species: %d", species); + ASSUMPTION_FAIL_IF(!IsSpeciesEnabled(species), "Species disabled: %d", species); + if (position == B_POSITION_PLAYER_LEFT) // MULTI_PLAYER + { + partySize = &DATA.playerPartySize; + party = DATA.recordedBattle.playerParty; + } + else if (position == B_POSITION_PLAYER_RIGHT) // MULTI_PARTNER + { + partySize = &DATA.playerPartySize; + if ((*partySize == 0) || (*partySize == 1) || (*partySize == 2)) + *partySize = 3; + party = DATA.recordedBattle.playerParty; + } + else if (position == B_POSITION_OPPONENT_LEFT) // MULTI_OPPONENT_A + { + partySize = &DATA.opponentPartySize; + party = DATA.recordedBattle.opponentParty; + } + else // MULTI_OPPONENT_B + { + partySize = &DATA.opponentPartySize; + if ((*partySize == 0) || (*partySize == 1) || (*partySize == 2)) + *partySize = 3; + party = DATA.recordedBattle.opponentParty; + } + INVALID_IF(*partySize >= PARTY_SIZE, "Too many Pokemon in party"); + DATA.currentPosition = position; DATA.currentPartyIndex = *partySize; DATA.currentMon = &party[DATA.currentPartyIndex]; DATA.gender = 0xFF; // Male @@ -1621,10 +1875,10 @@ void ClosePokemon(u32 sourceLine) { s32 i; u32 data; - INVALID_IF(DATA.hasExplicitSpeeds && !(DATA.explicitSpeeds[DATA.currentSide] & (1 << DATA.currentPartyIndex)), "Speed required"); + INVALID_IF(DATA.hasExplicitSpeeds && !(DATA.explicitSpeeds[DATA.currentPosition] & (1 << DATA.currentPartyIndex)), "Speed required"); for (i = 0; i < STATE->battlersCount; i++) { - if ((i & BIT_SIDE) == DATA.currentSide + if (i == DATA.currentPosition && DATA.currentMonIndexes[i] == DATA.currentPartyIndex) { INVALID_IF(GetMonData(DATA.currentMon, MON_DATA_HP) == 0, "Battlers cannot be fainted"); @@ -1695,7 +1949,7 @@ void Ability_(u32 sourceLine, enum Ability ability) // Store forced ability to be set when the battle starts if invalid. if (i == NUM_ABILITY_SLOTS) { - DATA.forcedAbilities[DATA.currentSide][DATA.currentPartyIndex] = ability; + DATA.forcedAbilities[DATA.currentPosition][DATA.currentPartyIndex] = ability; } } @@ -1707,7 +1961,9 @@ void Level_(u32 sourceLine, u32 level) INVALID_IF(level == 0 || level > MAX_LEVEL, "Illegal level: %d", level); SetMonData(DATA.currentMon, MON_DATA_LEVEL, &level); SetMonData(DATA.currentMon, MON_DATA_EXP, &gExperienceTables[gSpeciesInfo[species].growthRate][level]); + gMain.inBattle = TRUE; CalculateMonStats(DATA.currentMon); + gMain.inBattle = FALSE; } void MaxHP_(u32 sourceLine, u32 maxHP) @@ -1715,6 +1971,8 @@ void MaxHP_(u32 sourceLine, u32 maxHP) INVALID_IF(!DATA.currentMon, "MaxHP outside of PLAYER/OPPONENT"); INVALID_IF(maxHP == 0, "Illegal max HP: %d", maxHP); SetMonData(DATA.currentMon, MON_DATA_MAX_HP, &maxHP); + bool32 hyperTrainingFlag = TRUE; + SetMonData(DATA.currentMon, MON_DATA_HYPER_TRAINED_HP, &hyperTrainingFlag); } void HP_(u32 sourceLine, u32 hp) @@ -1730,6 +1988,8 @@ void Attack_(u32 sourceLine, u32 attack) INVALID_IF(!DATA.currentMon, "Attack outside of PLAYER/OPPONENT"); INVALID_IF(attack == 0, "Illegal attack: %d", attack); SetMonData(DATA.currentMon, MON_DATA_ATK, &attack); + bool32 hyperTrainingFlag = TRUE; + SetMonData(DATA.currentMon, MON_DATA_HYPER_TRAINED_ATK, &hyperTrainingFlag); } void Defense_(u32 sourceLine, u32 defense) @@ -1737,6 +1997,8 @@ void Defense_(u32 sourceLine, u32 defense) INVALID_IF(!DATA.currentMon, "Defense outside of PLAYER/OPPONENT"); INVALID_IF(defense == 0, "Illegal defense: %d", defense); SetMonData(DATA.currentMon, MON_DATA_DEF, &defense); + bool32 hyperTrainingFlag = TRUE; + SetMonData(DATA.currentMon, MON_DATA_HYPER_TRAINED_DEF, &hyperTrainingFlag); } void SpAttack_(u32 sourceLine, u32 spAttack) @@ -1744,6 +2006,8 @@ void SpAttack_(u32 sourceLine, u32 spAttack) INVALID_IF(!DATA.currentMon, "SpAttack outside of PLAYER/OPPONENT"); INVALID_IF(spAttack == 0, "Illegal special attack: %d", spAttack); SetMonData(DATA.currentMon, MON_DATA_SPATK, &spAttack); + bool32 hyperTrainingFlag = TRUE; + SetMonData(DATA.currentMon, MON_DATA_HYPER_TRAINED_SPATK, &hyperTrainingFlag); } void SpDefense_(u32 sourceLine, u32 spDefense) @@ -1751,6 +2015,8 @@ void SpDefense_(u32 sourceLine, u32 spDefense) INVALID_IF(!DATA.currentMon, "SpDefense outside of PLAYER/OPPONENT"); INVALID_IF(spDefense == 0, "Illegal special defense: %d", spDefense); SetMonData(DATA.currentMon, MON_DATA_SPDEF, &spDefense); + bool32 hyperTrainingFlag = TRUE; + SetMonData(DATA.currentMon, MON_DATA_HYPER_TRAINED_SPDEF, &hyperTrainingFlag); } void Speed_(u32 sourceLine, u32 speed) @@ -1758,8 +2024,10 @@ void Speed_(u32 sourceLine, u32 speed) INVALID_IF(!DATA.currentMon, "Speed outside of PLAYER/OPPONENT"); INVALID_IF(speed == 0, "Illegal speed: %d", speed); SetMonData(DATA.currentMon, MON_DATA_SPEED, &speed); + bool32 hyperTrainingFlag = TRUE; + SetMonData(DATA.currentMon, MON_DATA_HYPER_TRAINED_SPEED, &hyperTrainingFlag); DATA.hasExplicitSpeeds = TRUE; - DATA.explicitSpeeds[DATA.currentSide] |= 1 << DATA.currentPartyIndex; + DATA.explicitSpeeds[DATA.currentPosition] |= 1 << DATA.currentPartyIndex; } void HPIV_(u32 sourceLine, u32 hpIV) @@ -1812,10 +2080,12 @@ void Item_(u32 sourceLine, u32 item) switch (GetItemHoldEffect(item)) { case HOLD_EFFECT_MEGA_STONE: - SetGimmick(sourceLine, DATA.currentSide, DATA.currentPartyIndex, GIMMICK_MEGA); + SetGimmick(sourceLine, DATA.currentPosition, DATA.currentPartyIndex, GIMMICK_MEGA); break; case HOLD_EFFECT_Z_CRYSTAL: - SetGimmick(sourceLine, DATA.currentSide, DATA.currentPartyIndex, GIMMICK_Z_MOVE); + SetGimmick(sourceLine, DATA.currentPosition, DATA.currentPartyIndex, GIMMICK_Z_MOVE); + break; + default: break; } } @@ -1833,7 +2103,7 @@ void Moves_(u32 sourceLine, u16 moves[MAX_MON_MOVES]) u32 pp = GetMovePP(moves[i]); SetMonData(DATA.currentMon, MON_DATA_PP1 + i, &pp); } - DATA.explicitMoves[DATA.currentSide] |= 1 << DATA.currentPartyIndex; + DATA.explicitMoves[DATA.currentPosition] |= 1 << DATA.currentPartyIndex; } void MovesWithPP_(u32 sourceLine, struct moveWithPP moveWithPP[MAX_MON_MOVES]) @@ -1848,7 +2118,7 @@ void MovesWithPP_(u32 sourceLine, struct moveWithPP moveWithPP[MAX_MON_MOVES]) SetMonData(DATA.currentMon, MON_DATA_MOVE1 + i, &moveWithPP[i].moveId); SetMonData(DATA.currentMon, MON_DATA_PP1 + i, &moveWithPP[i].pp); } - DATA.explicitMoves[DATA.currentSide] |= 1 << DATA.currentPartyIndex; + DATA.explicitMoves[DATA.currentPosition] |= 1 << DATA.currentPartyIndex; } void Friendship_(u32 sourceLine, u32 friendship) @@ -1874,21 +2144,21 @@ void DynamaxLevel_(u32 sourceLine, u32 dynamaxLevel) { INVALID_IF(!DATA.currentMon, "DynamaxLevel outside of PLAYER/OPPONENT"); SetMonData(DATA.currentMon, MON_DATA_DYNAMAX_LEVEL, &dynamaxLevel); - SetGimmick(sourceLine, DATA.currentSide, DATA.currentPartyIndex, GIMMICK_DYNAMAX); + SetGimmick(sourceLine, DATA.currentPosition, DATA.currentPartyIndex, GIMMICK_DYNAMAX); } void GigantamaxFactor_(u32 sourceLine, bool32 gigantamaxFactor) { INVALID_IF(!DATA.currentMon, "GigantamaxFactor outside of PLAYER/OPPONENT"); SetMonData(DATA.currentMon, MON_DATA_GIGANTAMAX_FACTOR, &gigantamaxFactor); - SetGimmick(sourceLine, DATA.currentSide, DATA.currentPartyIndex, GIMMICK_DYNAMAX); + SetGimmick(sourceLine, DATA.currentPosition, DATA.currentPartyIndex, GIMMICK_DYNAMAX); } -void TeraType_(u32 sourceLine, u32 teraType) +void TeraType_(u32 sourceLine, enum Type teraType) { INVALID_IF(!DATA.currentMon, "TeraType outside of PLAYER/OPPONENT"); SetMonData(DATA.currentMon, MON_DATA_TERA_TYPE, &teraType); - SetGimmick(sourceLine, DATA.currentSide, DATA.currentPartyIndex, GIMMICK_TERA); + SetGimmick(sourceLine, DATA.currentPosition, DATA.currentPartyIndex, GIMMICK_TERA); } void Shadow_(u32 sourceLine, bool32 isShadow) @@ -1903,6 +2173,13 @@ void Shiny_(u32 sourceLine, bool32 isShiny) DATA.isShiny = isShiny; } +void Environment_(u32 sourceLine, u32 environment) +{ + INVALID_IF(DATA.forcedEnvironment, "Environment is already set"); + INVALID_IF(environment >= BATTLE_ENVIRONMENT_COUNT, "Illegal environment: %d", environment); + DATA.forcedEnvironment = environment + 1; +} + static const char *const sBattlerIdentifiersSingles[] = { "player", @@ -1928,7 +2205,13 @@ static const char *BattlerIdentifier(s32 battlerId) return sBattlerIdentifiersSingles[battlerId]; case BATTLE_TEST_DOUBLES: case BATTLE_TEST_AI_DOUBLES: - return sBattlerIdentifiersDoubles[battlerId]; + case BATTLE_TEST_MULTI: + case BATTLE_TEST_AI_MULTI: + case BATTLE_TEST_TWO_VS_ONE: + case BATTLE_TEST_AI_TWO_VS_ONE: + case BATTLE_TEST_ONE_VS_TWO: + case BATTLE_TEST_AI_ONE_VS_TWO: + return sBattlerIdentifiersDoubles[battlerId]; } return ""; } @@ -2068,7 +2351,7 @@ void CloseTurn(u32 sourceLine) for (i = 0; i < STATE->battlersCount; i++) { if (!(DATA.actionBattlers & (1 << i))) - { + { // Multi test partner trainers want setting to RecordedPartner controller if no move set in this case. if (IsAITest() && (i & BIT_SIDE) == B_SIDE_OPPONENT) // If Move was not specified, allow any move used. SetAiActionToPass(sourceLine, i); else @@ -2082,7 +2365,7 @@ void CloseTurn(u32 sourceLine) static struct Pokemon *CurrentMon(s32 battlerId) { struct Pokemon *party; - if ((battlerId & BIT_SIDE) == B_SIDE_PLAYER) + if (battlerId == B_POSITION_PLAYER_LEFT || battlerId == B_POSITION_PLAYER_RIGHT) party = DATA.recordedBattle.playerParty; else party = DATA.recordedBattle.opponentParty; @@ -2181,7 +2464,7 @@ void MoveGetIdAndSlot(s32 battlerId, struct MoveContext *ctx, u32 *moveId, u32 * if (ctx->explicitGimmick && ctx->gimmick != GIMMICK_NONE) { u32 item = GetMonData(mon, MON_DATA_HELD_ITEM); - enum ItemHoldEffect holdEffect = GetItemHoldEffect(item); + enum HoldEffect holdEffect = GetItemHoldEffect(item); u32 species = GetMonData(mon, MON_DATA_SPECIES); u32 side = battlerId & BIT_SIDE; @@ -2320,7 +2603,7 @@ static void TryMarkExpectMove(u32 sourceLine, struct BattlePokemon *battler, str s32 target; INVALID_IF(DATA.turnState == TURN_CLOSED, "EXPECT_MOVE outside TURN"); - INVALID_IF(!IsAITest(), "EXPECT_MOVE is usable only in AI_SINGLE_BATTLE_TEST & AI_DOUBLE_BATTLE_TEST"); + INVALID_IF(!IsAITest(), "EXPECT_MOVE is usable only in AI_SINGLE_BATTLE_TEST, AI_DOUBLE_BATTLE_TEST, AI_MULTI_BATTLE_TEST, and AI_TWO_VS_ONE_TEST"); MoveGetIdAndSlot(battlerId, ctx, &moveId, &moveSlot, sourceLine); target = MoveGetTarget(battlerId, moveId, ctx, sourceLine); @@ -2351,7 +2634,7 @@ void ExpectSendOut(u32 sourceLine, struct BattlePokemon *battler, u32 partyIndex s32 i, id; s32 battlerId = battler - gBattleMons; INVALID_IF(DATA.turnState == TURN_CLOSED, "EXPECT_SEND_OUT outside TURN"); - INVALID_IF(!IsAITest(), "EXPECT_SEND_OUT is usable only in AI_SINGLE_BATTLE_TEST & AI_DOUBLE_BATTLE_TEST"); + INVALID_IF(!IsAITest(), "EXPECT_SEND_OUT is usable only in AI_SINGLE_BATTLE_TEST, AI_DOUBLE_BATTLE_TEST, AI_MULTI_BATTLE_TEST, AI_TWO_VS_ONE_TEST, and AI_ONE_VS_TWO_TEST"); INVALID_IF(partyIndex >= ((battlerId & BIT_SIDE) == B_SIDE_PLAYER ? DATA.playerPartySize : DATA.opponentPartySize), "EXPECT_SEND_OUT to invalid party index"); for (i = 0; i < STATE->battlersCount; i++) { @@ -2359,8 +2642,9 @@ void ExpectSendOut(u32 sourceLine, struct BattlePokemon *battler, u32 partyIndex INVALID_IF(DATA.currentMonIndexes[i] == partyIndex, "EXPECT_SEND_OUT to battler"); } if (!(DATA.actionBattlers & (1 << battlerId))) - { - if (IsAITest() && (battlerId & BIT_SIDE) == B_SIDE_OPPONENT) // If Move was not specified, allow any move used. + { // Multi test partner trainers want setting to PlayerPartner controller even if no move set in this case. + if (IsAITest() && (((battlerId & BIT_SIDE) == B_SIDE_OPPONENT) // If Move was not specified, allow any move used. + || (IsMultibattleTest() && battlerId == B_POSITION_PLAYER_RIGHT))) SetAiActionToPass(sourceLine, battlerId); else Move(sourceLine, battler, (struct MoveContext) { move: MOVE_CELEBRATE, explicitMove: TRUE }); @@ -2403,7 +2687,7 @@ void Score(u32 sourceLine, struct BattlePokemon *battler, u32 cmp, bool32 toValu s32 battlerId = battler - gBattleMons; s32 turn = DATA.turns; - INVALID_IF(!IsAITest(), "SCORE_%s%s is usable only in AI_SINGLE_BATTLE_TEST & AI_DOUBLE_BATTLE_TEST", sCmpToStringTable[cmp], (toValue == TRUE) ? "_VAL" : ""); + INVALID_IF(!IsAITest(), "SCORE_%s%s is usable only in AI_SINGLE_BATTLE_TEST, AI_DOUBLE_BATTLE_TEST, AI_MULTI_BATTLE_TEST, & AI_TWO_VS_ONE_TEST", sCmpToStringTable[cmp], (toValue == TRUE) ? "_VAL" : ""); for (i = 0; i < MAX_AI_SCORE_COMPARISION_PER_TURN; i++) { @@ -2487,7 +2771,7 @@ void ExpectSwitch(u32 sourceLine, struct BattlePokemon *battler, u32 partyIndex) s32 i, id; s32 battlerId = battler - gBattleMons; INVALID_IF(DATA.turnState == TURN_CLOSED, "EXPECT_SWITCH outside TURN"); - INVALID_IF(!IsAITest(), "EXPECT_SWITCH is usable only in AI_SINGLE_BATTLE_TEST & AI_DOUBLE_BATTLE_TEST"); + INVALID_IF(!IsAITest(), "EXPECT_SWITCH is usable only in AI_SINGLE_BATTLE_TEST, AI_DOUBLE_BATTLE_TEST, AI_MULTI_BATTLE_TEST, AI_TWO_VS_ONE_TEST, and AI_ONE_VS_TWO_TEST"); INVALID_IF(DATA.actionBattlers & (1 << battlerId), "Multiple battler actions"); INVALID_IF(partyIndex >= ((battlerId & BIT_SIDE) == B_SIDE_PLAYER ? DATA.playerPartySize : DATA.opponentPartySize), "EXPECT_SWITCH to invalid party index"); @@ -2819,6 +3103,11 @@ u32 TestRunner_Battle_GetForcedAbility(u32 side, u32 partyIndex) return DATA.forcedAbilities[side][partyIndex]; } +u32 TestRunner_Battle_GetForcedEnvironment(void) +{ + return DATA.forcedEnvironment; +} + u32 TestRunner_Battle_GetChosenGimmick(u32 side, u32 partyIndex) { return DATA.chosenGimmick[side][partyIndex]; From 83018f36eb965303bf2dbefa262203a05ec08bff Mon Sep 17 00:00:00 2001 From: cawtds <38510667+cawtds@users.noreply.github.com> Date: Fri, 14 Nov 2025 18:13:35 +0100 Subject: [PATCH 3/6] update controllers and fix remaining tests --- include/battle_controllers.h | 10 +- include/battle_gimmick.h | 1 + include/constants/form_change_types.h | 8 +- include/data.h | 83 +++---- include/debug.h | 4 + src/battle_controller_opponent.c | 51 +++- src/battle_controller_player.c | 75 ++++-- src/battle_controller_player_partner.c | 17 +- src/battle_controller_recorded_opponent.c | 24 +- src/battle_controller_recorded_partner.c | 269 ++++++++++++++++++++++ src/battle_controller_recorded_player.c | 79 ++++--- src/battle_controllers.c | 121 ++++++---- src/battle_gimmick.c | 7 + src/battle_intro.c | 13 +- src/battle_message.c | 71 +++++- src/data/battle_partners.h | 2 +- src/data/battle_partners.party | 2 +- src/data/pokemon/form_change_tables.h | 244 +++++++++++++++++++- src/data/pokemon/form_species_tables.h | 237 +++++++++++++++++++ 19 files changed, 1129 insertions(+), 189 deletions(-) create mode 100644 src/battle_controller_recorded_partner.c diff --git a/include/battle_controllers.h b/include/battle_controllers.h index 71799e16e..98003ba60 100644 --- a/include/battle_controllers.h +++ b/include/battle_controllers.h @@ -204,7 +204,7 @@ struct ChooseMoveStruct u8 currentPp[MAX_MON_MOVES]; u8 maxPp[MAX_MON_MOVES]; u16 species; - u8 monTypes[3]; + enum Type monTypes[3]; struct ZMoveData zmove; }; @@ -365,7 +365,7 @@ void BtlController_HandleSpriteInvisibility(u32 battler); bool32 TwoPlayerIntroMons(u32 battlerId); // Double battle with both player pokemon active. bool32 TwoOpponentIntroMons(u32 battlerId); // Double battle with both opponent pokemon active. void BtlController_HandleIntroTrainerBallThrow(u32 battler, u16 tagTrainerPal, const u16 *trainerPal, s16 framesToWait, void (*controllerCallback)(u32 battler)); -void BtlController_HandleDrawPartyStatusSummary(u32 battler, u32 side, bool32 considerDelay); +void BtlController_HandleDrawPartyStatusSummary(u32 battler, enum BattleSide side, bool32 considerDelay); void BtlController_HandleHidePartyStatusSummary(u32 battler); void BtlController_HandleBattleAnimation(u32 battler); @@ -396,6 +396,10 @@ void HandleChooseMoveAfterDma3(u32 battler); void SetControllerToRecordedPlayer(u32 battler); void RecordedPlayerBufferExecCompleted(u32 battler); +// recorded partner controller +void SetControllerToRecordedPartner(u32 battler); +void RecordedPartnerBufferExecCompleted(u32 battler); + // opponent controller void SetControllerToOpponent(u32 battler); void OpponentBufferExecCompleted(u32 battler); @@ -465,6 +469,8 @@ void BtlCtrl_DrawVoiceoverMessageFrame(void); void BtlCtrl_RemoveVoiceoverMessageFrame(void); bool32 ShouldBattleRestrictionsApply(u32 battler); +void FreeShinyStars(void); + // oak and old man controller void SetControllerToOakOrOldMan(u32 battler); diff --git a/include/battle_gimmick.h b/include/battle_gimmick.h index 42b8c7255..84b1d6b26 100644 --- a/include/battle_gimmick.h +++ b/include/battle_gimmick.h @@ -35,6 +35,7 @@ void SetGimmickAsActivated(u32 battler, enum Gimmick gimmick); void ChangeGimmickTriggerSprite(u32 spriteId, u32 animId); void CreateGimmickTriggerSprite(u32 battler); bool32 IsGimmickTriggerSpriteActive(void); +bool32 IsGimmickTriggerSpriteMatchingBattler(u32 battler); void HideGimmickTriggerSprite(void); void DestroyGimmickTriggerSprite(void); diff --git a/include/constants/form_change_types.h b/include/constants/form_change_types.h index a1c4c5bc4..f43f3bddc 100644 --- a/include/constants/form_change_types.h +++ b/include/constants/form_change_types.h @@ -48,7 +48,7 @@ enum FormChanges FORM_CHANGE_WITHDRAW, // Form change that activates when the Pokémon faints, either in battle or in the overworld by poison. // If species is not specified and it's on the player's side, it will try to use the value - // saved in gBattleStruct->changedSpecies from a previous form change. + // saved in gBattleStruct->partyState[x][y].changedSpecies from a previous form change. // - No parameters. FORM_CHANGE_FAINT, // Form change that activates when the Pokémon is sent out at the beginning of a battle @@ -56,13 +56,13 @@ enum FormChanges // param2: a move that will be replaced, optional // param3: a new move to replace it with, optional FORM_CHANGE_BEGIN_BATTLE, - // Form change that activates at the end of a battle. If species is not specified and it's on the player's side, it will try to use the value saved in gBattleStruct->changedSpecies from a previous form change. + // Form change that activates at the end of a battle. If species is not specified and it's on the player's side, it will try to use the value saved in gBattleStruct->partyState[x][y].changedSpecies from a previous form change. // param1: item to hold, optional // param2: a move that will be replaced, optional // param3: a new move to replace it with, optional FORM_CHANGE_END_BATTLE, - // Form change that activates at the end of a battle based on the terrain if it participated in the battle and hasn't fainted. Takes priority over FORM_CHANGE_END_BATTLE. - // param1: battle terrain to check. + // Form change that activates at the end of a battle based on the environment if it participated in the battle and hasn't fainted. Takes priority over FORM_CHANGE_END_BATTLE. + // param1: battle environment to check. FORM_CHANGE_END_BATTLE_ENVIRONMENT, // Form change that activates when the Pokémon is switched out in battle. // param1: ability to check, optional diff --git a/include/data.h b/include/data.h index a371bcd1c..7cccf3eba 100644 --- a/include/data.h +++ b/include/data.h @@ -5,6 +5,7 @@ #include "constants/trainers.h" #include "constants/battle.h" #include "difficulty.h" +#include "debug.h" #define MAX_TRAINER_ITEMS 4 @@ -193,27 +194,39 @@ extern const struct FollowerMsgInfo gFollowerCuriousMessages[]; extern const struct FollowerMsgInfo gFollowerMusicMessages[]; extern const struct FollowerMsgInfo gFollowerPoisonedMessages[]; + +static inline bool8 IsPartnerTrainerId(u16 trainerId) +{ + if (trainerId >= TRAINER_PARTNER(PARTNER_NONE) && trainerId < TRAINER_PARTNER(PARTNER_COUNT)) + return TRUE; + return FALSE; +} + static inline u16 SanitizeTrainerId(u16 trainerId) { - if (trainerId >= TRAINERS_COUNT) + if (trainerId >= TRAINERS_COUNT && !IsPartnerTrainerId(trainerId)) return TRAINER_NONE; return trainerId; } static inline const struct Trainer *GetTrainerStructFromId(u16 trainerId) { - u32 sanitizedTrainerId = SanitizeTrainerId(trainerId); + u32 sanitizedTrainerId = 0; + if (gIsDebugBattle) return GetDebugAiTrainer(); + sanitizedTrainerId = SanitizeTrainerId(trainerId); enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); - return &gTrainers[difficulty][sanitizedTrainerId]; + if (IsPartnerTrainerId(trainerId)) + return &gBattlePartners[difficulty][sanitizedTrainerId - TRAINER_PARTNER(PARTNER_NONE)]; + else + return &gTrainers[difficulty][sanitizedTrainerId]; } -static inline const u8 GetTrainerClassFromId(u16 trainerId) +static inline const enum TrainerClassID GetTrainerClassFromId(u16 trainerId) { - u32 sanitizedTrainerId = SanitizeTrainerId(trainerId); - enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); + const struct Trainer *trainer = GetTrainerStructFromId(trainerId); - return gTrainers[difficulty][sanitizedTrainerId].trainerClass; + return trainer->trainerClass; } static inline const u8 *GetTrainerClassNameFromId(u16 trainerId) @@ -227,82 +240,72 @@ static inline const u8 *GetTrainerClassNameFromId(u16 trainerId) static inline const u8 *GetTrainerNameFromId(u16 trainerId) { - u32 sanitizedTrainerId = SanitizeTrainerId(trainerId); - - enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); - - enum DifficultyLevel partnerDifficulty = GetBattlePartnerDifficultyLevel(trainerId); - if (trainerId > TRAINER_PARTNER(PARTNER_NONE)) + { + enum DifficultyLevel partnerDifficulty = GetBattlePartnerDifficultyLevel(trainerId); return gBattlePartners[partnerDifficulty][trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerName; - return gTrainers[difficulty][sanitizedTrainerId].trainerName; + } + return GetTrainerStructFromId(trainerId)->trainerName; } static inline const u8 GetTrainerPicFromId(u16 trainerId) { - u32 sanitizedTrainerId = SanitizeTrainerId(trainerId); - enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); enum DifficultyLevel partnerDifficulty = GetBattlePartnerDifficultyLevel(trainerId); if (trainerId > TRAINER_PARTNER(PARTNER_NONE)) return gBattlePartners[partnerDifficulty][trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerPic; - return gTrainers[difficulty][sanitizedTrainerId].trainerPic; + return GetTrainerStructFromId(trainerId)->trainerPic; +} + +static inline const u8 GetTrainerBackPicFromId(u16 trainerId) +{ + enum DifficultyLevel partnerDifficulty = GetBattlePartnerDifficultyLevel(trainerId); + + if (trainerId > TRAINER_PARTNER(PARTNER_NONE)) + return gBattlePartners[partnerDifficulty][trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerBackPic; + + return GetTrainerStructFromId(trainerId)->trainerBackPic; } static inline const u8 GetTrainerStartingStatusFromId(u16 trainerId) { - return gTrainers[GetCurrentDifficultyLevel()][SanitizeTrainerId(trainerId)].startingStatus; + return GetTrainerStructFromId(trainerId)->startingStatus; } static inline const enum TrainerBattleType GetTrainerBattleType(u16 trainerId) { - u32 sanitizedTrainerId = SanitizeTrainerId(trainerId); - enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); - - return gTrainers[difficulty][sanitizedTrainerId].battleType; + return GetTrainerStructFromId(trainerId)->battleType; } static inline const u8 GetTrainerPartySizeFromId(u16 trainerId) { - u32 sanitizedTrainerId = SanitizeTrainerId(trainerId); - enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); - - return gTrainers[difficulty][sanitizedTrainerId].partySize; + return GetTrainerStructFromId(trainerId)->partySize; } static inline const bool32 DoesTrainerHaveMugshot(u16 trainerId) { - return gTrainers[GetCurrentDifficultyLevel()][SanitizeTrainerId(trainerId)].mugshotColor; + return GetTrainerStructFromId(trainerId)->mugshotColor; } static inline const u8 GetTrainerMugshotColorFromId(u16 trainerId) { - return gTrainers[GetCurrentDifficultyLevel()][SanitizeTrainerId(trainerId)].mugshotColor; + return GetTrainerStructFromId(trainerId)->mugshotColor; } static inline const u16 *GetTrainerItemsFromId(u16 trainerId) { - u32 sanitizedTrainerId = SanitizeTrainerId(trainerId); - enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); - - return gTrainers[difficulty][sanitizedTrainerId].items; + return GetTrainerStructFromId(trainerId)->items; } static inline const struct TrainerMon *GetTrainerPartyFromId(u16 trainerId) { - u32 sanitizedTrainerId = SanitizeTrainerId(trainerId); - enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); - - return gTrainers[difficulty][sanitizedTrainerId].party; + return GetTrainerStructFromId(trainerId)->party; } static inline const u64 GetTrainerAIFlagsFromId(u16 trainerId) { - u32 sanitizedTrainerId = SanitizeTrainerId(trainerId); - enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); - - return gTrainers[difficulty][sanitizedTrainerId].aiFlags; + return GetTrainerStructFromId(trainerId)->aiFlags; } #endif // GUARD_DATA_H diff --git a/include/debug.h b/include/debug.h index 1a48e9f6c..01be269c4 100644 --- a/include/debug.h +++ b/include/debug.h @@ -4,6 +4,10 @@ void Debug_ShowMainMenu(void); extern const u8 Debug_FlagsAndVarNotSetBattleConfigMessage[]; const u8 *GetWeatherName(u32 weatherId); +const struct Trainer* GetDebugAiTrainer(void); + +void DebugNative_GetAbilityNames(void); +void DebugNative_Party_SetFriendship(void); extern EWRAM_DATA bool8 gIsDebugBattle; extern EWRAM_DATA u64 gDebugAIFlags; diff --git a/src/battle_controller_opponent.c b/src/battle_controller_opponent.c index 32323639e..59ffa5542 100644 --- a/src/battle_controller_opponent.c +++ b/src/battle_controller_opponent.c @@ -39,7 +39,10 @@ #include "constants/songs.h" #include "constants/trainers.h" // #include "trainer_hill.h" +#include "trainer_tower.h" #include "test_runner.h" +#include "test/battle.h" +#include "test/test_runner_battle.h" static void OpponentHandleDrawTrainerPic(u32 battler); static void OpponentHandleTrainerSlideBack(u32 battler); @@ -160,8 +163,7 @@ static void Intro_WaitForShinyAnimAndHealthbox(u32 battler) gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim = FALSE; gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].triedShinyMonAnim = FALSE; gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].finishedShinyMonAnim = FALSE; - FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS); - FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS); + FreeShinyStars(); } else { @@ -175,8 +177,7 @@ static void Intro_WaitForShinyAnimAndHealthbox(u32 battler) if (!gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].triedShinyMonAnim && !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].finishedShinyMonAnim) { - FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS); - FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS); + FreeShinyStars(); } else { @@ -354,18 +355,40 @@ static u32 OpponentGetTrainerPicId(u32 battlerId) static void OpponentHandleDrawTrainerPic(u32 battler) { s16 xPos; - u32 trainerPicId = OpponentGetTrainerPicId(battler); - - if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS) && !BATTLE_TWO_VS_ONE_OPPONENT) + u32 trainerPicId; + + // Sets Multibattle test opponent sprites to not be Hiker + if (IsMultibattleTest()) { - if ((GetBattlerPosition(battler) & BIT_FLANK) != 0) // second mon + if (GetBattlerPosition(battler) == B_POSITION_OPPONENT_LEFT) + { + trainerPicId = TRAINER_PIC_LEAF; + if (!(gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)) + xPos = 176; + else + xPos = 200; + } + else + { + trainerPicId = TRAINER_PIC_RED; xPos = 152; - else // first mon - xPos = 200; + } } else { - xPos = 176; + trainerPicId = OpponentGetTrainerPicId(battler); + + if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS) && !BATTLE_TWO_VS_ONE_OPPONENT) + { + if ((GetBattlerPosition(battler) & BIT_FLANK) != 0) // second mon + xPos = 152; + else // first mon + xPos = 200; + } + else + { + xPos = 176; + } } BtlController_HandleDrawTrainerPic(battler, trainerPicId, TRUE, xPos, (8 - gTrainerSprites[trainerPicId].frontPicCoords.size) * 4 + 40, -1); @@ -520,6 +543,12 @@ static void OpponentHandleChoosePokemon(u32 battler) { if (IsSwitchOutEffect(GetMoveEffect(gCurrentMove)) || gAiLogicData->ejectButtonSwitch || gAiLogicData->ejectPackSwitch) switchType = SWITCH_MID_BATTLE; + + // reset the AI data to consider the correct on-field state at time of switch + SetBattlerAiData(GetBattlerAtPosition(B_POSITION_PLAYER_LEFT), gAiLogicData); + if (IsDoubleBattle()) + SetBattlerAiData(GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT), gAiLogicData); + chosenMonId = GetMostSuitableMonToSwitchInto(battler, switchType); if (chosenMonId == PARTY_SIZE) { diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index 0895f4568..cc42ddb40 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -37,7 +37,6 @@ #include "constants/battle_anim.h" #include "constants/battle_move_effects.h" #include "constants/battle_partner.h" -#include "constants/hold_effects.h" #include "constants/items.h" #include "constants/moves.h" #include "constants/party_menu.h" @@ -49,6 +48,8 @@ #include "pokemon_summary_screen.h" #include "type_icons.h" #include "pokedex.h" +#include "test/battle.h" +#include "test/test_runner_battle.h" static void PlayerHandleLoadMonSprite(u32 battler); static void PlayerHandleDrawTrainerPic(u32 battler); @@ -457,6 +458,13 @@ void HandleInputChooseTarget(u32 battler) PlaySE(SE_SELECT); gSprites[gBattlerSpriteIds[gMultiUsePlayerCursor]].callback = SpriteCB_HideAsMoveTarget; gBattlerControllerFuncs[battler] = HandleInputChooseMove; + if (gBattleStruct->gimmick.playerSelect == 1 && gBattleStruct->gimmick.usableGimmick[battler] == GIMMICK_Z_MOVE) + { + gBattleStruct->gimmick.playerSelect = 0; + gBattleStruct->zmove.viewing = TRUE; + ReloadMoveNames(battler); + } + TryToAddMoveInfoWindow(); DoBounceEffect(battler, BOUNCE_HEALTHBOX, 7, 1); DoBounceEffect(battler, BOUNCE_MON, 7, 1); EndBounceEffect(gMultiUsePlayerCursor, BOUNCE_HEALTHBOX); @@ -1258,8 +1266,7 @@ static void Intro_WaitForShinyAnimAndHealthbox(u32 battler) gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim = FALSE; gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].triedShinyMonAnim = FALSE; gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].finishedShinyMonAnim = FALSE; - FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS); - FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS); + FreeShinyStars(); HandleLowHpMusicChange(GetBattlerMon(battler), battler); @@ -1774,7 +1781,7 @@ static void MoveSelectionDisplayMoveType(u32 battler) struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct *)(&gBattleResources->bufferA[battler][4]); txtPtr = StringCopy(gDisplayedStringBattle, gText_MoveInterfaceType); u32 move = moveInfo->moves[gMoveSelectionCursor[battler]]; - u32 type = GetMoveType(move); + enum Type type = GetMoveType(move); enum BattleMoveEffects effect = GetMoveEffect(move); if (effect == EFFECT_TERA_BLAST) @@ -1826,6 +1833,14 @@ static void MoveSelectionDisplayMoveDescription(u32 battler) u16 move = moveInfo->moves[gMoveSelectionCursor[battler]]; u16 pwr = GetMovePower(move); u16 acc = GetMoveAccuracy(move); + enum DamageCategory cat = GetBattleMoveCategory(move); + + if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX || IsGimmickSelected(battler, GIMMICK_DYNAMAX)) + { + pwr = GetMaxMovePower(move); + move = GetMaxMove(battler, move); + acc = 0; + } u8 pwr_num[3], acc_num[3]; u8 cat_desc[7] = _("CAT: "); @@ -1859,7 +1874,7 @@ static void MoveSelectionDisplayMoveDescription(u32 battler) if (gCategoryIconSpriteId == 0xFF) gCategoryIconSpriteId = CreateSprite(&gSpriteTemplate_CategoryIcons, 38, 64, 1); - StartSpriteAnim(&gSprites[gCategoryIconSpriteId], GetBattleMoveCategory(move)); + StartSpriteAnim(&gSprites[gCategoryIconSpriteId], cat); CopyWindowToVram(B_WIN_MOVE_DESCRIPTION, COPYWIN_FULL); } @@ -1966,30 +1981,40 @@ static void PlayerHandleDrawTrainerPic(u32 battler) bool32 isFrontPic; s16 xPos, yPos; u32 trainerPicId; - - trainerPicId = PlayerGetTrainerBackPicId(); - if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + if (IsMultibattleTest()) { - if ((GetBattlerPosition(battler) & BIT_FLANK) != B_FLANK_LEFT) // Second mon, on the right. - xPos = 90; - else // First mon, on the left. + trainerPicId = TRAINER_BACK_PIC_RED; + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) xPos = 32; - - if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gPartnerTrainerId < TRAINER_PARTNER(PARTNER_NONE)) - { - xPos = 90; - yPos = 80; - } else - { - yPos = (8 - gTrainerBacksprites[trainerPicId].coordinates.size) * 4 + 80; - } - + xPos = 80; + yPos = (8 - gTrainerBacksprites[trainerPicId].coordinates.size) * 4 + 80; } else { - xPos = 80; - yPos = (8 - gTrainerBacksprites[trainerPicId].coordinates.size) * 4 + 80; + trainerPicId = PlayerGetTrainerBackPicId(); + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + if ((GetBattlerPosition(battler) & BIT_FLANK) != B_FLANK_LEFT) // Second mon, on the right. + xPos = 90; + else // First mon, on the left. + xPos = 32; + + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gPartnerTrainerId < TRAINER_PARTNER(PARTNER_NONE)) + { + xPos = 90; + yPos = 80; + } + else + { + yPos = (8 - gTrainerBacksprites[trainerPicId].coordinates.size) * 4 + 80; + } + } + else + { + xPos = 80; + yPos = (8 - gTrainerBacksprites[trainerPicId].coordinates.size) * 4 + 80; + } } // Use front pic table for any tag battles unless your partner is Steven or a custom partner. @@ -2101,7 +2126,7 @@ static void PlayerHandleChooseAction(u32 battler) else if (gAiBattleData->chosenTarget[B_POSITION_PLAYER_RIGHT] == B_POSITION_PLAYER_LEFT) StringAppend(gStringVar1, COMPOUND_STRING(" {DOWN_ARROW}-")); else if (gAiBattleData->chosenTarget[B_POSITION_PLAYER_RIGHT] == B_POSITION_PLAYER_RIGHT) - StringAppend(gStringVar1, COMPOUND_STRING(" {DOWN_ARROW}-")); + StringAppend(gStringVar1, COMPOUND_STRING(" -{DOWN_ARROW}")); } else if (moveTarget == MOVE_TARGET_BOTH) { @@ -2181,6 +2206,8 @@ void PlayerHandleChooseMove(u32 battler) if (!IsGimmickTriggerSpriteActive()) gBattleStruct->gimmick.triggerSpriteId = 0xFF; + else if (!IsGimmickTriggerSpriteMatchingBattler(battler)) + DestroyGimmickTriggerSprite(); if (!(gBattleStruct->gimmick.usableGimmick[battler] == GIMMICK_Z_MOVE && !gBattleStruct->zmove.viable)) CreateGimmickTriggerSprite(battler); diff --git a/src/battle_controller_player_partner.c b/src/battle_controller_player_partner.c index c2340a089..872a9b1b8 100644 --- a/src/battle_controller_player_partner.c +++ b/src/battle_controller_player_partner.c @@ -31,6 +31,8 @@ #include "constants/songs.h" #include "constants/party_menu.h" #include "constants/trainers.h" +#include "test/battle.h" +#include "test/test_runner_battle.h" static void PlayerPartnerHandleDrawTrainerPic(u32 battler); static void PlayerPartnerHandleTrainerSlideBack(u32 battler); @@ -204,7 +206,13 @@ static void PlayerPartnerHandleDrawTrainerPic(u32 battler) enum DifficultyLevel difficulty = GetBattlePartnerDifficultyLevel(gPartnerTrainerId); - if (gPartnerTrainerId > TRAINER_PARTNER(PARTNER_NONE)) + if (IsMultibattleTest()) + { + trainerPicId = TRAINER_BACK_PIC_STEVEN; + xPos = 90; + yPos = (8 - gTrainerBacksprites[trainerPicId].coordinates.size) * 4 + 80; + } + else if (gPartnerTrainerId > TRAINER_PARTNER(PARTNER_NONE)) { trainerPicId = gBattlePartners[difficulty][gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerBackPic; xPos = 90; @@ -285,7 +293,6 @@ static void PlayerPartnerHandleChoosePokemon(u32 battler) else if (gBattleStruct->monToSwitchIntoId[battler] >= PARTY_SIZE || !IsValidForBattle(&gPlayerParty[gBattleStruct->monToSwitchIntoId[battler]])) { chosenMonId = GetMostSuitableMonToSwitchInto(battler, SWITCH_AFTER_KO); - if (chosenMonId == PARTY_SIZE || !IsValidForBattle(&gPlayerParty[chosenMonId])) // just switch to the next mon { s32 firstId = (IsAiVsAiBattle()) ? 0 : (PARTY_SIZE / 2); @@ -310,6 +317,8 @@ static void PlayerPartnerHandleChoosePokemon(u32 battler) gBattleStruct->AI_monToSwitchIntoId[battler] = PARTY_SIZE; gBattleStruct->monToSwitchIntoId[battler] = chosenMonId; } + if (TESTING) + TestRunner_Battle_CheckSwitch(battler, chosenMonId); BtlController_EmitChosenMonReturnValue(battler, B_COMM_TO_ENGINE, chosenMonId, NULL); BtlController_Complete(battler); } @@ -320,9 +329,9 @@ static void PlayerPartnerHandleIntroTrainerBallThrow(u32 battler) enum DifficultyLevel difficulty = GetBattlePartnerDifficultyLevel(gPartnerTrainerId); if (gPartnerTrainerId > TRAINER_PARTNER(PARTNER_NONE)) - trainerPal = gTrainerBacksprites[gBattlePartners[difficulty][gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerPic].palette.data; + trainerPal = gTrainerBacksprites[gBattlePartners[difficulty][gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerBackPic].palette.data; else if (IsAiVsAiBattle()) - trainerPal = gTrainerSprites[GetTrainerPicFromId(gPartnerTrainerId)].palette.data; + trainerPal = gTrainerSprites[GetTrainerBackPicFromId(gPartnerTrainerId)].palette.data; else trainerPal = gTrainerSprites[GetBattleTowerTrainerFrontSpriteId(gPartnerTrainerId)].palette.data; // 2 vs 2 multi battle in Battle Frontier, load front sprite and pal. diff --git a/src/battle_controller_recorded_opponent.c b/src/battle_controller_recorded_opponent.c index 0432e250c..adc55d634 100644 --- a/src/battle_controller_recorded_opponent.c +++ b/src/battle_controller_recorded_opponent.c @@ -31,6 +31,8 @@ #include "constants/battle_anim.h" #include "constants/songs.h" #include "constants/trainers.h" +#include "test/battle.h" +#include "test/test_runner_battle.h" static void RecordedOpponentHandleDrawTrainerPic(u32 battler); static void RecordedOpponentHandleTrainerSlideBack(u32 battler); @@ -170,8 +172,7 @@ static void Intro_WaitForShinyAnimAndHealthbox(u32 battler) gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim = FALSE; gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].triedShinyMonAnim = FALSE; gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].finishedShinyMonAnim = FALSE; - FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS); - FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS); + FreeShinyStars(); } gBattleSpritesDataPtr->healthBoxesData[battler].introEndDelay = 3; @@ -274,7 +275,24 @@ static void RecordedOpponentHandleDrawTrainerPic(u32 battler) s16 xPos; u32 trainerPicId; - if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + // Sets Multibattle test opponent sprites to not be Hiker + if (IsMultibattleTest()) + { + if (GetBattlerPosition(battler) == B_POSITION_OPPONENT_LEFT) + { + trainerPicId = TRAINER_PIC_LEAF; + if (!(gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)) + xPos = 176; + else + xPos = 200; + } + else + { + trainerPicId = TRAINER_PIC_RED; + xPos = 152; + } + } + else if (gBattleTypeFlags & BATTLE_TYPE_MULTI) { if ((GetBattlerPosition(battler) & BIT_FLANK) != 0) // second mon xPos = 152; diff --git a/src/battle_controller_recorded_partner.c b/src/battle_controller_recorded_partner.c new file mode 100644 index 000000000..c1b5f6e14 --- /dev/null +++ b/src/battle_controller_recorded_partner.c @@ -0,0 +1,269 @@ +#include "global.h" +#include "battle.h" +#include "battle_ai_main.h" +#include "battle_ai_util.h" +#include "battle_anim.h" +#include "battle_controllers.h" +#include "battle_message.h" +#include "battle_interface.h" +#include "battle_setup.h" +#include "battle_tower.h" +#include "battle_z_move.h" +#include "bg.h" +#include "data.h" +#include "item_use.h" +#include "link.h" +#include "main.h" +#include "m4a.h" +#include "palette.h" +#include "party_menu.h" +#include "pokeball.h" +#include "pokemon.h" +#include "recorded_battle.h" +#include "reshow_battle_screen.h" +#include "sound.h" +#include "string_util.h" +#include "task.h" +#include "test_runner.h" +#include "text.h" +#include "util.h" +#include "window.h" +#include "constants/battle_anim.h" +#include "constants/battle_partner.h" +#include "constants/songs.h" +#include "constants/party_menu.h" +#include "constants/trainers.h" + +static void RecordedPartnerHandleDrawTrainerPic(u32 battler); +static void RecordedPartnerHandleTrainerSlideBack(u32 battler); +static void RecordedPartnerHandleChooseAction(u32 battler); +static void RecordedPartnerHandleChooseMove(u32 battler); +static void RecordedPartnerHandleChoosePokemon(u32 battler); +static void RecordedPartnerHandleIntroTrainerBallThrow(u32 battler); +static void RecordedPartnerHandleDrawPartyStatusSummary(u32 battler); +static void RecordedPartnerHandleEndLinkBattle(u32 battler); +static void RecordedPartnerBufferRunCommand(u32 battler); + +static void (*const sRecordedPartnerBufferCommands[CONTROLLER_CMDS_COUNT])(u32 battler) = +{ + [CONTROLLER_GETMONDATA] = BtlController_HandleGetMonData, + [CONTROLLER_GETRAWMONDATA] = BtlController_Empty, + [CONTROLLER_SETMONDATA] = BtlController_HandleSetMonData, + [CONTROLLER_SETRAWMONDATA] = BtlController_HandleSetRawMonData, + [CONTROLLER_LOADMONSPRITE] = BtlController_HandleLoadMonSprite, + [CONTROLLER_SWITCHINANIM] = BtlController_HandleSwitchInAnim, + [CONTROLLER_RETURNMONTOBALL] = BtlController_HandleReturnMonToBall, + [CONTROLLER_DRAWTRAINERPIC] = RecordedPartnerHandleDrawTrainerPic, + [CONTROLLER_TRAINERSLIDE] = BtlController_Empty, + [CONTROLLER_TRAINERSLIDEBACK] = RecordedPartnerHandleTrainerSlideBack, + [CONTROLLER_FAINTANIMATION] = BtlController_HandleFaintAnimation, + [CONTROLLER_PALETTEFADE] = BtlController_Empty, + [CONTROLLER_SUCCESSBALLTHROWANIM] = BtlController_Empty, + [CONTROLLER_BALLTHROWANIM] = BtlController_Empty, + [CONTROLLER_PAUSE] = BtlController_Empty, + [CONTROLLER_MOVEANIMATION] = BtlController_HandleMoveAnimation, + [CONTROLLER_PRINTSTRING] = BtlController_HandlePrintString, + [CONTROLLER_PRINTSTRINGPLAYERONLY] = BtlController_Empty, + [CONTROLLER_CHOOSEACTION] = RecordedPartnerHandleChooseAction, + [CONTROLLER_YESNOBOX] = BtlController_Empty, + [CONTROLLER_CHOOSEMOVE] = RecordedPartnerHandleChooseMove, + [CONTROLLER_OPENBAG] = BtlController_Empty, + [CONTROLLER_CHOOSEPOKEMON] = RecordedPartnerHandleChoosePokemon, + [CONTROLLER_23] = BtlController_Empty, + [CONTROLLER_HEALTHBARUPDATE] = BtlController_HandleHealthBarUpdate, + [CONTROLLER_EXPUPDATE] = PlayerHandleExpUpdate, // Partner's player gets experience the same way as the player. + [CONTROLLER_STATUSICONUPDATE] = BtlController_HandleStatusIconUpdate, + [CONTROLLER_STATUSANIMATION] = BtlController_HandleStatusAnimation, + [CONTROLLER_STATUSXOR] = BtlController_Empty, + [CONTROLLER_DATATRANSFER] = BtlController_Empty, + [CONTROLLER_DMA3TRANSFER] = BtlController_Empty, + [CONTROLLER_PLAYBGM] = BtlController_Empty, + [CONTROLLER_32] = BtlController_Empty, + [CONTROLLER_TWORETURNVALUES] = BtlController_Empty, + [CONTROLLER_CHOSENMONRETURNVALUE] = BtlController_Empty, + [CONTROLLER_ONERETURNVALUE] = BtlController_Empty, + [CONTROLLER_ONERETURNVALUE_DUPLICATE] = BtlController_Empty, + [CONTROLLER_HITANIMATION] = BtlController_HandleHitAnimation, + [CONTROLLER_CANTSWITCH] = BtlController_Empty, + [CONTROLLER_PLAYSE] = BtlController_HandlePlaySE, + [CONTROLLER_PLAYFANFAREORBGM] = BtlController_HandlePlayFanfareOrBGM, + [CONTROLLER_FAINTINGCRY] = BtlController_HandleFaintingCry, + [CONTROLLER_INTROSLIDE] = BtlController_HandleIntroSlide, + [CONTROLLER_INTROTRAINERBALLTHROW] = RecordedPartnerHandleIntroTrainerBallThrow, + [CONTROLLER_DRAWPARTYSTATUSSUMMARY] = RecordedPartnerHandleDrawPartyStatusSummary, + [CONTROLLER_HIDEPARTYSTATUSSUMMARY] = BtlController_HandleHidePartyStatusSummary, + [CONTROLLER_ENDBOUNCE] = BtlController_Empty, + [CONTROLLER_SPRITEINVISIBILITY] = BtlController_HandleSpriteInvisibility, + [CONTROLLER_BATTLEANIMATION] = BtlController_HandleBattleAnimation, + [CONTROLLER_LINKSTANDBYMSG] = BtlController_Empty, + [CONTROLLER_RESETACTIONMOVESELECTION] = BtlController_Empty, + [CONTROLLER_ENDLINKBATTLE] = RecordedPartnerHandleEndLinkBattle, + [CONTROLLER_DEBUGMENU] = BtlController_Empty, + [CONTROLLER_TERMINATOR_NOP] = BtlController_TerminatorNop +}; + +void SetControllerToRecordedPartner(u32 battler) +{ + gBattlerControllerEndFuncs[battler] = RecordedPartnerBufferExecCompleted; + gBattlerControllerFuncs[battler] = RecordedPartnerBufferRunCommand; +} + +static void RecordedPartnerBufferRunCommand(u32 battler) +{ + if (IsBattleControllerActiveOnLocal(battler)) + { + if (gBattleResources->bufferA[battler][0] < ARRAY_COUNT(sRecordedPartnerBufferCommands)) + sRecordedPartnerBufferCommands[gBattleResources->bufferA[battler][0]](battler); + else + BtlController_Complete(battler); + } +} + +static void Intro_WaitForHealthbox(u32 battler) +{ + bool32 finished = FALSE; + + if (!IsDoubleBattle() || (IsDoubleBattle() && (gBattleTypeFlags & BATTLE_TYPE_MULTI))) + { + if (gSprites[gHealthboxSpriteIds[battler]].callback == SpriteCallbackDummy) + finished = TRUE; + } + else + { + if (gSprites[gHealthboxSpriteIds[battler]].callback == SpriteCallbackDummy + && gSprites[gHealthboxSpriteIds[BATTLE_PARTNER(battler)]].callback == SpriteCallbackDummy) + { + finished = TRUE; + } + } + + if (IsCryPlayingOrClearCrySongs()) + finished = FALSE; + + if (finished) + { + gBattleSpritesDataPtr->healthBoxesData[battler].introEndDelay = 3; + gBattlerControllerFuncs[battler] = BtlController_Intro_DelayAndEnd; + } +} + +void Controller_RecordedPartnerShowIntroHealthbox(u32 battler) +{ + if (!gBattleSpritesDataPtr->healthBoxesData[battler].ballAnimActive + && !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].ballAnimActive + && gSprites[gBattleControllerData[battler]].callback == SpriteCallbackDummy + && gSprites[gBattlerSpriteIds[battler]].callback == SpriteCallbackDummy + && ++gBattleSpritesDataPtr->healthBoxesData[battler].introEndDelay != 1) + { + gBattleSpritesDataPtr->healthBoxesData[battler].introEndDelay = 0; + TryShinyAnimation(battler, GetBattlerMon(battler)); + + if (IsDoubleBattle() && !(gBattleTypeFlags & BATTLE_TYPE_MULTI)) + { + DestroySprite(&gSprites[gBattleControllerData[BATTLE_PARTNER(battler)]]); + UpdateHealthboxAttribute(gHealthboxSpriteIds[BATTLE_PARTNER(battler)], GetBattlerMon(BATTLE_PARTNER(battler)), HEALTHBOX_ALL); + StartHealthboxSlideIn(BATTLE_PARTNER(battler)); + SetHealthboxSpriteVisible(gHealthboxSpriteIds[BATTLE_PARTNER(battler)]); + } + + DestroySprite(&gSprites[gBattleControllerData[battler]]); + UpdateHealthboxAttribute(gHealthboxSpriteIds[battler], GetBattlerMon(battler), HEALTHBOX_ALL); + StartHealthboxSlideIn(battler); + SetHealthboxSpriteVisible(gHealthboxSpriteIds[battler]); + + gBattleSpritesDataPtr->animationData->introAnimActive = FALSE; + + gBattlerControllerFuncs[battler] = Intro_WaitForHealthbox; + } +} + +void RecordedPartnerBufferExecCompleted(u32 battler) +{ + gBattlerControllerFuncs[battler] = RecordedPartnerBufferRunCommand; + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + { + u8 playerId = GetMultiplayerId(); + + PrepareBufferDataTransferLink(battler, B_COMM_CONTROLLER_IS_DONE, 4, &playerId); + gBattleResources->bufferA[battler][0] = CONTROLLER_TERMINATOR_NOP; + } + else + { + MarkBattleControllerIdleOnLocal(battler); + } +} + +// some explanation here +// in emerald it's possible to have a tag battle in the battle frontier facilities with AI +// which use the front sprite for both the player and the partner as opposed to any other battles (including the one with Steven) that use the back pic as well as animate it +static void RecordedPartnerHandleDrawTrainerPic(u32 battler) +{ + bool32 isFrontPic; + s16 xPos, yPos; + u32 trainerPicId; + + trainerPicId = TRAINER_BACK_PIC_STEVEN; + xPos = 90; + yPos = (8 - gTrainerBacksprites[trainerPicId].coordinates.size) * 4 + 80; + + isFrontPic = FALSE; + + BtlController_HandleDrawTrainerPic(battler, trainerPicId, isFrontPic, xPos, yPos, -1); +} + +static void RecordedPartnerHandleTrainerSlideBack(u32 battler) +{ + BtlController_HandleTrainerSlideBack(battler, 35, FALSE); +} + +static void RecordedPartnerHandleChooseAction(u32 battler) +{ + BtlController_EmitTwoReturnValues(battler, B_COMM_TO_ENGINE, RecordedBattle_GetBattlerAction(RECORDED_ACTION_TYPE, battler), 0); + BtlController_Complete(battler); +} + +static void RecordedPartnerHandleChooseMove(u32 battler) +{ + u8 moveIndex = RecordedBattle_GetBattlerAction(RECORDED_MOVE_SLOT, battler); + u8 target = RecordedBattle_GetBattlerAction(RECORDED_MOVE_TARGET, battler); + BtlController_EmitTwoReturnValues(battler, B_COMM_TO_ENGINE, B_ACTION_EXEC_SCRIPT, moveIndex | (target << 8)); + + BtlController_Complete(battler); +} + +static void RecordedPartnerHandleChoosePokemon(u32 battler) +{ + gBattleStruct->monToSwitchIntoId[battler] = RecordedBattle_GetBattlerAction(RECORDED_PARTY_INDEX, battler); + gSelectedMonPartyId = gBattleStruct->monToSwitchIntoId[battler]; // Revival Blessing + BtlController_EmitChosenMonReturnValue(battler, B_COMM_TO_ENGINE, gBattleStruct->monToSwitchIntoId[battler], NULL); + BtlController_Complete(battler); +} + +static void RecordedPartnerHandleIntroTrainerBallThrow(u32 battler) +{ + const u16 *trainerPal; + enum DifficultyLevel difficulty = GetBattlePartnerDifficultyLevel(gPartnerTrainerId); + + if (gPartnerTrainerId > TRAINER_PARTNER(PARTNER_NONE)) + trainerPal = gTrainerBacksprites[gBattlePartners[difficulty][gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerPic].palette.data; + else if (IsAiVsAiBattle()) + trainerPal = gTrainerSprites[GetTrainerPicFromId(gPartnerTrainerId)].palette.data; + else + trainerPal = gTrainerSprites[GetBattleTowerTrainerFrontSpriteId(gPartnerTrainerId)].palette.data; // 2 vs 2 multi battle in Battle Frontier, load front sprite and pal. + + BtlController_HandleIntroTrainerBallThrow(battler, 0xD6F9, trainerPal, 24, Controller_RecordedPartnerShowIntroHealthbox); +} + +static void RecordedPartnerHandleDrawPartyStatusSummary(u32 battler) +{ + BtlController_HandleDrawPartyStatusSummary(battler, B_SIDE_PLAYER, TRUE); +} + +static void RecordedPartnerHandleEndLinkBattle(u32 battler) +{ + gBattleOutcome = gBattleResources->bufferA[battler][1]; + FadeOutMapMusic(5); + BeginFastPaletteFade(3); + BtlController_Complete(battler); + gBattlerControllerFuncs[battler] = SetBattleEndCallbacks; +} diff --git a/src/battle_controller_recorded_player.c b/src/battle_controller_recorded_player.c index 8ab4c665b..17de15f97 100644 --- a/src/battle_controller_recorded_player.c +++ b/src/battle_controller_recorded_player.c @@ -28,6 +28,8 @@ #include "constants/battle_anim.h" #include "constants/songs.h" #include "constants/trainers.h" +#include "test/battle.h" +#include "test/test_runner_battle.h" static void RecordedPlayerHandleDrawTrainerPic(u32 battler); static void RecordedPlayerHandleTrainerSlideBack(u32 battler); @@ -40,7 +42,6 @@ static void RecordedPlayerHandleStatusAnimation(u32 battler); static void RecordedPlayerHandleIntroTrainerBallThrow(u32 battler); static void RecordedPlayerHandleDrawPartyStatusSummary(u32 battler); static void RecordedPlayerHandleEndLinkBattle(u32 battler); - static void RecordedPlayerBufferRunCommand(u32 battler); static void (*const sRecordedPlayerBufferCommands[CONTROLLER_CMDS_COUNT])(u32 battler) = @@ -147,8 +148,7 @@ static void Intro_WaitForShinyAnimAndHealthbox(u32 battler) gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].triedShinyMonAnim = FALSE; gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].finishedShinyMonAnim = FALSE; - FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS); - FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS); + FreeShinyStars(); HandleLowHpMusicChange(GetBattlerMon(battler), battler); if (IsDoubleBattle()) @@ -276,43 +276,54 @@ static void RecordedPlayerHandleDrawTrainerPic(u32 battler) s16 xPos, yPos; u32 trainerPicId; - if (gBattleTypeFlags & BATTLE_TYPE_RECORDED_LINK) + // Sets Multibattle test player sprites to not be Hiker + if (IsMultibattleTest()) { - if (gBattleTypeFlags & BATTLE_TYPE_MULTI) - trainerPicId = GetBattlerLinkPlayerGender(battler); - else - trainerPicId = gLinkPlayers[gRecordedBattleMultiplayerId].gender; - } - else - { - trainerPicId = gLinkPlayers[0].gender; - } - - if (gBattleTypeFlags & BATTLE_TYPE_MULTI) - { - if ((GetBattlerPosition(battler) & BIT_FLANK) != 0) // second mon - xPos = 90; - else // first mon - xPos = 32; - + trainerPicId = TRAINER_BACK_PIC_RED; if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) - { - xPos = 90; - yPos = 80; - } + xPos = 32; else - { - yPos = (8 - gTrainerBacksprites[trainerPicId].coordinates.size) * 4 + 80; - } - - } - else - { - xPos = 80; + xPos = 80; yPos = (8 - gTrainerBacksprites[trainerPicId].coordinates.size) * 4 + 80; } + else + { + if (gBattleTypeFlags & BATTLE_TYPE_RECORDED_LINK) + { + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + trainerPicId = GetBattlerLinkPlayerGender(battler); + else + trainerPicId = gLinkPlayers[gRecordedBattleMultiplayerId].gender; + } + else + trainerPicId = gLinkPlayers[0].gender; - if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + if ((GetBattlerPosition(battler) & BIT_FLANK) != 0) // second mon + xPos = 90; + else // first mon + xPos = 32; + + // !TESTING added as otherwise first test battle sprite is positioned incorrectly + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && !TESTING) + { + xPos = 90; + yPos = 80; + } + else + { + yPos = (8 - gTrainerBacksprites[trainerPicId].coordinates.size) * 4 + 80; + } + } + else + { + xPos = 80; + yPos = (8 - gTrainerBacksprites[trainerPicId].coordinates.size) * 4 + 80; + } + } + + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && !TESTING) isFrontPic = TRUE; else isFrontPic = FALSE; diff --git a/src/battle_controllers.c b/src/battle_controllers.c index 8e91993ec..51bc97149 100644 --- a/src/battle_controllers.c +++ b/src/battle_controllers.c @@ -31,6 +31,9 @@ #include "constants/item_effects.h" #include "constants/songs.h" #include "constants/sound.h" +#include "test/battle.h" +#include "test/test.h" +#include "test/test_runner_battle.h" #include "pokemon_animation.h" static EWRAM_DATA u8 sLinkSendTaskId = 0; @@ -85,13 +88,13 @@ void SetUpBattleVars(void) BattleAI_SetupItems(); BattleAI_SetupFlags(); - // if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE) - // { - // ZeroEnemyPartyMons(); - // CreateMon(&gEnemyParty[0], SPECIES_ZIGZAGOON, 2, USE_RANDOM_IVS, 0, 0, OT_ID_PLAYER_ID, 0); - // i = 0; - // SetMonData(&gEnemyParty[0], MON_DATA_HELD_ITEM, &i); - // } + if (!IS_FRLG && gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE) + { + ZeroEnemyPartyMons(); + CreateMon(&gEnemyParty[0], SPECIES_ZIGZAGOON, 2, USE_RANDOM_IVS, 0, 0, OT_ID_PLAYER_ID, 0); + i = 0; + SetMonData(&gEnemyParty[0], MON_DATA_HELD_ITEM, &i); + } } void InitBattleControllers(void) @@ -165,6 +168,7 @@ static void InitBtlControllersInternal(void) if ((gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER) || !isMulti + || (IsMultibattleTest()) || (!isLink && !isRecorded) || (isLink && !isDouble)) { @@ -189,64 +193,82 @@ static void InitBtlControllersInternal(void) if (isLink) { if (isDouble && isMulti && !isMaster) - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_0]] = SetControllerToLinkPartner; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_0)] = SetControllerToLinkPartner; else - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_0]] = SetControllerToPlayer; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_0)] = SetControllerToPlayer; if (!isDouble || !isMulti || !isMaster) { - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_1]] = SetControllerToLinkOpponent; - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_2]] = SetControllerToPlayer; - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_3]] = SetControllerToLinkOpponent; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_1)] = SetControllerToLinkOpponent; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_2)] = SetControllerToPlayer; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_3)] = SetControllerToLinkOpponent; } else { - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_1]] = SetControllerToOpponent; - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_2]] = SetControllerToLinkPartner; - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_3]] = SetControllerToOpponent; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_1)] = SetControllerToOpponent; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_2)] = SetControllerToLinkPartner; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_3)] = SetControllerToOpponent; } } else { // Player 1 if (isRecorded) - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_0]] = SetControllerToRecordedPlayer; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_0)] = SetControllerToRecordedPlayer; else if (gBattleTypeFlags & BATTLE_TYPE_SAFARI) - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_0]] = SetControllerToSafari; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_0)] = SetControllerToSafari; else if (gBattleTypeFlags & (BATTLE_TYPE_OLD_MAN_TUTORIAL | BATTLE_TYPE_FIRST_BATTLE)) gBattlerControllerFuncs[B_BATTLER_0] = SetControllerToOakOrOldMan; else if (isAIvsAI) - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_0]] = SetControllerToPlayerPartner; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_0)] = SetControllerToPlayerPartner; else - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_0]] = SetControllerToPlayer; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_0)] = SetControllerToPlayer; // Opponent 1 bool32 isOpponent1Recorded; if (isDouble) - isOpponent1Recorded = (!isInGamePartner && isRecorded && !isMulti && isRecordedLink); + isOpponent1Recorded = ((!isInGamePartner && isRecorded && !isMulti && isRecordedLink) || (IsMultibattleTest() && isRecordedLink)); else isOpponent1Recorded = isRecorded && isRecordedLink; if (isOpponent1Recorded) - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_1]] = SetControllerToRecordedOpponent; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_1)] = SetControllerToRecordedOpponent; else - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_1]] = SetControllerToOpponent; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_1)] = SetControllerToOpponent; // Player 2 - if (isInGamePartner) - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_2]] = SetControllerToPlayerPartner; + if (IsMultibattleTest() && isRecordedLink) + { + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_2)] = SetControllerToRecordedPartner; + } + else if (IsMultibattleTest() && isRecorded && !isRecordedLink) + { // Sets to PlayerPartner if EXPECT_XXXX used in test for partner trainer, else sets to RecordedPartner. + if (gBattleTestRunnerState->data.expectedAiActions[B_BATTLER_2][0].actionSet == TRUE) + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_2)] = SetControllerToPlayerPartner; + else + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_2)] = SetControllerToRecordedPartner; + } + else if ((isInGamePartner && !isRecorded) + || isAIvsAI) + { + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_2)] = SetControllerToPlayerPartner; + } else if (isRecorded) - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_2]] = SetControllerToRecordedPlayer; - else if (isAIvsAI) - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_2]] = SetControllerToPlayerPartner; + { + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_2)] = SetControllerToRecordedPlayer; + } else - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_2]] = SetControllerToPlayer; + { + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_2)] = SetControllerToPlayer; + } // Opponent 2 - if (isInGamePartner || !isRecorded || isMulti || !isRecordedLink) - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_3]] = SetControllerToOpponent; + if (IsMultibattleTest() && isRecordedLink) + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_3)] = SetControllerToRecordedOpponent; + else if (isInGamePartner || !isRecorded || isMulti || !isRecordedLink) + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_3)] = SetControllerToOpponent; else - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_3]] = SetControllerToRecordedOpponent; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_3)] = SetControllerToRecordedOpponent; } bool32 bufferPartyOrders; @@ -339,6 +361,11 @@ static inline bool32 IsControllerRecordedPlayer(u32 battler) return (gBattlerControllerEndFuncs[battler] == RecordedPlayerBufferExecCompleted); } +static inline bool32 IsControllerRecordedPartner(u32 battler) +{ + return (gBattlerControllerEndFuncs[battler] == RecordedPartnerBufferExecCompleted); +} + static inline bool32 IsControllerOpponent(u32 battler) { return (gBattlerControllerEndFuncs[battler] == OpponentBufferExecCompleted); @@ -619,7 +646,7 @@ static void Task_HandleSendLinkBuffersData(u8 taskId) if (IsLinkTaskFinished()) { blockSize = BYTE_TO_SEND(LINK_BUFF_SIZE_LO) | (BYTE_TO_SEND(LINK_BUFF_SIZE_HI) << 8); - gTasks[taskId].tBlockSendDelayTimer = 5; + gTasks[taskId].tBlockSendDelayTimer = 1; gTasks[taskId].tCurrentBlock_Start = gTasks[taskId].tCurrentBlock_Start + blockSize + LINK_BUFF_DATA; gTasks[taskId].tState = SENDTASK_STATE_BEGIN_SEND_BLOCK; } @@ -627,7 +654,7 @@ static void Task_HandleSendLinkBuffersData(u8 taskId) case SENDTASK_STATE_UNUSED_STATE: if (--gTasks[taskId].tBlockSendDelayTimer == 0) { - gTasks[taskId].tBlockSendDelayTimer = 5; + gTasks[taskId].tBlockSendDelayTimer = 1; gTasks[taskId].tState = SENDTASK_STATE_BEGIN_SEND_BLOCK; } break; @@ -2307,6 +2334,7 @@ void BtlController_HandleSwitchInAnim(u32 battler) bool32 isPlayerSide = (IsControllerPlayer(battler) || IsControllerPlayerPartner(battler) || IsControllerRecordedPlayer(battler) + || IsControllerRecordedPartner(battler) || IsControllerLinkPartner(battler) || (IsControllerPokedude(battler) && GetBattlerSide(battler) == B_SIDE_PLAYER)); @@ -2608,6 +2636,7 @@ void BtlController_HandleHealthBarUpdate(u32 battler) SetBattleBarStruct(battler, gHealthboxSpriteIds[battler], maxHP, 0, hpVal); if (IsControllerPlayer(battler) || IsControllerRecordedPlayer(battler) + || IsControllerRecordedPartner(battler) || IsControllerOakOldMan(battler) || IsControllerPokedude(battler)) UpdateHpTextInHealthbox(gHealthboxSpriteIds[battler], HP_CURRENT, 0, maxHP); @@ -2744,7 +2773,7 @@ bool32 TwoOpponentIntroMons(u32 battler) // Double battle with both opponent pok void BtlController_HandleIntroTrainerBallThrow(u32 battler, u16 tagTrainerPal, const u16 *trainerPal, s16 framesToWait, void (*controllerCallback)(u32 battler)) { u8 paletteNum, taskId; - u32 side = GetBattlerSide(battler); + enum BattleSide side = GetBattlerSide(battler); SetSpritePrimaryCoordsFromSecondaryCoords(&gSprites[gBattleStruct->trainerSlideSpriteIds[battler]]); if (side == B_SIDE_PLAYER) @@ -2873,7 +2902,7 @@ static void SpriteCB_FreeOpponentSprite(struct Sprite *sprite) #undef sBattlerId -void BtlController_HandleDrawPartyStatusSummary(u32 battler, u32 side, bool32 considerDelay) +void BtlController_HandleDrawPartyStatusSummary(u32 battler, enum BattleSide side, bool32 considerDelay) { if (gBattleResources->bufferA[battler][1] != 0 && IsOnPlayerSide(battler)) { @@ -3010,8 +3039,7 @@ void TryShinyAnimAfterMonAnim(u32 battler) { gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim = FALSE; gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim = FALSE; - FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS); - FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS); + FreeShinyStars(); BtlController_Complete(battler); } } @@ -3076,14 +3104,13 @@ void BtlController_HandleSwitchInSoundAndEnd(u32 battler) void BtlController_HandleSwitchInShowHealthbox(u32 battler) { - u32 side = GetBattlerSide(battler); + enum BattleSide side = GetBattlerSide(battler); if (gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim && (side == B_SIDE_PLAYER || gSprites[gBattlerSpriteIds[battler]].callback == SpriteCallbackDummy)) { gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim = FALSE; gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim = FALSE; - FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS); - FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS); + FreeShinyStars(); if (side == B_SIDE_PLAYER) { @@ -3113,8 +3140,7 @@ static void SwitchIn_CleanShinyAnimShowSubstitute(u32 battler) // Reset shiny anim (even if it didn't occur) gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim = FALSE; gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim = FALSE; - FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS); - FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS); + FreeShinyStars(); // Check if Substitute should be shown if (gBattleSpritesDataPtr->battlerData[battler].behindSubstitute) @@ -3199,3 +3225,14 @@ bool32 ShouldBattleRestrictionsApply(u32 battler) { return IsControllerPlayer(battler); } + +void FreeShinyStars(void) +{ + for (u32 battler = 0; battler < gBattlersCount; battler++) + { + if (gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim) + return; + } + FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS); + FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS); +} diff --git a/src/battle_gimmick.c b/src/battle_gimmick.c index 76ea80a4f..38d60d436 100644 --- a/src/battle_gimmick.c +++ b/src/battle_gimmick.c @@ -178,6 +178,13 @@ bool32 IsGimmickTriggerSpriteActive(void) return FALSE; } +bool32 IsGimmickTriggerSpriteMatchingBattler(u32 battler) +{ + if (battler == gSprites[gBattleStruct->gimmick.triggerSpriteId].tBattler) + return TRUE; + return FALSE; +} + void HideGimmickTriggerSprite(void) { if (gBattleStruct->gimmick.triggerSpriteId != 0xFF) diff --git a/src/battle_intro.c b/src/battle_intro.c index a6b46eb7b..226c4e46f 100644 --- a/src/battle_intro.c +++ b/src/battle_intro.c @@ -91,9 +91,9 @@ s32 GetAnimBgAttribute(u8 bgId, u8 attributeId) } #define tState data[0] -#define tTerrain data[1] +#define tEnvironment data[1] -void HandleIntroSlide(u8 terrain) +void HandleIntroSlide(u8 environment) { u8 taskId; @@ -103,16 +103,19 @@ void HandleIntroSlide(u8 terrain) } else if ((gBattleTypeFlags & BATTLE_TYPE_LEGENDARY) && GetMonData(&gEnemyParty[0], MON_DATA_SPECIES, NULL) == SPECIES_KYOGRE) { - terrain = BATTLE_ENVIRONMENT_UNDERWATER; + environment = BATTLE_ENVIRONMENT_UNDERWATER; taskId = CreateTask(BattleIntroSlide2, 0); } else { - taskId = CreateTask(sBattleIntroSlideFuncs[terrain], 0); + if (environment >= NELEMS(sBattleIntroSlideFuncs) + || sBattleIntroSlideFuncs[environment] == NULL) + environment = BATTLE_ENVIRONMENT_PLAIN; + taskId = CreateTask(sBattleIntroSlideFuncs[environment], 0); } gTasks[taskId].tState = 0; - gTasks[taskId].tTerrain = terrain; + gTasks[taskId].tEnvironment = environment; gTasks[taskId].data[2] = 0; gTasks[taskId].data[3] = 0; gTasks[taskId].data[4] = 0; diff --git a/src/battle_message.c b/src/battle_message.c index 9780a1701..7716b617f 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -74,9 +74,9 @@ static const u8 sText_TwoWildPkmnAppeared[] = _("Oh! A wild {B_OPPONENT_MON1_NAM static const u8 sText_Trainer1WantsToBattle[] = _("You are challenged by {B_TRAINER1_CLASS} {B_TRAINER1_NAME}!\p"); static const u8 sText_LinkTrainerWantsToBattle[] = _("You are challenged by {B_LINK_OPPONENT1_NAME}!"); static const u8 sText_TwoLinkTrainersWantToBattle[] = _("You are challenged by {B_LINK_OPPONENT1_NAME} and {B_LINK_OPPONENT2_NAME}!"); -static const u8 sText_Trainer1SentOutPkmn[] = _("{B_TRAINER1_CLASS} {B_TRAINER1_NAME} sent out {B_OPPONENT_MON1_NAME}!"); -static const u8 sText_Trainer1SentOutTwoPkmn[] = _("{B_TRAINER1_CLASS} {B_TRAINER1_NAME} sent out {B_OPPONENT_MON1_NAME} and {B_OPPONENT_MON2_NAME}!"); -static const u8 sText_Trainer1SentOutPkmn2[] = _("{B_TRAINER1_CLASS} {B_TRAINER1_NAME} sent out {B_BUFF1}!"); +static const u8 sText_Trainer1SentOutPkmn[] = _("{B_TRAINER1_NAME_WITH_CLASS} sent out {B_OPPONENT_MON1_NAME}!"); +static const u8 sText_Trainer1SentOutTwoPkmn[] = _("{B_TRAINER1_NAME_WITH_CLASS} sent out {B_OPPONENT_MON1_NAME} and {B_OPPONENT_MON2_NAME}!"); +static const u8 sText_Trainer1SentOutPkmn2[] = _("{B_TRAINER1_NAME_WITH_CLASS} sent out {B_BUFF1}!"); static const u8 sText_LinkTrainerSentOutPkmn[] = _("{B_LINK_OPPONENT1_NAME} sent out {B_OPPONENT_MON1_NAME}!"); static const u8 sText_LinkTrainerSentOutTwoPkmn[] = _("{B_LINK_OPPONENT1_NAME} sent out {B_OPPONENT_MON1_NAME} and {B_OPPONENT_MON2_NAME}!"); static const u8 sText_TwoLinkTrainersSentOutPkmn[] = _("{B_LINK_OPPONENT1_NAME} sent out {B_LINK_OPPONENT_MON1_NAME}! {B_LINK_OPPONENT2_NAME} sent out {B_LINK_OPPONENT_MON2_NAME}!"); @@ -95,7 +95,8 @@ static const u8 sText_PkmnThatsEnough[] = _("{B_BUFF1}, that's enough! Come back static const u8 sText_PkmnComeBack[] = _("{B_BUFF1}, come back!"); static const u8 sText_PkmnOkComeBack[] = _("OK, {B_BUFF1}! Come back!"); static const u8 sText_PkmnGoodComeBack[] = _("Good job, {B_BUFF1}! Come back!"); -static const u8 sText_Trainer1WithdrewPkmn[] = _("{B_TRAINER1_CLASS} {B_TRAINER1_NAME} withdrew {B_BUFF1}!"); +static const u8 sText_Trainer1WithdrewPkmn[] = _("{B_TRAINER1_NAME_WITH_CLASS} withdrew {B_BUFF1}!"); +static const u8 sText_Trainer2WithdrewPkmn[] = _("{B_TRAINER2_NAME_WITH_CLASS} withdrew {B_BUFF1}!"); static const u8 sText_LinkTrainer1WithdrewPkmn[] = _("{B_LINK_OPPONENT1_NAME} withdrew {B_BUFF1}!"); static const u8 sText_LinkTrainer2WithdrewPkmn[] = _("{B_LINK_SCR_TRAINER_NAME} withdrew {B_BUFF1}!"); static const u8 sText_WildPkmnPrefix[] = _("The wild "); @@ -215,10 +216,14 @@ const u8 gText_Mind[] = _("Mind"); const u8 gText_Skill[] = _("Skill"); const u8 gText_Body[] = _("Body"); const u8 gText_Judgment[] = _("{B_BUFF1}{CLEAR 13}Judgment{CLEAR 13}{B_BUFF2}"); -static const u8 sText_TwoTrainersSentPkmn[] = _("{B_TRAINER1_CLASS} {B_TRAINER1_NAME} sent\nout {B_OPPONENT_MON1_NAME}!\p{B_TRAINER2_CLASS} {B_TRAINER2_NAME} sent\nout {B_OPPONENT_MON2_NAME}!"); -static const u8 sText_Trainer2SentOutPkmn[] = _("{B_TRAINER2_CLASS} {B_TRAINER2_NAME} sent\nout {B_BUFF1}!"); -static const u8 sText_TwoTrainersWantToBattle[] = _("{B_TRAINER1_CLASS} {B_TRAINER1_NAME} and\n{B_TRAINER2_CLASS} {B_TRAINER2_NAME}\lwant to battle!\p"); -static const u8 sText_InGamePartnerSentOutZGoN[] = _("{B_PARTNER_CLASS} {B_PARTNER_NAME} sent\nout {B_PLAYER_MON2_NAME}!\lGo, {B_PLAYER_MON1_NAME}!"); + +static const u8 sText_TwoTrainersSentPkmn[] = _("{B_TRAINER1_NAME_WITH_CLASS} sent out {B_OPPONENT_MON1_NAME}!\p{B_TRAINER2_NAME_WITH_CLASS} sent out {B_OPPONENT_MON2_NAME}!"); +static const u8 sText_Trainer2SentOutPkmn[] = _("{B_TRAINER2_NAME_WITH_CLASS} sent out {B_BUFF1}!"); +static const u8 sText_TwoTrainersWantToBattle[] = _("You are challenged by {B_TRAINER1_NAME_WITH_CLASS} and {B_TRAINER2_NAME_WITH_CLASS}!\p"); +static const u8 sText_InGamePartnerSentOutZGoN[] = _("{B_PARTNER_NAME_WITH_CLASS} sent out {B_PLAYER_MON2_NAME}! Go, {B_PLAYER_MON1_NAME}!"); +static const u8 sText_InGamePartnerSentOutPkmn2[] = _("{B_PARTNER_NAME_WITH_CLASS} sent out {B_PLAYER_MON2_NAME}!"); +static const u8 sText_InGamePartnerWithdrewPkmn2[] = _("{B_PARTNER_NAME_WITH_CLASS} withdrew {B_PLAYER_MON2_NAME}!"); + static const u8 sText_TwoInGameTrainersDefeated[] = _("{B_TRAINER1_CLASS} {B_TRAINER1_NAME} and\n{B_TRAINER2_CLASS} {B_TRAINER2_NAME}\lwere defeated!\p"); static const u8 sText_Trainer2LoseText[] = _("{B_TRAINER2_LOSE_TEXT}"); static const u8 sText_PkmnIncapableOfPower[] = _("{B_ATK_NAME_WITH_PREFIX} appears incapable\nof using its power!"); @@ -1768,7 +1773,9 @@ void BufferStringBattle(enum StringID stringID, u32 battler) case STRINGID_RETURNMON: // sending poke to ball msg if (IsOnPlayerSide(battler)) { - if (*(&gBattleStruct->hpScale) == 0) + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && GetBattlerPosition(battler) == B_POSITION_PLAYER_RIGHT) + stringPtr = sText_InGamePartnerWithdrewPkmn2; + else if (*(&gBattleStruct->hpScale) == 0) stringPtr = sText_PkmnThatsEnough; else if (*(&gBattleStruct->hpScale) == 1 || IsDoubleBattle()) stringPtr = sText_PkmnComeBack; @@ -1788,14 +1795,27 @@ void BufferStringBattle(enum StringID stringID, u32 battler) } else { - stringPtr = sText_Trainer1WithdrewPkmn; + if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + { + if (GetBattlerPosition(battler) == B_POSITION_OPPONENT_LEFT) + stringPtr = sText_Trainer1WithdrewPkmn; + else + stringPtr = sText_Trainer2WithdrewPkmn; + + } + else + { + stringPtr = sText_Trainer1WithdrewPkmn; + } } } break; case STRINGID_SWITCHINMON: // switch-in msg if (IsOnPlayerSide(gBattleScripting.battler)) { - if (*(&gBattleStruct->hpScale) == 0 || IsDoubleBattle()) + if ((gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) && (GetBattlerAtPosition(gBattleScripting.battler) == 2)) + stringPtr = sText_InGamePartnerSentOutPkmn2; + else if (*(&gBattleStruct->hpScale) == 0 || IsDoubleBattle()) stringPtr = sText_GoPkmn2; else if (*(&gBattleStruct->hpScale) == 1) stringPtr = sText_DoItPkmn; @@ -1817,12 +1837,39 @@ void BufferStringBattle(enum StringID stringID, u32 battler) } else { - if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + if (TESTING && gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + if (gBattleScripting.battler == 1) + { + stringPtr = sText_Trainer1SentOutPkmn; + } + else + { + if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + stringPtr = sText_Trainer2SentOutPkmn; + else + stringPtr = sText_Trainer1SentOutPkmn2; + } + } + else if (TESTING && gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + { + if (gBattleScripting.battler == 1) + stringPtr = sText_Trainer1SentOutPkmn; + else + stringPtr = sText_Trainer2SentOutPkmn; + } + else if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { stringPtr = sText_LinkTrainerMultiSentOutPkmn; + } else if (TRAINER_BATTLE_PARAM.opponentA == TRAINER_UNION_ROOM) + { stringPtr = sText_Trainer1SentOutPkmn2; + } else + { stringPtr = sText_LinkTrainerSentOutPkmn2; + } } } else diff --git a/src/data/battle_partners.h b/src/data/battle_partners.h index a38068864..35a9a2c4c 100644 --- a/src/data/battle_partners.h +++ b/src/data/battle_partners.h @@ -29,7 +29,7 @@ #line 10 .trainerName = _("STEVEN"), #line 11 - .trainerClass = TRAINER_CLASS_RIVAL_LATE, + .trainerClass = TRAINER_CLASS_PKMN_TRAINER_1, #line 12 .trainerPic = TRAINER_PIC_RS_BRENDAN_1, .encounterMusic_gender = diff --git a/src/data/battle_partners.party b/src/data/battle_partners.party index bcf818dca..bd3f2135a 100644 --- a/src/data/battle_partners.party +++ b/src/data/battle_partners.party @@ -8,7 +8,7 @@ Back Pic: Ruby Sapphire Brendan === PARTNER_STEVEN === Name: STEVEN -Class: Rival Late +Class: Pkmn Trainer 1 Pic: RS Brendan 1 Gender: Male Music: Male diff --git a/src/data/pokemon/form_change_tables.h b/src/data/pokemon/form_change_tables.h index ed80ae217..54584c579 100644 --- a/src/data/pokemon/form_change_tables.h +++ b/src/data/pokemon/form_change_tables.h @@ -73,6 +73,15 @@ static const struct FormChange sPikachuFormChangeTable[] = }; #endif //P_FAMILY_PIKACHU +#if P_FAMILY_CLEFAIRY +static const struct FormChange sClefableFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_CLEFABLE_MEGA, ITEM_CLEFABLITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_CLEFAIRY + #if P_FAMILY_MEOWTH static const struct FormChange sMeowthFormChangeTable[] = { @@ -102,6 +111,15 @@ static const struct FormChange sMachampFormChangeTable[] = }; #endif //P_FAMILY_MACHOP +#if P_FAMILY_BELLSPROUT +static const struct FormChange sVictreebelFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_VICTREEBEL_MEGA, ITEM_VICTREEBELITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_BELLSPROUT + #if P_FAMILY_SLOWPOKE static const struct FormChange sSlowbroFormChangeTable[] = { #if P_MEGA_EVOLUTIONS @@ -153,6 +171,15 @@ static const struct FormChange sKangaskhanFormChangeTable[] = { }; #endif //P_FAMILY_KANGASKHAN +#if P_FAMILY_STARYU +static const struct FormChange sStarmieFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_STARMIE_MEGA, ITEM_STARMINITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_STARYU + #if P_FAMILY_SCYTHER #if P_GEN_2_CROSS_EVOS static const struct FormChange sScizorFormChangeTable[] = { @@ -218,6 +245,15 @@ static const struct FormChange sSnorlaxFormChangeTable[] = { }; #endif //P_FAMILY_SNORLAX +#if P_FAMILY_DRATINI +static const struct FormChange sDragoniteFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_DRAGONITE_MEGA, ITEM_DRAGONINITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_DRATINI + #if P_FAMILY_MEWTWO static const struct FormChange sMewtwoFormChangeTable[] = { #if P_MEGA_EVOLUTIONS @@ -228,6 +264,24 @@ static const struct FormChange sMewtwoFormChangeTable[] = { }; #endif //P_FAMILY_MEWTWO +#if P_FAMILY_CHIKORITA +static const struct FormChange sMeganiumFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_MEGANIUM_MEGA, ITEM_MEGANIUMITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_CHIKORITA + +#if P_FAMILY_TOTODILE +static const struct FormChange sFeraligatrFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_FERALIGATR_MEGA, ITEM_FERALIGITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_TOTODILE + #if P_FAMILY_MAREEP static const struct FormChange sAmpharosFormChangeTable[] = { #if P_MEGA_EVOLUTIONS @@ -246,6 +300,15 @@ static const struct FormChange sHeracrossFormChangeTable[] = { }; #endif //P_FAMILY_HERACROSS +#if P_FAMILY_SKARMORY +static const struct FormChange sSkarmoryFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_SKARMORY_MEGA, ITEM_SKARMORITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_SKARMORY + #if P_FAMILY_HOUNDOUR static const struct FormChange sHoundoomFormChangeTable[] = { #if P_MEGA_EVOLUTIONS @@ -406,6 +469,13 @@ static const struct FormChange sGlalieFormChangeTable[] = { #endif {FORM_CHANGE_TERMINATOR}, }; + +static const struct FormChange sFroslassFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_FROSLASS_MEGA, ITEM_FROSLASSITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; #endif //P_FAMILY_SNORUNT #if P_FAMILY_CASTFORM @@ -690,6 +760,24 @@ static const struct FormChange sArceusFormChangeTable[] = { }; #endif //P_FAMILY_ARCEUS +#if P_FAMILY_TEPIG +static const struct FormChange sEmboarFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_EMBOAR_MEGA, ITEM_EMBOARITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_TEPIG + +#if P_FAMILY_DRILBUR +static const struct FormChange sExcadrillFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_EXCADRILL_MEGA, ITEM_EXCADRITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_DRILBUR + #if P_FAMILY_AUDINO static const struct FormChange sAudinoFormChangeTable[] = { #if P_MEGA_EVOLUTIONS @@ -699,6 +787,15 @@ static const struct FormChange sAudinoFormChangeTable[] = { }; #endif //P_FAMILY_AUDINO +#if P_FAMILY_VENIPEDE +static const struct FormChange sScolipedeFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_SCOLIPEDE_MEGA, ITEM_SCOLIPITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_VENIPEDE + #if P_FAMILY_DARUMAKA static const struct FormChange sDarmanitanFormChangeTable[] = { {FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_DARMANITAN_STANDARD, ABILITY_ZEN_MODE, HP_HIGHER_THAN, 50}, @@ -719,6 +816,15 @@ static const struct FormChange sDarmanitanGalarFormChangeTable[] = { #endif //P_GALARIAN_FORMS #endif //P_FAMILY_DARUMAKA +#if P_FAMILY_SCRAGGY +static const struct FormChange sScraftyFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_SCRAFTY_MEGA, ITEM_SCRAFTINITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_SCRAGGY + #if P_FAMILY_TRUBBISH static const struct FormChange sGarbodorFormChangeTable[] = { @@ -729,6 +835,24 @@ static const struct FormChange sGarbodorFormChangeTable[] = }; #endif //P_FAMILY_TRUBBISH +#if P_FAMILY_TYNAMO +static const struct FormChange sEelektrossFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_EELEKTROSS_MEGA, ITEM_EELEKTROSSITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_TYNAMO + +#if P_FAMILY_LITWICK +static const struct FormChange sChandelureFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_CHANDELURE_MEGA, ITEM_CHANDELURITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_LITWICK + #if P_FAMILY_TORNADUS static const struct FormChange sTornadusFormChangeTable[] = { {FORM_CHANGE_ITEM_USE, SPECIES_TORNADUS_THERIAN, ITEM_REVEAL_GLASS}, @@ -755,8 +879,8 @@ static const struct FormChange sLandorusFormChangeTable[] = { #if P_FAMILY_KYUREM static const struct Fusion sKyuremFusionTable[] = { - {0, ITEM_DNA_SPLICERS, SPECIES_KYUREM, SPECIES_RESHIRAM, SPECIES_KYUREM_WHITE}, - {0, ITEM_DNA_SPLICERS, SPECIES_KYUREM, SPECIES_ZEKROM, SPECIES_KYUREM_BLACK}, + {0, ITEM_DNA_SPLICERS, SPECIES_KYUREM, SPECIES_RESHIRAM, SPECIES_KYUREM_WHITE, MOVE_NONE, SWAP_EXTRA_MOVES_KYUREM_WHITE}, + {0, ITEM_DNA_SPLICERS, SPECIES_KYUREM, SPECIES_ZEKROM, SPECIES_KYUREM_BLACK, MOVE_NONE, SWAP_EXTRA_MOVES_KYUREM_BLACK}, {FUSION_TERMINATOR}, }; #endif //P_FAMILY_KYUREM @@ -790,7 +914,32 @@ static const struct FormChange sGenesectFormChangeTable[] = { }; #endif //P_FAMILY_GENESECT +#if P_FAMILY_CHESPIN +static const struct FormChange sChesnaughtFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_CHESNAUGHT_MEGA, ITEM_CHESNAUGHTITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_CHESPIN + +#if P_FAMILY_FENNEKIN +static const struct FormChange sDelphoxFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_DELPHOX_MEGA, ITEM_DELPHOXITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_FENNEKIN + #if P_FAMILY_FROAKIE +static const struct FormChange sGreninjaFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_GRENINJA_MEGA, ITEM_GRENINJITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; + static const struct FormChange sGreninjaBattleBondFormChangeTable[] = { {FORM_CHANGE_FAINT, SPECIES_GRENINJA_BATTLE_BOND}, {FORM_CHANGE_END_BATTLE, SPECIES_GRENINJA_BATTLE_BOND}, @@ -798,6 +947,24 @@ static const struct FormChange sGreninjaBattleBondFormChangeTable[] = { }; #endif //P_FAMILY_FROAKIE +#if P_FAMILY_LITLEO +static const struct FormChange sPyroarFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_PYROAR_MEGA, ITEM_PYROARITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_LITLEO + +#if P_FAMILY_FLABEBE +static const struct FormChange sFloetteEternalFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_FLOETTE_MEGA, ITEM_FLOETTITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_FLABEBE + #if P_FAMILY_FURFROU static const struct FormChange sFurfrouFormChangeTable[] = { {FORM_CHANGE_WITHDRAW, SPECIES_FURFROU_NATURAL}, @@ -818,6 +985,42 @@ static const struct FormChange sAegislashFormChangeTable[] = { }; #endif //P_FAMILY_HONEDGE +#if P_FAMILY_INKAY +static const struct FormChange sMalamarFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_MALAMAR_MEGA, ITEM_MALAMARITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_INKAY + +#if P_FAMILY_BINACLE +static const struct FormChange sBarbaracleFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_BARBARACLE_MEGA, ITEM_BARBARACITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_BINACLE + +#if P_FAMILY_SKRELP +static const struct FormChange sDragalgeFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_DRAGALGE_MEGA, ITEM_DRAGALGITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_SKRELP + +#if P_FAMILY_HAWLUCHA +static const struct FormChange sHawluchaFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_HAWLUCHA_MEGA, ITEM_HAWLUCHANITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_HAWLUCHA + #if P_FAMILY_XERNEAS static const struct FormChange sXerneasFormChangeTable[] = { {FORM_CHANGE_BEGIN_BATTLE, SPECIES_XERNEAS_ACTIVE}, @@ -856,6 +1059,9 @@ static const struct FormChange sZygarde10PowerConstructFormChangeTable[] = { static const struct FormChange sZygardeCompleteFormChangeTable[] = { {FORM_CHANGE_FAINT}, {FORM_CHANGE_END_BATTLE}, +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_ZYGARDE_MEGA, ITEM_ZYGARDITE}, +#endif {FORM_CHANGE_TERMINATOR}, }; #endif //P_FAMILY_ZYGARDE @@ -925,6 +1131,7 @@ static const struct FormChange sSilvallyFormChangeTable[] = { #if P_FAMILY_MINIOR static const struct FormChange sMiniorRedFormChangeTable[] = { + {FORM_CHANGE_BEGIN_BATTLE, SPECIES_MINIOR_CORE_RED}, {FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_METEOR_RED, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50}, {FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_CORE_RED, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50}, {FORM_CHANGE_BATTLE_SWITCH, SPECIES_MINIOR_CORE_RED}, @@ -933,6 +1140,7 @@ static const struct FormChange sMiniorRedFormChangeTable[] = { {FORM_CHANGE_TERMINATOR}, }; static const struct FormChange sMiniorBlueFormChangeTable[] = { + {FORM_CHANGE_BEGIN_BATTLE, SPECIES_MINIOR_CORE_BLUE}, {FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_METEOR_BLUE, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50}, {FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_CORE_BLUE, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50}, {FORM_CHANGE_BATTLE_SWITCH, SPECIES_MINIOR_CORE_BLUE}, @@ -941,6 +1149,7 @@ static const struct FormChange sMiniorBlueFormChangeTable[] = { {FORM_CHANGE_TERMINATOR}, }; static const struct FormChange sMiniorGreenFormChangeTable[] = { + {FORM_CHANGE_BEGIN_BATTLE, SPECIES_MINIOR_CORE_GREEN}, {FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_METEOR_GREEN, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50}, {FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_CORE_GREEN, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50}, {FORM_CHANGE_BATTLE_SWITCH, SPECIES_MINIOR_CORE_GREEN}, @@ -949,6 +1158,7 @@ static const struct FormChange sMiniorGreenFormChangeTable[] = { {FORM_CHANGE_TERMINATOR}, }; static const struct FormChange sMiniorIndigoFormChangeTable[] = { + {FORM_CHANGE_BEGIN_BATTLE, SPECIES_MINIOR_CORE_INDIGO}, {FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_METEOR_INDIGO, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50}, {FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_CORE_INDIGO, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50}, {FORM_CHANGE_BATTLE_SWITCH, SPECIES_MINIOR_CORE_INDIGO}, @@ -957,6 +1167,7 @@ static const struct FormChange sMiniorIndigoFormChangeTable[] = { {FORM_CHANGE_TERMINATOR}, }; static const struct FormChange sMiniorOrangeFormChangeTable[] = { + {FORM_CHANGE_BEGIN_BATTLE, SPECIES_MINIOR_CORE_ORANGE}, {FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_METEOR_ORANGE, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50}, {FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_CORE_ORANGE, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50}, {FORM_CHANGE_BATTLE_SWITCH, SPECIES_MINIOR_CORE_ORANGE}, @@ -965,6 +1176,7 @@ static const struct FormChange sMiniorOrangeFormChangeTable[] = { {FORM_CHANGE_TERMINATOR}, }; static const struct FormChange sMiniorVioletFormChangeTable[] = { + {FORM_CHANGE_BEGIN_BATTLE, SPECIES_MINIOR_CORE_VIOLET}, {FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_METEOR_VIOLET, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50}, {FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_CORE_VIOLET, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50}, {FORM_CHANGE_BATTLE_SWITCH, SPECIES_MINIOR_CORE_VIOLET}, @@ -973,6 +1185,7 @@ static const struct FormChange sMiniorVioletFormChangeTable[] = { {FORM_CHANGE_TERMINATOR}, }; static const struct FormChange sMiniorYellowFormChangeTable[] = { + {FORM_CHANGE_BEGIN_BATTLE, SPECIES_MINIOR_CORE_YELLOW}, {FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_METEOR_YELLOW, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50}, {FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_MINIOR_CORE_YELLOW, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50}, {FORM_CHANGE_BATTLE_SWITCH, SPECIES_MINIOR_CORE_YELLOW}, @@ -996,10 +1209,19 @@ static const struct FormChange sMimikyuTotemFormChangeTable[] = { }; #endif //P_FAMILY_MIMIKYU +#if P_FAMILY_DRAMPA +static const struct FormChange sDrampaFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_DRAMPA_MEGA, ITEM_DRAMPANITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_DRAMPA + #if P_FAMILY_NECROZMA static const struct Fusion sNecrozmaFusionTable[] = { - {1, ITEM_N_SOLARIZER, SPECIES_NECROZMA, SPECIES_SOLGALEO, SPECIES_NECROZMA_DUSK_MANE, MOVE_SUNSTEEL_STRIKE, MOVE_CONFUSION}, - {2, ITEM_N_LUNARIZER, SPECIES_NECROZMA, SPECIES_LUNALA, SPECIES_NECROZMA_DAWN_WINGS, MOVE_MOONGEIST_BEAM, MOVE_CONFUSION}, + {1, ITEM_N_SOLARIZER, SPECIES_NECROZMA, SPECIES_SOLGALEO, SPECIES_NECROZMA_DUSK_MANE, MOVE_SUNSTEEL_STRIKE, FORGET_EXTRA_MOVES}, + {2, ITEM_N_LUNARIZER, SPECIES_NECROZMA, SPECIES_LUNALA, SPECIES_NECROZMA_DAWN_WINGS, MOVE_MOONGEIST_BEAM, FORGET_EXTRA_MOVES}, {FUSION_TERMINATOR}, }; @@ -1195,8 +1417,18 @@ static const struct FormChange sAlcremieFormChangeTable[] = }; #endif //P_FAMILY_MILCERY +#if P_FAMILY_FALINKS +static const struct FormChange sFalinksFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_FALINKS_MEGA, ITEM_FALINKSITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_FALINKS + #if P_FAMILY_EISCUE static const struct FormChange sEiscueFormChangeTable[] = { + {FORM_CHANGE_BATTLE_WEATHER, SPECIES_EISCUE_ICE, B_WEATHER_HAIL | B_WEATHER_SNOW, ABILITY_ICE_FACE}, {FORM_CHANGE_FAINT, SPECIES_EISCUE_ICE}, {FORM_CHANGE_END_BATTLE, SPECIES_EISCUE_ICE}, {FORM_CHANGE_TERMINATOR}, @@ -1266,8 +1498,8 @@ static const struct FormChange sUrshifuRapidStrikeFormChangeTable[] = { #if P_FAMILY_CALYREX static const struct Fusion sCalyrexFusionTable[] = { - {3, ITEM_REINS_OF_UNITY, SPECIES_CALYREX, SPECIES_GLASTRIER, SPECIES_CALYREX_ICE, MOVE_GLACIAL_LANCE, MOVE_CONFUSION}, - {3, ITEM_REINS_OF_UNITY, SPECIES_CALYREX, SPECIES_SPECTRIER, SPECIES_CALYREX_SHADOW, MOVE_ASTRAL_BARRAGE, MOVE_CONFUSION}, + {3, ITEM_REINS_OF_UNITY, SPECIES_CALYREX, SPECIES_GLASTRIER, SPECIES_CALYREX_ICE, MOVE_GLACIAL_LANCE, FORGET_EXTRA_MOVES}, + {3, ITEM_REINS_OF_UNITY, SPECIES_CALYREX, SPECIES_SPECTRIER, SPECIES_CALYREX_SHADOW, MOVE_ASTRAL_BARRAGE, FORGET_EXTRA_MOVES}, {FUSION_TERMINATOR}, }; #endif //P_FAMILY_CALYREX diff --git a/src/data/pokemon/form_species_tables.h b/src/data/pokemon/form_species_tables.h index 53ee47f93..ab703bc2d 100644 --- a/src/data/pokemon/form_species_tables.h +++ b/src/data/pokemon/form_species_tables.h @@ -150,6 +150,16 @@ static const u16 sSandslashFormSpeciesIdTable[] = { }; #endif //P_FAMILY_SANDSHREW +#if P_FAMILY_CLEFAIRY +static const u16 sClefableFormSpeciesIdTable[] = { + SPECIES_CLEFABLE, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_CLEFABLE_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_CLEFAIRY + #if P_FAMILY_VULPIX static const u16 sVulpixFormSpeciesIdTable[] = { SPECIES_VULPIX, @@ -248,6 +258,16 @@ static const u16 sMachampFormSpeciesIdTable[] = { }; #endif //P_FAMILY_MACHOP +#if P_FAMILY_BELLSPROUT +static const u16 sVictreebelFormSpeciesIdTable[] = { + SPECIES_VICTREEBEL, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_VICTREEBEL_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_BELLSPROUT + #if P_FAMILY_GEODUDE static const u16 sGeodudeFormSpeciesIdTable[] = { SPECIES_GEODUDE, @@ -445,6 +465,16 @@ static const u16 sKangaskhanFormSpeciesIdTable[] = { }; #endif //P_FAMILY_KANGASKHAN +#if P_FAMILY_STARYU +static const u16 sStarmieFormSpeciesIdTable[] = { + SPECIES_STARMIE, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_STARMIE_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_STARYU + #if P_FAMILY_MR_MIME static const u16 sMrMimeFormSpeciesIdTable[] = { SPECIES_MR_MIME, @@ -570,6 +600,16 @@ static const u16 sMoltresFormSpeciesIdTable[] = { }; #endif //P_FAMILY_MOLTRES +#if P_FAMILY_DRATINI +static const u16 sDragoniteFormSpeciesIdTable[] = { + SPECIES_DRAGONITE, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_DRAGONITE_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_DRATINI + #if P_FAMILY_MEWTWO static const u16 sMewtwoFormSpeciesIdTable[] = { SPECIES_MEWTWO, @@ -581,6 +621,16 @@ static const u16 sMewtwoFormSpeciesIdTable[] = { }; #endif //P_FAMILY_MEWTWO +#if P_FAMILY_CHIKORITA +static const u16 sMeganiumFormSpeciesIdTable[] = { + SPECIES_MEGANIUM, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_MEGANIUM_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_CHIKORITA + #if P_FAMILY_CYNDAQUIL static const u16 sTyphlosionFormSpeciesIdTable[] = { SPECIES_TYPHLOSION, @@ -591,6 +641,16 @@ static const u16 sTyphlosionFormSpeciesIdTable[] = { }; #endif //P_FAMILY_CYNDAQUIL +#if P_FAMILY_TOTODILE +static const u16 sFeraligatrFormSpeciesIdTable[] = { + SPECIES_FERALIGATR, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_FERALIGATR_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_TOTODILE + #if P_FAMILY_MAREEP static const u16 sAmpharosFormSpeciesIdTable[] = { SPECIES_AMPHAROS, @@ -701,6 +761,16 @@ static const u16 sCorsolaFormSpeciesIdTable[] = { }; #endif //P_FAMILY_CORSOLA +#if P_FAMILY_SKARMORY +static const u16 sSkarmoryFormSpeciesIdTable[] = { + SPECIES_SKARMORY, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_SKARMORY_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_SKARMORY + #if P_FAMILY_HOUNDOUR static const u16 sHoundoomFormSpeciesIdTable[] = { SPECIES_HOUNDOOM, @@ -907,6 +977,14 @@ static const u16 sGlalieFormSpeciesIdTable[] = { #endif FORM_SPECIES_END, }; + +static const u16 sFroslassFormSpeciesIdTable[] = { + SPECIES_FROSLASS, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_FROSLASS_MEGA, +#endif + FORM_SPECIES_END, +}; #endif //P_FAMILY_SNORUNT #if P_FAMILY_BAGON @@ -1142,6 +1220,16 @@ static const u16 sArceusFormSpeciesIdTable[] = { }; #endif //P_FAMILY_ARCEUS +#if P_FAMILY_TEPIG +static const u16 sEmboarFormSpeciesIdTable[] = { + SPECIES_EMBOAR, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_EMBOAR_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_TEPIG + #if P_FAMILY_OSHAWOTT static const u16 sSamurottFormSpeciesIdTable[] = { SPECIES_SAMUROTT, @@ -1152,6 +1240,16 @@ static const u16 sSamurottFormSpeciesIdTable[] = { }; #endif //P_FAMILY_OSHAWOTT +#if P_FAMILY_DRILBUR +static const u16 sExcadrillFormSpeciesIdTable[] = { + SPECIES_EXCADRILL, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_EXCADRILL_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_DRILBUR + #if P_FAMILY_AUDINO static const u16 sAudinoFormSpeciesIdTable[] = { SPECIES_AUDINO, @@ -1162,6 +1260,16 @@ static const u16 sAudinoFormSpeciesIdTable[] = { }; #endif //P_FAMILY_AUDINO +#if P_FAMILY_VENIPEDE +static const u16 sScolipedeFormSpeciesIdTable[] = { + SPECIES_SCOLIPEDE, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_SCOLIPEDE_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_VENIPEDE + #if P_FAMILY_PETILIL static const u16 sLilligantFormSpeciesIdTable[] = { SPECIES_LILLIGANT, @@ -1207,6 +1315,16 @@ static const u16 sDarmanitanFormSpeciesIdTable[] = { }; #endif //P_FAMILY_DARUMAKA +#if P_FAMILY_SCRAGGY +static const u16 sScraftyFormSpeciesIdTable[] = { + SPECIES_SCRAFTY, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_SCRAFTY_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_SCRAGGY + #if P_FAMILY_YAMASK static const u16 sYamaskFormSpeciesIdTable[] = { SPECIES_YAMASK, @@ -1263,6 +1381,26 @@ static const u16 sSawsbuckFormSpeciesIdTable[] = { }; #endif //P_FAMILY_DEERLING +#if P_FAMILY_TYNAMO +static const u16 sEelektrossFormSpeciesIdTable[] = { + SPECIES_EELEKTROSS, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_EELEKTROSS_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_TYNAMO + +#if P_FAMILY_LITWICK +static const u16 sChandelureFormSpeciesIdTable[] = { + SPECIES_CHANDELURE, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_CHANDELURE_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_LITWICK + #if P_FAMILY_STUNFISK static const u16 sStunfiskFormSpeciesIdTable[] = { SPECIES_STUNFISK, @@ -1343,11 +1481,34 @@ static const u16 sGenesectFormSpeciesIdTable[] = { }; #endif //P_FAMILY_GENESECT +#if P_FAMILY_CHESPIN +static const u16 sChesnaughtFormSpeciesIdTable[] = { + SPECIES_CHESNAUGHT, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_CHESNAUGHT_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_CHESPIN + +#if P_FAMILY_FENNEKIN +static const u16 sDelphoxFormSpeciesIdTable[] = { + SPECIES_DELPHOX, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_DELPHOX_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_FENNEKIN + #if P_FAMILY_FROAKIE static const u16 sGreninjaFormSpeciesIdTable[] = { SPECIES_GRENINJA, SPECIES_GRENINJA_BATTLE_BOND, SPECIES_GRENINJA_ASH, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_GRENINJA_MEGA, +#endif FORM_SPECIES_END, }; #endif //P_FAMILY_FROAKIE @@ -1426,6 +1587,16 @@ static const u16 sVivillonFormSpeciesIdTable[] = { }; #endif //P_FAMILY_SCATTERBUG +#if P_FAMILY_LITLEO +static const u16 sPyroarFormSpeciesIdTable[] = { + SPECIES_PYROAR, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_PYROAR_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_LITLEO + #if P_FAMILY_FLABEBE static const u16 sFlabebeFormSpeciesIdTable[] = { SPECIES_FLABEBE_RED, @@ -1443,6 +1614,9 @@ static const u16 sFloetteFormSpeciesIdTable[] = { SPECIES_FLOETTE_BLUE, SPECIES_FLOETTE_WHITE, SPECIES_FLOETTE_ETERNAL, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_FLOETTE_MEGA, +#endif FORM_SPECIES_END, }; @@ -1488,6 +1662,46 @@ static const u16 sAegislashFormSpeciesIdTable[] = { }; #endif //P_FAMILY_HONEDGE +#if P_FAMILY_INKAY +static const u16 sMalamarFormSpeciesIdTable[] = { + SPECIES_MALAMAR, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_MALAMAR_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_INKAY + +#if P_FAMILY_BINACLE +static const u16 sBarbaracleFormSpeciesIdTable[] = { + SPECIES_BARBARACLE, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_BARBARACLE_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_BINACLE + +#if P_FAMILY_SKRELP +static const u16 sDragalgeFormSpeciesIdTable[] = { + SPECIES_DRAGALGE, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_DRAGALGE_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_SKRELP + +#if P_FAMILY_HAWLUCHA +static const u16 sHawluchaFormSpeciesIdTable[] = { + SPECIES_HAWLUCHA, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_HAWLUCHA_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_HAWLUCHA + #if P_FAMILY_GOOMY static const u16 sSliggooFormSpeciesIdTable[] = { SPECIES_SLIGGOO, @@ -1549,6 +1763,9 @@ static const u16 sZygardeFormSpeciesIdTable[] = { SPECIES_ZYGARDE_10_POWER_CONSTRUCT, SPECIES_ZYGARDE_50_POWER_CONSTRUCT, SPECIES_ZYGARDE_COMPLETE, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_ZYGARDE_MEGA, +#endif FORM_SPECIES_END, }; #endif //P_FAMILY_ZYGARDE @@ -1724,6 +1941,16 @@ static const u16 sMimikyuFormSpeciesIdTable[] = { }; #endif //P_FAMILY_MIMIKYU +#if P_FAMILY_DRAMPA +static const u16 sDrampaFormSpeciesIdTable[] = { + SPECIES_DRAMPA, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_DRAMPA_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_DRAMPA + #if P_FAMILY_JANGMO_O static const u16 sKommoOFormSpeciesIdTable[] = { SPECIES_KOMMO_O, @@ -1999,6 +2226,16 @@ static const u16 sAlcremieFormSpeciesIdTable[] = { }; #endif //P_FAMILY_MILCERY +#if P_FAMILY_FALINKS +static const u16 sFalinksFormSpeciesIdTable[] = { + SPECIES_FALINKS, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_FALINKS_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_FALINKS + #if P_FAMILY_EISCUE static const u16 sEiscueFormSpeciesIdTable[] = { SPECIES_EISCUE_ICE, From a15c857e5badea8480ad6755fe79dfc417592b81 Mon Sep 17 00:00:00 2001 From: cawtds <38510667+cawtds@users.noreply.github.com> Date: Sat, 15 Nov 2025 02:38:41 +0100 Subject: [PATCH 4/6] add new megaevolutions --- graphics/pokemon/bombirdier/back.png | Bin 638 -> 567 bytes graphics/pokemon/bombirdier/front.png | Bin 877 -> 780 bytes graphics/pokemon/bombirdier/normal.pal | 26 +- graphics/pokemon/bombirdier/shiny.pal | 24 +- graphics/pokemon/clodsire/front.png | Bin 698 -> 0 bytes graphics/pokemon/dipplin/back.png | Bin 538 -> 531 bytes graphics/pokemon/dipplin/front.png | Bin 550 -> 520 bytes graphics/pokemon/dipplin/normal.pal | 24 +- graphics/pokemon/dipplin/shiny.pal | 24 +- graphics/pokemon/duraludon/front.png | Bin 891 -> 0 bytes graphics/pokemon/enamorus/front.png | Bin 832 -> 0 bytes graphics/pokemon/frigibax/anim_front.png | Bin 919 -> 0 bytes graphics/pokemon/frigibax/back.png | Bin 475 -> 418 bytes graphics/pokemon/frigibax/front.png | Bin 0 -> 540 bytes graphics/pokemon/frigibax/normal.pal | 32 +- graphics/pokemon/frigibax/shiny.pal | 32 +- .../pokemon/furfrou/dandy_trim/anim_front.png | Bin 1208 -> 0 bytes graphics/pokemon/furfrou/dandy_trim/back.png | Bin 710 -> 0 bytes graphics/pokemon/furfrou/dandy_trim/icon.png | Bin 533 -> 0 bytes .../pokemon/furfrou/dandy_trim/normal.pal | 19 - .../pokemon/furfrou/dandy_trim/overworld.png | Bin 849 -> 0 bytes .../furfrou/dandy_trim/overworld_normal.pal | 19 - .../furfrou/dandy_trim/overworld_shiny.pal | 19 - graphics/pokemon/furfrou/dandy_trim/shiny.pal | 19 - .../furfrou/debutante_trim/anim_front.png | Bin 1269 -> 0 bytes .../pokemon/furfrou/debutante_trim/back.png | Bin 710 -> 0 bytes .../pokemon/furfrou/debutante_trim/icon.png | Bin 530 -> 0 bytes .../pokemon/furfrou/debutante_trim/normal.pal | 19 - .../furfrou/debutante_trim/overworld.png | Bin 941 -> 0 bytes .../debutante_trim/overworld_normal.pal | 19 - .../debutante_trim/overworld_shiny.pal | 19 - .../pokemon/furfrou/debutante_trim/shiny.pal | 19 - .../furfrou/diamond_trim/anim_front.png | Bin 1246 -> 0 bytes .../pokemon/furfrou/diamond_trim/back.png | Bin 657 -> 0 bytes .../pokemon/furfrou/diamond_trim/icon.png | Bin 558 -> 0 bytes .../pokemon/furfrou/diamond_trim/normal.pal | 19 - .../furfrou/diamond_trim/overworld.png | Bin 909 -> 0 bytes .../furfrou/diamond_trim/overworld_normal.pal | 19 - .../furfrou/diamond_trim/overworld_shiny.pal | 19 - .../pokemon/furfrou/diamond_trim/shiny.pal | 19 - .../pokemon/furfrou/heart_trim/anim_front.png | Bin 1340 -> 0 bytes graphics/pokemon/furfrou/heart_trim/back.png | Bin 610 -> 0 bytes graphics/pokemon/furfrou/heart_trim/icon.png | Bin 537 -> 0 bytes .../pokemon/furfrou/heart_trim/normal.pal | 19 - .../pokemon/furfrou/heart_trim/overworld.png | Bin 908 -> 0 bytes .../furfrou/heart_trim/overworld_normal.pal | 19 - .../furfrou/heart_trim/overworld_shiny.pal | 19 - graphics/pokemon/furfrou/heart_trim/shiny.pal | 19 - .../furfrou/kabuki_trim/anim_front.png | Bin 1315 -> 0 bytes graphics/pokemon/furfrou/kabuki_trim/back.png | Bin 635 -> 0 bytes graphics/pokemon/furfrou/kabuki_trim/icon.png | Bin 509 -> 0 bytes .../pokemon/furfrou/kabuki_trim/normal.pal | 19 - .../pokemon/furfrou/kabuki_trim/overworld.png | Bin 932 -> 0 bytes .../furfrou/kabuki_trim/overworld_normal.pal | 19 - .../furfrou/kabuki_trim/overworld_shiny.pal | 19 - .../pokemon/furfrou/kabuki_trim/shiny.pal | 19 - .../furfrou/la_reine_trim/anim_front.png | Bin 1181 -> 0 bytes .../pokemon/furfrou/la_reine_trim/back.png | Bin 630 -> 0 bytes .../pokemon/furfrou/la_reine_trim/icon.png | Bin 516 -> 0 bytes .../pokemon/furfrou/la_reine_trim/normal.pal | 19 - .../furfrou/la_reine_trim/overworld.png | Bin 908 -> 0 bytes .../la_reine_trim/overworld_normal.pal | 19 - .../furfrou/la_reine_trim/overworld_shiny.pal | 19 - .../pokemon/furfrou/la_reine_trim/shiny.pal | 19 - .../furfrou/matron_trim/anim_front.png | Bin 1187 -> 0 bytes graphics/pokemon/furfrou/matron_trim/back.png | Bin 732 -> 0 bytes graphics/pokemon/furfrou/matron_trim/icon.png | Bin 517 -> 0 bytes .../pokemon/furfrou/matron_trim/normal.pal | 19 - .../pokemon/furfrou/matron_trim/overworld.png | Bin 930 -> 0 bytes .../furfrou/matron_trim/overworld_normal.pal | 19 - .../furfrou/matron_trim/overworld_shiny.pal | 19 - .../pokemon/furfrou/matron_trim/shiny.pal | 19 - .../furfrou/pharaoh_trim/anim_front.png | Bin 1249 -> 0 bytes .../pokemon/furfrou/pharaoh_trim/back.png | Bin 724 -> 0 bytes .../pokemon/furfrou/pharaoh_trim/icon.png | Bin 515 -> 0 bytes .../pokemon/furfrou/pharaoh_trim/normal.pal | 19 - .../furfrou/pharaoh_trim/overworld.png | Bin 938 -> 0 bytes .../furfrou/pharaoh_trim/overworld_normal.pal | 19 - .../furfrou/pharaoh_trim/overworld_shiny.pal | 19 - .../pokemon/furfrou/pharaoh_trim/shiny.pal | 19 - .../pokemon/furfrou/star_trim/anim_front.png | Bin 1188 -> 0 bytes graphics/pokemon/furfrou/star_trim/back.png | Bin 683 -> 0 bytes graphics/pokemon/furfrou/star_trim/icon.png | Bin 574 -> 0 bytes graphics/pokemon/furfrou/star_trim/normal.pal | 19 - .../pokemon/furfrou/star_trim/overworld.png | Bin 946 -> 0 bytes .../furfrou/star_trim/overworld_normal.pal | 19 - .../furfrou/star_trim/overworld_shiny.pal | 19 - graphics/pokemon/furfrou/star_trim/shiny.pal | 19 - graphics/pokemon/great_tusk/anim_front.png | Bin 1930 -> 0 bytes graphics/pokemon/great_tusk/back.png | Bin 781 -> 890 bytes graphics/pokemon/great_tusk/front.png | Bin 0 -> 1087 bytes graphics/pokemon/great_tusk/normal.pal | 30 +- graphics/pokemon/great_tusk/shiny.pal | 30 +- graphics/pokemon/greninja/ash/overworld.png | Bin 0 -> 1092 bytes .../pokemon/greninja/ash/overworld_normal.pal | 19 + .../pokemon/greninja/ash/overworld_shiny.pal | 19 + graphics/pokemon/hydrapple/back.png | Bin 829 -> 907 bytes graphics/pokemon/hydrapple/front.png | Bin 1159 -> 980 bytes graphics/pokemon/hydrapple/normal.pal | 30 +- graphics/pokemon/hydrapple/shiny.pal | 30 +- graphics/pokemon/kecleon/overworld_shiny.pal | 2 +- graphics/pokemon/kingler/overworld.png | Bin 914 -> 1046 bytes graphics/pokemon/koraidon/back.png | Bin 1276 -> 1241 bytes graphics/pokemon/koraidon/front.png | Bin 1223 -> 1276 bytes graphics/pokemon/koraidon/normal.pal | 32 +- graphics/pokemon/koraidon/shiny.pal | 32 +- graphics/pokemon/krabby/overworld.png | Bin 728 -> 567 bytes graphics/pokemon/lurantis/anim_front.png | Bin 0 -> 1334 bytes graphics/pokemon/lurantis/front.png | Bin 790 -> 0 bytes graphics/pokemon/miraidon/back.png | Bin 847 -> 1007 bytes graphics/pokemon/miraidon/front.png | Bin 1075 -> 1224 bytes graphics/pokemon/miraidon/normal.pal | 32 +- graphics/pokemon/miraidon/shiny.pal | 32 +- graphics/pokemon/nickit/front.png | Bin 647 -> 4711 bytes graphics/pokemon/nickit/normal.pal | 8 +- graphics/pokemon/nickit/overworld.png | Bin 671 -> 600 bytes graphics/pokemon/nickit/overworld_normal.pal | 26 +- graphics/pokemon/nickit/overworld_shiny.pal | 30 +- graphics/pokemon/ogerpon/back.png | Bin 515 -> 699 bytes graphics/pokemon/ogerpon/cornerstone/back.png | Bin 540 -> 682 bytes .../pokemon/ogerpon/cornerstone/front.png | Bin 947 -> 915 bytes .../pokemon/ogerpon/cornerstone/normal.pal | 30 +- .../pokemon/ogerpon/cornerstone/shiny.pal | 30 +- graphics/pokemon/ogerpon/front.png | Bin 1007 -> 958 bytes graphics/pokemon/ogerpon/hearthflame/back.png | Bin 534 -> 746 bytes .../pokemon/ogerpon/hearthflame/front.png | Bin 947 -> 904 bytes .../pokemon/ogerpon/hearthflame/normal.pal | 28 +- .../pokemon/ogerpon/hearthflame/shiny.pal | 28 +- graphics/pokemon/ogerpon/normal.pal | 30 +- graphics/pokemon/ogerpon/shiny.pal | 30 +- graphics/pokemon/ogerpon/wellspring/back.png | Bin 534 -> 728 bytes graphics/pokemon/ogerpon/wellspring/front.png | Bin 909 -> 862 bytes .../pokemon/ogerpon/wellspring/normal.pal | 30 +- graphics/pokemon/ogerpon/wellspring/shiny.pal | 30 +- graphics/pokemon/oinkologne/back.png | Bin 495 -> 489 bytes graphics/pokemon/oinkologne/f/back.png | Bin 613 -> 490 bytes graphics/pokemon/oinkologne/f/front.png | Bin 771 -> 719 bytes graphics/pokemon/oinkologne/f/normal.pal | 31 +- graphics/pokemon/oinkologne/f/shiny.pal | 31 +- graphics/pokemon/oinkologne/front.png | Bin 602 -> 649 bytes graphics/pokemon/oinkologne/normal.pal | 30 +- graphics/pokemon/oinkologne/shiny.pal | 30 +- graphics/pokemon/pichu/spiky_eared/front.png | Bin 481 -> 0 bytes graphics/pokemon/pikachu/starter/icon.png | Bin 405 -> 388 bytes graphics/pokemon/terapagos/anim_front.png | Bin 1284 -> 0 bytes graphics/pokemon/terapagos/back.png | Bin 611 -> 533 bytes graphics/pokemon/terapagos/front.png | Bin 0 -> 995 bytes graphics/pokemon/terapagos/normal.pal | 30 +- graphics/pokemon/terapagos/shiny.pal | 30 +- .../pokemon/terapagos/terastal/anim_front.png | Bin 5458 -> 0 bytes graphics/pokemon/terapagos/terastal/back.png | Bin 4904 -> 1168 bytes graphics/pokemon/terapagos/terastal/front.png | Bin 0 -> 1216 bytes .../pokemon/terapagos/terastal/normal.pal | 30 +- graphics/pokemon/terapagos/terastal/shiny.pal | 30 +- graphics/pokemon/thievul/back.png | Bin 669 -> 599 bytes graphics/pokemon/thievul/front.png | Bin 828 -> 772 bytes graphics/pokemon/thievul/normal.pal | 16 +- graphics/pokemon/thievul/overworld.png | Bin 940 -> 796 bytes graphics/pokemon/thievul/overworld_normal.pal | 26 +- graphics/pokemon/thievul/overworld_shiny.pal | 30 +- graphics/pokemon/thievul/shiny.pal | 8 +- include/config/pokemon.h | 3 +- include/config/species_enabled.h | 2 + include/constants/species.h | 31 +- src/data/graphics/pokemon.h | 7246 ++++++++--------- .../object_event_pic_tables_followers.h | 202 +- src/data/pokemon/egg_moves.h | 7 + .../pokemon/species_info/gen_1_families.h | 555 +- .../pokemon/species_info/gen_2_families.h | 356 +- .../pokemon/species_info/gen_3_families.h | 165 +- .../pokemon/species_info/gen_4_families.h | 2 +- .../pokemon/species_info/gen_5_families.h | 487 +- .../pokemon/species_info/gen_6_families.h | 786 +- .../pokemon/species_info/gen_7_families.h | 88 +- .../pokemon/species_info/gen_8_families.h | 301 +- .../pokemon/species_info/gen_9_families.h | 73 +- 176 files changed, 6954 insertions(+), 5106 deletions(-) delete mode 100755 graphics/pokemon/clodsire/front.png delete mode 100644 graphics/pokemon/duraludon/front.png delete mode 100755 graphics/pokemon/enamorus/front.png delete mode 100644 graphics/pokemon/frigibax/anim_front.png create mode 100644 graphics/pokemon/frigibax/front.png delete mode 100644 graphics/pokemon/furfrou/dandy_trim/anim_front.png delete mode 100644 graphics/pokemon/furfrou/dandy_trim/back.png delete mode 100644 graphics/pokemon/furfrou/dandy_trim/icon.png delete mode 100644 graphics/pokemon/furfrou/dandy_trim/normal.pal delete mode 100644 graphics/pokemon/furfrou/dandy_trim/overworld.png delete mode 100644 graphics/pokemon/furfrou/dandy_trim/overworld_normal.pal delete mode 100644 graphics/pokemon/furfrou/dandy_trim/overworld_shiny.pal delete mode 100644 graphics/pokemon/furfrou/dandy_trim/shiny.pal delete mode 100644 graphics/pokemon/furfrou/debutante_trim/anim_front.png delete mode 100644 graphics/pokemon/furfrou/debutante_trim/back.png delete mode 100644 graphics/pokemon/furfrou/debutante_trim/icon.png delete mode 100644 graphics/pokemon/furfrou/debutante_trim/normal.pal delete mode 100644 graphics/pokemon/furfrou/debutante_trim/overworld.png delete mode 100644 graphics/pokemon/furfrou/debutante_trim/overworld_normal.pal delete mode 100644 graphics/pokemon/furfrou/debutante_trim/overworld_shiny.pal delete mode 100644 graphics/pokemon/furfrou/debutante_trim/shiny.pal delete mode 100644 graphics/pokemon/furfrou/diamond_trim/anim_front.png delete mode 100644 graphics/pokemon/furfrou/diamond_trim/back.png delete mode 100644 graphics/pokemon/furfrou/diamond_trim/icon.png delete mode 100644 graphics/pokemon/furfrou/diamond_trim/normal.pal delete mode 100644 graphics/pokemon/furfrou/diamond_trim/overworld.png delete mode 100644 graphics/pokemon/furfrou/diamond_trim/overworld_normal.pal delete mode 100644 graphics/pokemon/furfrou/diamond_trim/overworld_shiny.pal delete mode 100644 graphics/pokemon/furfrou/diamond_trim/shiny.pal delete mode 100644 graphics/pokemon/furfrou/heart_trim/anim_front.png delete mode 100644 graphics/pokemon/furfrou/heart_trim/back.png delete mode 100644 graphics/pokemon/furfrou/heart_trim/icon.png delete mode 100644 graphics/pokemon/furfrou/heart_trim/normal.pal delete mode 100644 graphics/pokemon/furfrou/heart_trim/overworld.png delete mode 100644 graphics/pokemon/furfrou/heart_trim/overworld_normal.pal delete mode 100644 graphics/pokemon/furfrou/heart_trim/overworld_shiny.pal delete mode 100644 graphics/pokemon/furfrou/heart_trim/shiny.pal delete mode 100644 graphics/pokemon/furfrou/kabuki_trim/anim_front.png delete mode 100644 graphics/pokemon/furfrou/kabuki_trim/back.png delete mode 100644 graphics/pokemon/furfrou/kabuki_trim/icon.png delete mode 100644 graphics/pokemon/furfrou/kabuki_trim/normal.pal delete mode 100644 graphics/pokemon/furfrou/kabuki_trim/overworld.png delete mode 100644 graphics/pokemon/furfrou/kabuki_trim/overworld_normal.pal delete mode 100644 graphics/pokemon/furfrou/kabuki_trim/overworld_shiny.pal delete mode 100644 graphics/pokemon/furfrou/kabuki_trim/shiny.pal delete mode 100644 graphics/pokemon/furfrou/la_reine_trim/anim_front.png delete mode 100644 graphics/pokemon/furfrou/la_reine_trim/back.png delete mode 100644 graphics/pokemon/furfrou/la_reine_trim/icon.png delete mode 100644 graphics/pokemon/furfrou/la_reine_trim/normal.pal delete mode 100644 graphics/pokemon/furfrou/la_reine_trim/overworld.png delete mode 100644 graphics/pokemon/furfrou/la_reine_trim/overworld_normal.pal delete mode 100644 graphics/pokemon/furfrou/la_reine_trim/overworld_shiny.pal delete mode 100644 graphics/pokemon/furfrou/la_reine_trim/shiny.pal delete mode 100644 graphics/pokemon/furfrou/matron_trim/anim_front.png delete mode 100644 graphics/pokemon/furfrou/matron_trim/back.png delete mode 100644 graphics/pokemon/furfrou/matron_trim/icon.png delete mode 100644 graphics/pokemon/furfrou/matron_trim/normal.pal delete mode 100644 graphics/pokemon/furfrou/matron_trim/overworld.png delete mode 100644 graphics/pokemon/furfrou/matron_trim/overworld_normal.pal delete mode 100644 graphics/pokemon/furfrou/matron_trim/overworld_shiny.pal delete mode 100644 graphics/pokemon/furfrou/matron_trim/shiny.pal delete mode 100644 graphics/pokemon/furfrou/pharaoh_trim/anim_front.png delete mode 100644 graphics/pokemon/furfrou/pharaoh_trim/back.png delete mode 100644 graphics/pokemon/furfrou/pharaoh_trim/icon.png delete mode 100644 graphics/pokemon/furfrou/pharaoh_trim/normal.pal delete mode 100644 graphics/pokemon/furfrou/pharaoh_trim/overworld.png delete mode 100644 graphics/pokemon/furfrou/pharaoh_trim/overworld_normal.pal delete mode 100644 graphics/pokemon/furfrou/pharaoh_trim/overworld_shiny.pal delete mode 100644 graphics/pokemon/furfrou/pharaoh_trim/shiny.pal delete mode 100644 graphics/pokemon/furfrou/star_trim/anim_front.png delete mode 100644 graphics/pokemon/furfrou/star_trim/back.png delete mode 100644 graphics/pokemon/furfrou/star_trim/icon.png delete mode 100644 graphics/pokemon/furfrou/star_trim/normal.pal delete mode 100644 graphics/pokemon/furfrou/star_trim/overworld.png delete mode 100644 graphics/pokemon/furfrou/star_trim/overworld_normal.pal delete mode 100644 graphics/pokemon/furfrou/star_trim/overworld_shiny.pal delete mode 100644 graphics/pokemon/furfrou/star_trim/shiny.pal delete mode 100644 graphics/pokemon/great_tusk/anim_front.png create mode 100644 graphics/pokemon/great_tusk/front.png create mode 100644 graphics/pokemon/greninja/ash/overworld.png create mode 100644 graphics/pokemon/greninja/ash/overworld_normal.pal create mode 100644 graphics/pokemon/greninja/ash/overworld_shiny.pal create mode 100644 graphics/pokemon/lurantis/anim_front.png delete mode 100644 graphics/pokemon/lurantis/front.png delete mode 100644 graphics/pokemon/pichu/spiky_eared/front.png delete mode 100644 graphics/pokemon/terapagos/anim_front.png create mode 100644 graphics/pokemon/terapagos/front.png delete mode 100644 graphics/pokemon/terapagos/terastal/anim_front.png create mode 100644 graphics/pokemon/terapagos/terastal/front.png diff --git a/graphics/pokemon/bombirdier/back.png b/graphics/pokemon/bombirdier/back.png index eb45117013530504a8dab426d3bc1d746db2b869..d2f321a35be0e0549e55e9c058b22f1adcd9d42b 100644 GIT binary patch delta 542 zcmV+(0^$As1h)i`B!2;OQb$4nuFf3k0000mP)t-snbV~-DKJz~QA#;NW?NvoP-J;{ zcfGi}lYND>rK%7R5aHL_=G@-^000000000032jpu0005CNkl~B@*f`yfQNhtj||{kZGW&pF($}{MB6|C;0Jg$ zC@qdY1q;Xkit42<16V8f6YuyZmwF7TVWN<&3*TkHvaKi(TvtX{UR)WBX%7`daRxD+b2B3uH*Qn*+aX`)*o635F$BOkv;Ap+S6=!%2YEqXhp*4M^0n zVQ6zw|0r6AE`QUG4AgK#X+3J3&T^e9?cQIta6kZ!<1?9o~ zehSlqkEPJ}Re6&__ys9EZsYe;m~W#Brc=mGm`x!IW`9$7AV}{qARgan<26_tQ-DW4 zMhBxQ5Kf@1VC+#4DthIk^D}~yKn#AQ2{tfP_?TWQ0|IPW8nsgIRpmwn^gY2NbUN|LYxa gK9Gl>m>0hgKR%)=qHIw7N&o-=07*qoM6N<$f^=&1NdN!< delta 613 zcmV-r0-F7|1pWk&B!4haOjJdg(xfygFiJT>4-XF}(xGNsV7aQV@8jW)~De@28n5a2f=F8>@6kN5cD!}%2^GbW&O7CCO|13=Cb zkOY;$**S+3$7$>WKzTAE5CpXZIy-ZPn0L#vM1b-EpbM!Bw1H5;ruafwDv$uL3dprd zK$nMvc!&cKD}QVn5Gs_DfS6CfNd=s(>j%pM2{@^MZl2rqJHRUyP%7ZC%wJUyw=j(Z z@c>G|Z~oZB=~193KnL{uAZ&x5j52?*hYslSm%vmX!!Cadh|Aac1JIwSynGw~1(XVh z(6=82l7M3V2H-#};J3?*kT;+z|!ey zfo%wYc=UL=`U?%}0;dlXpWpngQ4lazV1i~HBNrG2m`K1r3V2z7eIElRlgAgr5Wv4r z!%wX=fnL~m7QpY7Al(GcR(U>3z)2roD?!The=}F-F&xJ|j{WY?{(sL8jx|tFQieC`00000NkvXXu0mjf=^-A| diff --git a/graphics/pokemon/bombirdier/front.png b/graphics/pokemon/bombirdier/front.png index b8aa83644ba1f142ff37e0e980d17ef7b4ef173b..618c5c7c9b66ce98cb5420f3d29cd7240a8bf87b 100644 GIT binary patch delta 737 zcmV<70v`SC28;%fH-FQmG$}Ap9VJRRLS|cFb!l#yK1t?GVv~J^w56&L5D?+l+WGhR z000000000000`d~h5!Hpib+I4R9JA9 z3nIGP_D>Nsp8YGs*WbP*ZWsV2z6F#7M#bW5GZh=mB8s z?R@P7xLd#xTE`H=r4`_|15O575Yi{$nO@7l3PFiVkiD&XnoWVJiAI1zmH?KAMKl6e z3qm;b4#38Icqnz4iGjx{bOd6M@z)Fx!gL!?2phfPOH`CVFvgOlMD@R0M|p>0Gay&R zJw8`n0is_8SOzhzIp_vd&vNfv1xVRr*j5eLURu_V6Ck??N;zGPJM00000NkvXXu0mjf1+hFv delta 835 zcmV-J1HAl<2JHrrH-FNkG$}AjIYJK)4<^!~W?Nvns;}?k;gfxZP#q;rN=xQUV*mU9 znLbIUtEYQ{doJbV^Z)q$gGR9J<*mVwTzAPj|trU)wf{%?Cv3o1Gk_Aj|zwz!S+ zd0JZHF#P{8=10B#4PfjufO-HgdSly!{r=TDbO4~2MW((~e}8=~km${UsRE2`=ygrK z4$5r5sl->MgbLzJf<4zK0Y*p5=LA77kX#TU8q+v0me6gIb2i&YGv@p0?`9t+{^v5 z1vSBDVEzOcmwy0M*@6NfVL+i$KNk9@8eRZn1>iJ`w<4SXRsf#>?=(!V!g~>R0203e z#KfDvumDC;hQonY!5E^Zg*}VAKJTM74}{W!X2Ev@c_X@#kZ^Q&AY=5H!JXiIYD#-L zFizU&*}*WlQ}4aE-eavTEVT3kksz$x-h0Lygli7wEq{ZAAR4VdLI5%g2#>#74ss<< z087!7pkF&2DBvKlT*!HszxT)!phyA$=Y${$bm~3Y=mg-jcgaHY{%AgC5`6)X=E)9P zdOmuT|N9$15SAqy!3s#6g~1!lNhEjgn4=ZObDp~7TN_N2%iCv z8;V3x0Dn~nahzzGq=M4H%d!fBcLQnxgc&ws6%gl0B2Pzw7+{tU093C*6lRGEAmZns z^XOOsax8(s-my6WLsSQIRUc`eI@)VWgdI!19dHZqD_XOYEHFLr}ja9N30k5cj9bG1 z6F4dg5`!23000+sMObuGZ)S9NVRB^vM@&RePDdbiWpW@hE;Mn4q~QPn00?w&PDe*f zL^A*Y002sWDIWj;00d`2O+f$vv5yPP{gc2H@u->b~C% z6$6d;AO9Wz8lUdCu**LVs5)PuYji()bms#ipoU>I>F(FK0v6a0Ba=5r70j?kY$0!) ze=nVBeVr>+eCq&{>o4fn(x>BFLoO@c)tJgsYCNal+d3t=R)y$+LgamSLR(I(sL_27 zv?|JOTGSrw1oIW4!z!t%ga)_vJrF9nKP?CR$=DIxo gLqx1d{}iB!2;OQb$4nuFf3k0000mP)t-s0JraeK>(mND=T3RxLp9&j{*PF z7GJ9!|8_#fs8Ij#W(C{F4cO)l;eQ(e;o}=I9f1X5ZjS$= zhdBenJH|LG`1UZ}!&?Lw-v=TRkgg6vK-qx0hh5tD`+-R|R07(ieF3Bx)gffQe=Sd^8k-@ec!%VCON)t04<$j5o$hA-2HyP=4bVEn|!b zywUQ$3%0nKC6};1UzxVT+H|r)cz;l3-Az-l+IU`=Dln5dM{5d2+s&ur>-#c{Mb85cXw&wm=P~ z0BD$&=TrPGfO8J6;EIdJqkvtY3n9EHGR`+rq~_zi8zA9bDn9dG4=zPA?GFQ!mSOM8 vLgkY>;YkX$pekvmji)~^IyGGQGM>~ArEDHztGHd&00000NkvXXu0mjfT|?hW delta 512 zcmV+b0{{J!1eyepB!4PUOjJbxx9=-q4y4#h5D*Yws~z#lP{yfK{{H^LPy^kM0RPk$ z`J|$`O)>v=LLb+pbpQYW4s=pZQ~&?}|NsC0|NsC0|NsAJ!ZSqx00EInL_t(oh3%Ee zlEWYjL?bsZSFh_uSMH^=U-x{WCcnRR*c_1P&($yx2Q5K-CAwc{7-*~4dQ~(Olz5pU` z)h1+re@7xt5TQNNxiTAvC#M<#ECm1;0Om4)=njyp>H-|oX%3(fbRE-+?rn(@ zK*IqlfVxtGUVndXI`WPj3y>G00*oC@WPqV7{zxbQ;}-)GAowxrS3(BRn4j5-5KHj( zq5N!D6*CLKvdY>nv%`(oEb-br;x@v$^kawk?cpl5aTBn+_}n3O(GbBKT?9E;dq+qw zwx0&U19k+?0mzJE+#;0p>6E0Xz} zIECs!PeUE}0osGG)eidgWe}DI7@0=#T>&|dO*3*>HgRI0>bn?F zf?_B}LX-?K!e$9Grg?r#QL$*L7$;r@Acz8(Z@0Gqu~5YZNGoFp^ynw7iP8a(6i{Sh zprZ|t^7qzD4$(7or-ab=8w0e%KTOdgTD@Jli;(znlxJlIR4Sj|?VzTsTr&BBsr#3U z9UPn70@=c`6hQG1(nsHJ(=nhOVM77WTBA}uS;TrH94o1F1DM3IFt0_XpKw_1UnCOuT(nYxE)CLVm)holuaA$;O5f`90ue&KrowA@?)E%7Sg zs{ZB*G=Xa#{D%r|P9Waz!E^%c4rvw8#DzlZN>+gabiIxey2ebzdYC{>13=SH0<;B` zCIN{Pp#`>@0r18vreL+za1#SzUqS*cgK+@rj!W<0xV{a7C4iWj#>BP`whEb$>a^$Wls?Xdz-Rc?6M5Ef86h79xIv>bF|nV}Kxa+qU|S5Xt@oeyCeL z&J<7qB(*=}Y=;|QTB*fa*nUF*IW1tuLrPzSu)7G{jE7V(Mp77~1pR}E5)p2rL+pj2VgE5M}>S)0hGf%U_%E zSdZxSL_=#u=i@jH5MaW~r7&_BE!r9C5Trlc1cMyc!1UiVp4<5oGw}t@yA`@taO)%h P00001BCpEP)Px#Fi=cXMV!*4Vuh?RU5jcoIS>#Kdx4bh;(LRAVvB*Kw6@I%BvSwX|7u}#y=iI~ zIAY%7_E%R?fB*mj`AI}UR9J;M1ub|srQA)&?5Ovxm$4|y#K z`t@}dx7+RX{BQ9iKR5jlkUs%10oy(xFafhq07$?_Q&3U8DUV|*sEMVFW41AZnkC%a zHkvR1fHWfWpfU{D0+6o~dOckn1#GlYvt9;-K5xl{0K`=QQ+NG00NBnELT3K|h5@$u z`oFal837;#s9;~2p|=qicw4yd`VoM;pt;DBY!JX!%93ocL4rsU&wm+C0eS*R7y~c} z7$kfS*cyN)T(2e6Vg>j%q{}II4f?O_S(2R)had&)t```0j0E#y2Wb(xQ`7FK?XlsbTK zg0z(2q<_930MQ-?XynZ5wY?6YM_Bf~U^?kY0OAg?5P%R%@UNR{Apmm36Jeca*WV8|j}?&TCjuDIEywgma;xUYb5hY~xxepUd000PPVt0E$SKH?56x;b1b9to3FK4>@RB=UO4+By89?_tuv4Vg zjm!5@ahk#%kW)p3TJEpDXMj$hYrlH5a}nEnz^WbpspAiTbR?i(^$y4nfbLnph5E&F ziru_>+-!JEAXNZoZh8jX=gA)OxPr8%>LUJ*Z}4H5bn5N`_ZMqS4oK`*O|OelS{yeB zIaWYsZ@mG$2@tr(2A~Vq{*h82i>1A`qT}UK0$iF82%m?C75@WZT002ovPDHLkV1mD@k-q={ diff --git a/graphics/pokemon/enamorus/front.png b/graphics/pokemon/enamorus/front.png deleted file mode 100755 index c679b07e571f202cbeaeaf1bbe6459f76043c961..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 832 zcmV-G1Hb%|4&Df3j1yFOn3#XRriumAu6js1y)00009 za7bBm001r{001r{0eGc9b^rhX2XskIMF-~w2Ld+%F@^|F0007`NkldL*U_>EQ3R0|y(1{_k%9H_J8MB?@i7Kc~=PraUg@BNb zP7RaYq3W3b(BIHIKrL$C4VC(2Ig#F%_b%u29YX&z49C8^Y4Sb|)GgErOdV|Fz>y3t zAQN*zU?aS!12!_kXX;A@1SYi~DDX%NLVL~+L*K?4fNHiWhZ!JOGX_-iP=w5iK^8Q? zB#xXV!zJ38su9-@TvF9fwHwlqILL|{FzEOl>MtUz#r9#4>?XTDt+W_BfJ-F(q<==s zOvV66TaDx-IXP9J>p;M~7ApKT#!5X9}k z?copxKkH{-#Z^4mIEFi*!hq7H>!YpSG5jP9KL3{FaqA6Vg$q=9FOHoed(SI6;IJ+) zvcrOAJy~2mCC2u3>#21RAC~yTZHMi{VvRX*9KTatjzF;97qN25>qWHX0>m0xd+Mx%T(*qp%cZXVx&_2$kPZt+4i zQ{K;4MXDKtDJJPa~+rEC-H!dSVcf@0|Gw%6CnUFz6S`IolBSAD-n7g zu!$1?UW?h?R)V`EC9;JMgg1ad!1PoLBCE^#WFbN`b5$dEp#bq_kG9|7He^3%2Ds{{ zw|Sqg{9VGVkw{*|Q_Lj=bLQkSBX!kCmB_3-R5S}unkf3G6aN?Q4&fcC{~EIZ0000< KMNUMnLSTZXz;guv diff --git a/graphics/pokemon/frigibax/anim_front.png b/graphics/pokemon/frigibax/anim_front.png deleted file mode 100644 index cfdaf7de70cc062c0a609aec2bc85f01d6d5d0b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 919 zcmV;I18Dq-P)F>ljA6o4I187$GeTvJ!7MDJ=*15*|Mfin*&DlCyu_ae1>7Xq6dg>pg_ zRlDUMRPM%v>V-;-gtp zs}(?F!(%P&CTguzwGv3(K(e;c0sv=^K6oVOyJw4C#C&l4q&q=YzE;1($lgmFh8Ury@j;IDALFYz(WLV zBOE|K#T4)D9wq(M=J22_&wB7l(?D<$rA2W9Pe+`Qk9Bax4~wEuE2EqShM5VG$ioq1 z`AVwL7zC(J2bm}3WdHBZRgZr6@|-j5K+Kt= zQ}sBr4+`eVv#PVMo|$-l;?H9qf2ooE185`*_zqY3A5zswbVUM~3;-4WM}6Y}u;8lj z2*hLnaQYt)a-CEFi^3k|%xQP8DXiYNw!tyz)b0tZ_uU=WW%w@`s<#>A1VJA`{ywTz z@HhJcXdl$`31FN+hyz4dgo*?d-l1ma50K3&k*_W?3p_SE1Q6#)NWE_LztsT6pMWfU?dLqpCFZ_&)CZowp3B!V{D|6s&`aZ;@kG|GKAVw!Ps zj`EoZ$K&BhGI~7lC9at9@LD>?0~D@etLET3cL3JhxVPYAkI{2hU4}Qe0I$*E_MW+! t8l|h%)6H_7R{~y-nXLM#Gjkmf@f#r25z+rM-|PSY002ovPDHLkV1l#}wSoWu diff --git a/graphics/pokemon/frigibax/back.png b/graphics/pokemon/frigibax/back.png index d48c105e34e5da84dbb4303aa481fad587ad69ef..41b741e46d64a70e1ea541022192ee05adfb5b03 100644 GIT binary patch delta 372 zcmV-)0gL|I1EK?vH-FQmJy~j(Vrayg0QSk({MRR3iIb6{t)IBP5D*Zqy3f|%=)>sg z|Ns9!XN4|5T<(@0u>b%8AW1|)R9J=WmD`HLFbqVamyu11_5XjniZ6-D#g!dcD0m5Kt?=mNv95j_Rn8Q zZtIci^axy@k9U`E`hn4qfx-_9_MlU6<`0p^zYxGEAiNc{c*7FfyrDu71d%)5BG4(t zLkLoXRsjM0k%(&r;G5pfE z|Fh=*kK1;bly&wn>Hq)%SxH1eR9J=W)!UAPFbo7xY_ec(|Npx?vAKqXCRAE!rHs__ z(m8SxpiNU#Q&aPoAtL4%J+>B6+dAi{lwfLo%hy{KT$#XDvwyk)MFLyx(k~H${sv?V z)^9oN7XrZoaG2yIukW;Gm%T3nAs2AIrk8DelCFc0wFcfg?iBR9j`K!fcMmBbc>qNK z`9WPULIw~Uzys2YF!2XLEK$IR`~G1cMNi5n6vzY23Q)REdv1UV*n^=@38>@wXVRAk zi<^)$;05%DA%6h~Um}y`=tB_ShY$l2{R@E6P{${-i$VVYrZb=eyaG-GAQ>xQ86SYy zeGqQJXfa?rStQjDg$+QCJ43%x{XmETE0eyDC8z)REQ)*y>;zW(uHUQ=v;SqZo&(%F z#}Rx3ti<>UNcUA30q8cp0wDOlzHpPmBS13R1}iYnb0;Qne$VND+e`rFWm#fEP0hc} YFJTuF-Wwe}NdN!<07*qoM6N<$f;Ec5d;kCd diff --git a/graphics/pokemon/frigibax/front.png b/graphics/pokemon/frigibax/front.png new file mode 100644 index 0000000000000000000000000000000000000000..a4e3378b4812f845ababd4e51e0cd4e5ca0db946 GIT binary patch literal 540 zcmV+%0^|LOP)Px#Fi=cXMVZs3K0;TSc>~0n0OP?d{MRRHbBd9ot){QN5D*Zqy3f|%=)>sg|Ns9! zXN4|5T;m&H0{{R4nn^@KR9J=WmCKI9APhxgk~lV`|Npz=YePF-jA~M8R`CLQg6SZa}5p!#D!9dc4nT5r8xnLma{6zr)H`=24I%^=__o480 zQb4@!YTc{GLS+V>O#r+N0{p)6q`*4R1&!8+uKNYS8hoQ&RUzPn!Hx}mBOvcK`56$V zAy}h?j6fs?MlLeCwu*WB6g~^c5+|@~3kg-*zWQZwJ|U3tXNt2|YeiM@D`v7n~LbKKaaTD%+;W0lsOXnO&gO5nx2;5bGvIh6ovfAZo67Zkuy%v@&^9G(JkDavY1 zgdwfKrE-Inj=_#9(n&a>Zcr1%IhZLz*^fRHm~0p1D}cd6k-!$ZnI2Mn1DtUI&(t3? zF6L41#-BUU-`nc%$x`fKV@!qm%V?5pMK-^baP?JXbBsb}TSe0-pnc~^Wx e-*LwsAL9qpxfGeyC2Ya~0000?F(Fb;l07aJi}GB?HRj&yxDPZa$rz@ zsxGOkyS^a!H?Jf~u8wyAAbI-}0MaXj1|YoxsOA9)Ux*H-_@tyaL}!Q(j}z7SfMJ>> zF+ivu#<^>pg)!$m=|R|VHxTpwlJl?!qkA{N`SSBU5$V>QL(!L#W(ncO4X}RmG`T4_ zA7*YKxKni{ZZL%VEilBY+V2F0h$BykRrP+iy9V5~fBgL?0^AL-ylOxE)glnOf%jiq zy2^3v0hp*X077`)0udqh058Mcg#mOpug-y$T9`oe>m{H*n!w{6;Pj=tN~x_0H1#zg z=Fxii3aos@tl?lkL+N3x>C^N)vr8IzGTC2^wH6N%lD+#EL@qo?M2JrRf zkbT2c?XqCC0(iHOHDvqOFMct_FF5y7%F+V}S!$pzqdlC}#TlW2y6i>Y+(5v3Fh+_; zr4NX4a|6T$0?r-E!h(RJC}8Z|UyMf+T5leC_7|=fE&~)l0W$n6@aIS(J^^9m1aNC9 z0)isqf;qD643vCaLxj7OM>L%cNCL2u@NqUUD+=qdAz)0vK+OhrLEu7SCDM~PI&ExV zE~K34{W3*B+CbG#kARp;A*`ZgZM&~$LLgAJf@l+{s(minc7_oI{_m}_#@jkfex!w& z!!b;Lq^-|z3gf>2Kf18Jzr6}z#iv&tMW0~T2n~4s0kU0iF-FN;e3I95kuN|BJjSv{u`ui6Hn8|Aff+zWm zzY2zJAO@ff!~{OUrGZ?W)_A%{>w`a>Cb$ehzy>Z1eZwSb+v%3WYmqVanWL|&J z{T#bL_W|(>;1&$64;lzDgs_t!eW<(W59k*p7*+_<2LhC!ryc%4`hWoX0}VR-f%Ku) z{(ytI!yiZ=YOM!T0&IUEAvgf254r6RS|4)l52z0gf6)36Xn(-Y&m8_h`tV=%hkpPl W=J%gk#N^Qc0000~}AeA@(3rA@W z({IPYj`IUcr~ZZEJ^TM}|Cn0sUq;ivxs2O%P>t(=DIL!$m-ncMVU-}4Lrf|JKf`oP zaA9!fxX`#eb6n_ajtY*dPjKR6f(!V8WZ_`~F#;26ks&m@R|LFDgLlwA^%foe;zQVi zuQ`7gE!&2pIp+&u*oh*|`Ku7@Ze@;G@?-=zKeh$P(Rq`c?-T+2!L^W?ceUvt!LxZpO zmaw2YCZxrd{Iigw(Kogy0VB)hz97h%l~^o?Yg>PVKb(>qA<|0t2zh1scNd+A0GC&lHZ# zKJDl%xF8&DECpFeL}1`b%ca0zCKDzFghL5(W|Ip-Hj{rOAkPpq!Q(g<0^Dtg3eWQ6 z6bFS1*$dFA7StOeg;Dp4fV2^LYG@!6+UIO8@`>07*qoM6N<$g2S63UH||9 diff --git a/graphics/pokemon/furfrou/dandy_trim/icon.png b/graphics/pokemon/furfrou/dandy_trim/icon.png deleted file mode 100644 index a54f4fa4a4a9bd87d3a769af4cc48d60a2d03135..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 533 zcmV+w0_y#VP) zb924Dz5oCJdz?y~%}SK^O73%<_LTO$q+0goDfafP)zxa|N-1JuT0ucUX*qpc00009 za7bBm001r{001r{0eGc9b^rhX2XskIMF-~w2Ll5Yk+enf0004aNklPJ45tbpBGU~GqUUP=ogC5DgbGRI*{wxfeI?FG_#wN(`|@g;;cFPn5=i$~PiZ<` zlRE9M;tSJsUJ6JD0am|(X)z$Z!)PcLwhPT7=?k7HEikCCU}{oYIKctcY+!Moc?||? z){>J98}tSXEJ>7M<)9{{$G1J7s|ZBC@zVsNz3Li&J`+}_O5o&>6-G@pA;}^ps0y|@ zHQSWI7&M6SrGrG1+f^~+{}0?wA>*7X6>0&uhD@$jD>?fc?D**44-$_}2hioKD}zTQ z>#$wpfJ5nExH!5aFJR8FZK6_#^-4-lj7P&w-1;s}0Y78_h-UuTW|cprUQ$Xc6eAxX zC_SU(N{wHNBu1BNd{`uwjE#I;IN4zUBOezY?HsvV#Roj3m~SV1)FlV?zcXo4FSXdAc5J8bSTZZ?sub}_`|LyVPyaWK8634Xw00QMnL_t(|ob8pt zZqq;zhBrR!xmAE(!^T@g!=-T=pK-^Ls-CdCskpgL;zNH9|JT2}wheL^8(?OP{ZT$bdfpaB7a+iT0AL9I zc3Jss$8|!SQR-nq$1JbIq+7D>I0gvOLtF|(7y~1t&E1l1$4meSZNcF&gpt~>~S{AGrN42MsoIz3gE7LD7}zCHt)ZHXKa>Z9}7tR=2+h0n9j z=uHW#sYXJKBCVA4?b;StsJWNx44+>e|FLL32Y bzhwOc6(sj{8;KUQ00000NkvXXu0mjf0%4pp diff --git a/graphics/pokemon/furfrou/dandy_trim/overworld_normal.pal b/graphics/pokemon/furfrou/dandy_trim/overworld_normal.pal deleted file mode 100644 index 16e445224..000000000 --- a/graphics/pokemon/furfrou/dandy_trim/overworld_normal.pal +++ /dev/null @@ -1,19 +0,0 @@ -JASC-PAL -0100 -16 -153 211 165 -54 91 49 -88 88 88 -103 184 66 -237 241 227 -177 175 160 -16 16 16 -65 145 57 -91 134 247 -88 88 88 -237 241 227 -119 118 115 -188 4 0 -0 0 0 -0 0 0 -0 0 0 diff --git a/graphics/pokemon/furfrou/dandy_trim/overworld_shiny.pal b/graphics/pokemon/furfrou/dandy_trim/overworld_shiny.pal deleted file mode 100644 index f25fd2922..000000000 --- a/graphics/pokemon/furfrou/dandy_trim/overworld_shiny.pal +++ /dev/null @@ -1,19 +0,0 @@ -JASC-PAL -0100 -16 -153 211 165 -54 91 49 -50 48 48 -103 184 66 -119 118 115 -88 88 88 -16 16 16 -65 145 57 -91 134 247 -177 175 160 -255 255 255 -237 241 227 -188 4 0 -0 0 0 -0 0 0 -0 0 0 diff --git a/graphics/pokemon/furfrou/dandy_trim/shiny.pal b/graphics/pokemon/furfrou/dandy_trim/shiny.pal deleted file mode 100644 index a342aa9a3..000000000 --- a/graphics/pokemon/furfrou/dandy_trim/shiny.pal +++ /dev/null @@ -1,19 +0,0 @@ -JASC-PAL -0100 -16 -153 211 165 -66 66 68 -20 21 22 -39 39 40 -101 102 107 -82 82 89 -16 16 16 -45 79 40 -78 132 58 -110 185 43 -30 101 126 -179 181 180 -255 255 255 -189 0 48 -0 0 0 -0 0 0 diff --git a/graphics/pokemon/furfrou/debutante_trim/anim_front.png b/graphics/pokemon/furfrou/debutante_trim/anim_front.png deleted file mode 100644 index aa3a5489eae3af4403361dff369e05452ebf490a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1269 zcmV*bop9prDwJcT)fGtFVkL0000000000Z|e=500009 za7bBm000ie000ie0hKEb8vpwZ0Xt$^zs><{n?R721jz6lpbOZC z^bF(-AhNv;q+Im@1Fe@vU=Ff#4=o@d;9Azh=mS1blK%);I-ofZl*0#%Vmdqn`xX%B z+_;^G_b~xQYZ`QB%q(?T3Q-wjn*cUtX0|j@ayyXYk+pWyT+K&)XSURCw%8S8Ys+Q` z-##wQ_M`m4?B@ztY&UJdF82o6@5*_S5@2m}6brljSS=9O&J*-8v8^P%xLE#j8yB{S zPe9SyFL4;BGM>l9qy|)bV=K>3rIM3ErpaYnG#_8nD3uJ9>;Z@vRr&5UeZU=E?aV6%0)-eMk9W*KD8yG@Ct?4eR$$Utz#s>|7G zIo&tU0H8_3^NV$-utHK^45X_lfsTLv%0Rk`0-$_&DHJ&aENyWqHCNr@E&`P1rhzno z0hQ*Kfi!@?0cQirdw`2zFpkpzeAD#@r+aIGgtf1{nyLag?E*J6ky766-yQ zaJYEEm<1#l6WuEq_zzJNVbzm33yMj+}q00000NkvXXu0mjf;UYUZ diff --git a/graphics/pokemon/furfrou/debutante_trim/back.png b/graphics/pokemon/furfrou/debutante_trim/back.png deleted file mode 100644 index ec2567514a63213c4900f099b6dbb4e09478dc7f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 710 zcmV;%0y+JOP)s)Cy#O%(|NrUg>Hq)$00000002d|$iM&q00Cl4M??UK1szBL00HVr zL_t(|ob8l5Qo}G1hLbV$$ZxqadZ&nn7rGMwed1KkYNM_?8bU)bX;U& zd%)`>2L$XrV7xwVLSpwR0gZVcO{@p1RMy6vPLr;N`UTAE}r%lv+sYNUDV$ zCO^a0cA<3e)4-q>`uN|+{$aBg|FKSEah&N8L5!G$Z-Ixa`=?dVW{SL+FQY{Ch>g?Z z$B$kZj;D2@oIv6r3^-q=MC(Kk!f>2AUoQ114D;RFHWPs#w3)W3M?dyXxfXf!1DI%+ zIRVD!V9ayh%vqaR>r%W`q#$2zL3BR^ixE&rw;-@UN% UZeZqR`~Uy|07*qoM6N<$f;XS=0ssI2 diff --git a/graphics/pokemon/furfrou/debutante_trim/normal.pal b/graphics/pokemon/furfrou/debutante_trim/normal.pal deleted file mode 100644 index 2d6b70f57..000000000 --- a/graphics/pokemon/furfrou/debutante_trim/normal.pal +++ /dev/null @@ -1,19 +0,0 @@ -JASC-PAL -0100 -16 -153 211 165 -72 73 64 -224 224 216 -16 16 16 -160 160 152 -142 119 82 -255 240 173 -206 189 111 -72 80 64 -24 96 120 -184 0 48 -255 255 255 -233 234 234 -0 0 0 -0 0 0 -0 0 0 diff --git a/graphics/pokemon/furfrou/debutante_trim/overworld.png b/graphics/pokemon/furfrou/debutante_trim/overworld.png deleted file mode 100644 index 4ba981659cf75f8917136a86ba02b92e1da4dbc2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 941 zcmV;e15*5nP)*NypuCkh5D*YshWG99L zCm{G!?56R0Yy=3w1&NjN@$Syf^X{z2g!~`>$MrBQtEDZg_jds{_&B4%VE9M*%ss1R z*#LkM(vH+U@*5+x+GjSW01ldPz;aMV14dR0_{$MFFv1&-ZGa(~a7Hj{0UU5}eCLL~ z(>L}Q_}FpOcilyk!CbwgcER7FnRdkAnN+7V*bST>*!lkGip zpfgw;)yp|V;Q>n6)p8uqVzFe%@%SF+rx>s;mVFF}#q@c-yn-lt9`3IHs~@DzaI;~5 z$zu!v5CSk@!sDZ$0l< z&tkrn>j@`!&w0MmfIvyFKJlxQQW??!t>u9>06Vi`IA|Oj{%gzn#5BP0WX2MmD3<`u zzo@=mWz0|Oghax)QC*^2)ummQhPA~- z($cX=YlmN|4^2ggIZ9403ujjY7F8j#r3S>e3X%6~0HHTC@Olp15sS2~2b+k4{zdg{ zF>V}B<5zE&+d6|OFFEnI^!gqP5*TVep$ira--AC$J6a!kJ9$@3bqS>7o%#8!v8Wz` z6?zxhN}`II@oM$30!V+TZC>)BE&-vA&p8{_>#Fer{JwS+00E0RPaZr5@P43420MHP z1HD1E%4`Rk&ZVr=7wbOMd{QJL@t+_-N6Y5E?;b+4LAELzNAm{Y-W}vV>SX3+k6i?S zGWT-O5nW9v4}l>^gdPTkKw1jwB7mFH^%JSXeNP75sdt!%pft81N@xrda?Vp)A}z%V z8K5j6Ws2h!{iU`P%~WvysPP~Z$ehSA$GGbpF#;?*%SD_Js@sY@;_HTs(II7(Py#|< zTy+7sWUczFC!Qwj50dIT#UWK|Ppbge0p(AYshVge>Gj{T74v<{e`I_E2+#eos=Nha P00000NkvXXu0mjfNcOgY diff --git a/graphics/pokemon/furfrou/debutante_trim/overworld_normal.pal b/graphics/pokemon/furfrou/debutante_trim/overworld_normal.pal deleted file mode 100644 index 6acebd650..000000000 --- a/graphics/pokemon/furfrou/debutante_trim/overworld_normal.pal +++ /dev/null @@ -1,19 +0,0 @@ -JASC-PAL -0100 -16 -153 211 165 -50 48 48 -177 175 160 -237 241 227 -120 85 30 -229 214 89 -88 88 88 -188 149 56 -16 16 16 -91 134 247 -119 118 115 -237 241 227 -188 4 0 -0 0 0 -0 0 0 -0 0 0 diff --git a/graphics/pokemon/furfrou/debutante_trim/overworld_shiny.pal b/graphics/pokemon/furfrou/debutante_trim/overworld_shiny.pal deleted file mode 100644 index 43cfed54c..000000000 --- a/graphics/pokemon/furfrou/debutante_trim/overworld_shiny.pal +++ /dev/null @@ -1,19 +0,0 @@ -JASC-PAL -0100 -16 -153 211 165 -50 48 48 -88 88 88 -119 118 115 -120 85 30 -229 214 89 -177 175 160 -188 149 56 -16 16 16 -91 134 247 -237 241 227 -255 255 255 -188 4 0 -0 0 0 -0 0 0 -0 0 0 diff --git a/graphics/pokemon/furfrou/debutante_trim/shiny.pal b/graphics/pokemon/furfrou/debutante_trim/shiny.pal deleted file mode 100644 index 8ac48509b..000000000 --- a/graphics/pokemon/furfrou/debutante_trim/shiny.pal +++ /dev/null @@ -1,19 +0,0 @@ -JASC-PAL -0100 -16 -153 211 165 -20 21 22 -101 102 107 -16 16 16 -66 66 68 -158 108 75 -251 245 136 -211 173 101 -179 181 180 -30 101 126 -189 0 48 -255 255 255 -233 234 234 -0 0 0 -0 0 0 -0 0 0 diff --git a/graphics/pokemon/furfrou/diamond_trim/anim_front.png b/graphics/pokemon/furfrou/diamond_trim/anim_front.png deleted file mode 100644 index 5db380075511f141fb6463e648e1bee7003c7f4e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1246 zcmV<41R?v0P)*r1@8dUs(E5DgoUh00000FaOF{00009 za7bBm000ie000ie0hKEb8vppCPXS>W5%M*$yOC+3JtoEutI! zm?W2LkS14F`gSmsSBQZe52ciEqX4WKfN_i%EMS$>50i1s!GwT?9HzXBfpiWKLe5zG zcSk_V$&w2&y$%TJGLYj8e<&8n9DtuXR^Kxb1ni%roWVX)IhW*Z_U_36Go`o?Nuf4R znauI#0ik}X>q4mluL!VlK(1kDlLYWwkX6l3Nj`LP*w(w|Ktyo_Zk{?WR;Ic?915jR zAvPT#x!Ku2|NckoQ<67zeHlaO%Kq}jR+a!4W77rhUo5RN00;GB;KADF415d#LbSdE zFpmO_%4KC6^|MQ|1hDG?Gel8ZyMOn!>E3ek?g0O_FsAE(0fIfN8kG`|w%?b50|5tP z0JdoFbh+#S(+S;+qK%X(gSAm=L+J=Rxsc&W; zSYfNz2?t1x8>P?z*oe@Bke+}8bU<$_6L$j9Qc+-p{+`GQRsOc_?KRfmN9oP2hkkqE zjF~!ML-x;o07t<53_SNjp#78@5%NO>NL=%xxAJWS5UEmCqg7579Twa%29z)dHn4D`S3V zfX02$RHiha`z~C354ay1rYWixC?fz$dg%dOmRk1!VF?i0F5yaBTlRpeYL?y&4kNUA zFG-Dd^=>?^`#;ke^oeGdX0Q9UR%EdI1$mOj)k8w`!hbI7a9{ynt0CqW9)#wa7To9}Mb9Mhh37kW8 zBnS?b=5TmX`9+c)3G(Lkt34cWMyXR0T?z8W-#=-u5+sXC7$3D1(VWr}&Tt>#_gK;3x$!4}k6&1%)zn zz-@b-=sLh5nk_OnyW1p0Ad+l>k|yA!a+U!=g?$MG3IqbAl?M$kQM$l-{h$Md;RMJL zSl9K_AAv;i0BMv41&*D53{{c`W+W&#?DY2!AabTv49GHi2y*&iUk5ws)@b4M$x$Bk z6pDLFdVdxm%K!~R{My+xW(laNsu}sFbXFyihQ?^2n^8z zn9GsjkGn_$!|Y04UBp#!vl~WMKePbJhb5;UoP1~jP9Avq z0HBNjUOo_@OT*}gcJ4zz;9*8H`oYTw=LeIY(+^G%e53l|KR4Yit8V3qRR91007*qo IM6N<$f(5xG5&!@I diff --git a/graphics/pokemon/furfrou/diamond_trim/back.png b/graphics/pokemon/furfrou/diamond_trim/back.png deleted file mode 100644 index f3f8ae713e433d824987a29797136c89118ea18d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 657 zcmV;C0&e|@P)$P|wjbbnU?417yh!D)n%EHWd88 z2C1rQVIcB{-wzU5EdFskaL%JC5D6hREC2dZ=n?xtV8G_!&ERN&SYay8I86kMfvLo< zZL$_@^eOeG@H56io+#LjGB{E&sx}bQU@7QGICqzTW2;Z0NNAdceyVvEbO4;RTN;3Q z7W74L7{mjRm?eOeM&*yZ7o9X9%__R}w4G3jy#-3JL56dWhXu|AggBom zU<8;50}ytixm)AR?K=A;b|+|3NJ*#q7|lSir7!Gktzs08m)N^QX%2X_K}JEUQ?;wG zk~9hEB7l1VNb}QEX4kMaDIyz!wR|Cf^-VUtOfT#(VM5+EvO|egbhGFth3)j z10_f6I?c2P$FTiyk@HtRgV4NjWAK?tBVFvuXjJ*d)J`Lnnv|md% rVC|>cTPGL2aDt-!JLqCKI^`bUXj=ubDbKVa00000NkvXXu0mjf!7>F@ diff --git a/graphics/pokemon/furfrou/diamond_trim/icon.png b/graphics/pokemon/furfrou/diamond_trim/icon.png deleted file mode 100644 index 2acd3220d359bb2f6e862e4aefd1ba4e2f297c09..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 558 zcmV+}0@3}6P)i+lfKO3m(bod2|>q{aVgtej$ET0ucUS*eg@00009 za7bBm001r{001r{0eGc9b^rhX2XskIMF-~w2Ll5r$=nI!0004zNkl2^qc6yGXYm(A4~-8q{fxFfH5(qz1d-n*A5=c zI)Y|X2cY`<7$Q5>exaS>#{`Vo&8tF;bvpLNygtt)1Z=t(Z~M}Qkkd_>(9%@-6M#1& zOU|cTgvT>Y$v4L2$Jw?dYn$u>)FE4I(nW&@25{K8oCL9G9poGeZkJj+_*mx}wz{$k z?gzk{t?DTQATRImlyfjSkZmpe3Sjkn94t8q) zm)XARs}Pc^2F?2&x5Y>wRIhkH(#IDOu^s6HJnh-?NFVHPS$qb4u*Fiqpbzc@=#f6; w2U_|weYB``G1dp@`TSfTRpHO|VgFVi-#PIE@q=}?n*aa+07*qoM6N<$g2(3oRsaA1 diff --git a/graphics/pokemon/furfrou/diamond_trim/normal.pal b/graphics/pokemon/furfrou/diamond_trim/normal.pal deleted file mode 100644 index 7fdb0b262..000000000 --- a/graphics/pokemon/furfrou/diamond_trim/normal.pal +++ /dev/null @@ -1,19 +0,0 @@ -JASC-PAL -0100 -16 -153 211 165 -72 73 64 -224 224 216 -160 160 152 -122 119 97 -16 16 16 -127 78 38 -242 171 89 -193 111 38 -72 80 64 -24 96 120 -184 0 48 -255 255 255 -233 234 234 -0 0 0 -0 0 0 diff --git a/graphics/pokemon/furfrou/diamond_trim/overworld.png b/graphics/pokemon/furfrou/diamond_trim/overworld.png deleted file mode 100644 index ca116d2624da30d833c9cfab455d0ef3986ee7e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 909 zcmV;819JR{P)<1tkpERy=!1S@H(6E8fLSKK&@s90CYCvHO#6xCI=pNSRO#&Y(iO1WlyS1 zhzq_M0f1ZB2WgE>NGz!PMm-fSHx0~9gunyspxpq#8$|1|EDx5^cGF~aQtBQAc&JI4 zA<+U}IrJb}kHnU^oIty2u)R7dG?pH&E21#C_pA%bK|>cjKaAER*@4DjvFTSwMX@@H zgD#9=(A5HgoArGU2`nsHkEDGJUEt-zQeee4TM5LSJ$72>THxUpW5=&_OR>vCpCb%8 z!o%kt#0!Cb6SK`uRtsKctbbFlu);mYPD4jI8sT9a?jw|}kZy&qAug+FpBQW}^`yC> z6bR8lbY3Xd+%WJBfCPSap})c~;`yVnDklTUZQPIO1pQefyP zECmz}#m~uXA#kAhW689s6MSoZRtw6Qr$T(6YJsA`dc05qMJxpr((S?*`||TRjVi1X z(CH8HWf*Cm@QZo8tsGX7WcdsUjAmJ`kWiP4*tx-OZ(v!lI}}qN2~NVJccB&_jmtEB zf%f2XoQ^aSi;LMrFtw*umIC~JYzPG1frkW!S&#LRK*oA~9WE1I%!FX-i(F+gj3EJz zR+Kjz^syy}tjAccFl9`7P1T-%6$6bUI{o@Kw57T%JAfVagGEky!Zn# z1gsB%_W*IqTB#wBw@^c6J>E3UluL4mnUInEn(AXOTblFX6!SQz#)zVHjPz+B{D`vM zmCFiT9?>xhp+)j|h7yun5sfe>kxZ(?SxyuDdNgHq)$C#6EE00009 za7bBm000ie000ie0hKEb8vp~lGw($6L(Z3{h_5)dZ%+i^s?CP*Z#1wBW`OWo0~g#)_&n7>%z1ud2C7}U zfXx>Jh3Sm1IL}-Fdu<58W9KAURIMr%;!WTNR{P!l2Lgm}4pHp(P1E9DB(p$+08T(e zLb%2#>ZaKPJ}!#H39wbOZx3q(){ztNZl%0C914se5(29Ci)swk@W-Ej7b07W2xqxy zKJJ=dkB7*i|LLzDpb!BqW7puSnxhbRPd&A=#}PEpi~$BE_ICuRjd*JVgaB+l16%6f zkAY5PyzD!nHi|uBf9u)6C5|HAC_rKxFB79D3P{wu*h)DLa0KKAur{>pM4*80^@tM2 z{R{&v5$M4@IQ%^VE@Ik?!gQ22(4`k#0ht>pJ4~tp@B@6nvjEBr1)S$z$j?pyBJ+8C zHYqlsa>@VzYreDqrqTxJU1ZR2cxaar4RAa#BI`R!5W7x?15r%XBc|hk z6CuFb2tQGIr-6+F@B%DQ2GB#;081$`^&CYWf@4hk7xDoR zXgyZ_URK*_h=r6jRQKC_E9+L)Q=qD4ecOB_Ku+^U1&|W!LY*@Ov`(OI_H~QBx0BqZ zjg;~MtAa$JohCPB@0Lbr_7b)&z+?=DFF@`95K#NDod9LowIBNaEk?i{N7^0&f6i4H z(6nPKRR@5kC)+TDasU2bwIGxE+Sovb}o(iXhy}ShVjB zhbJK*(hjqzyz0YI|EuRu{o#OBP9)l4c1<pG`Q|#M|t&30-^w6 zfMx`E9*%JYuqjZ!Q$uumqew7tXO7p2&u-N1f1~|@icxL>p#mcHGZwOOiJ>wds*6?c z6SJ!r0*L~C%m-jxqtH-71q>Br+l~TY5l^qvV}Olo4bG8YtINGJ53<|>Hk4EbpaiuH zr0fPg!1Cu)lFtJo4|(DT)}5pTWB|?qLT()!4UnUB0x;atE+tF@m*k73y8IKXPM8mj zOBn2cCl-*VR6T~cXYCH5)_v|kUkL5 zqCUKL`2*=gPX0jpz#RTS`jC@9P|i5~LD@k|{s7YH4;oPZAf5g|`e6J)I{kt4!T1B3 y!PFnrz26#t0Ea&)eaHuYU=DvEeenLL{_rm~#JW5G1V8}*0000FVkL0053cbWs2R00Cl4M??UK1szBL00D+c zL_t(|oW0duYQjJe2k-=BpPP~#z}5BuO8RU?4-jSZY@iw1ghEf{g9q4`JwoZ7x`~OM z$$rrn2L$o|V|Hf(F^cY7agrq7JmdVyBW60+B6Wh4_qBX*9l(bw?ERC+5iB>hJmuRF zaLXAw=Z72EnUka(*OtFdn#3gUdd(@=aieI9Zh!>^qy<~)Uvdh_tn8?Bv2veLi>{7i zv~Ym2#Uk&&oJ=6rU9i6Pnp-;jl@`yD59lJ>t}FmwA!24;kWI486!c+OED(gC1< wUwc5+zh!ghobm9Nmb(BOU*zK%mR;NH7p048mJDJBZvX%Q07*qoM6N<$f?Is{_y7O^ diff --git a/graphics/pokemon/furfrou/heart_trim/icon.png b/graphics/pokemon/furfrou/heart_trim/icon.png deleted file mode 100644 index e065e47667a0fc275c1dd36a4ff58dac3360b2be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 537 zcmV+!0_OdRP)i+lfKO3m(bod2|>q{aVgtej$ET0ucUS*eg@00009 za7bBm001r{001r{0eGc9b^rhX2XskIMF-~w2Ll5$L%F~Y0004eNkl5dr z5PaP|!yMAvla`JQ#_#H7rt3Y=b4;qwJsP3%w5CYo(bO1FD%eGpd2heP?T@RovkHZn| zxq3&;t!hjE6_C&bBiTfuj7lG#(ye^ggu>d>S7BnSc&wKR4Mob00G^2qSyvb1T^v(H zjv5?Oz|@7rEP(9Ukjdu=6kvGnibG6m3p4>p@>uHVj#JO-_-5n^mnq^cW}`ZqKwBEQ zhnvsfPuo=%++qw6x;LXae=NnS|6k4*4c3kQ$%eYROVB|^y({{WR=y+PZRlt0!959} z()u_w6um*xr@;rvb{h}C3j_(2~J zd|mkQO+;)Ket@GZ8(#RqE@9$@A8fFYq}dN{1T6iKA1HS#KWdEQbmd39->?0+rEcv9 b{jMKB=++d4UFSQ?00000NkvXXu0mjfSQhSf diff --git a/graphics/pokemon/furfrou/heart_trim/normal.pal b/graphics/pokemon/furfrou/heart_trim/normal.pal deleted file mode 100644 index d8ddffcaa..000000000 --- a/graphics/pokemon/furfrou/heart_trim/normal.pal +++ /dev/null @@ -1,19 +0,0 @@ -JASC-PAL -0100 -16 -153 211 165 -64 64 64 -224 224 216 -204 209 181 -120 120 112 -160 160 152 -16 16 16 -114 50 77 -255 117 147 -193 77 98 -24 96 120 -72 80 64 -184 0 48 -255 255 255 -233 234 234 -0 0 0 diff --git a/graphics/pokemon/furfrou/heart_trim/overworld.png b/graphics/pokemon/furfrou/heart_trim/overworld.png deleted file mode 100644 index 226b08ce7d8c97a6b1eed2be3b5fcbbccfa74832..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 908 zcmV;719SX|P)nW zP>BtRZ-7`>8Td3jU+(PZtEfO?V5p-+_p_h>|L1qMQ>)#!+xCxI13ou(IIe3AyKd{R z^y{=icW&r#+QP>UE*CxHAicm+tFqF2iFx;f20V-Re zz>Aooc})0yRHBdzHZBdiFqt6(&Bj3KS%S(CIg;}%loyHS=m2=Xh`)0NZuuLp&y}Fz zU0Uu$!eS9KY;g4A=@~XS>CiDY0FH`ya+fid$JXOGz`PqT${FoB?dol(YH&p9nJG!+ z!Qv0gl)*3O!tgY`T5tC~iKWHUh0ZzrLSI_%;K{uE*{mq?=9Dgw0a08SMCtb=+xAPF zrB)!x&&H=nBLqGF@Zg6ji6m24J<$fiOtCCzKV7W?xUE`Vg^eIdzNK$0gJ)^_)fm)B z7B3LiX22%Bb}t>bCi;FT8Ew00JxjBpQ6Q`S1%Tp0Iw8#dIFgUW*syse2xzq_cv>f4E*7SoA^+SCc}5;WL7y($v(;X z(Kdo)J(M9c@$f9yLsTN+XCYiB zaM=gOg42y;Sq-%rlN+O;j?nCti6{3mbc$d)J%oRkRiKf=<1ET7fv8hMt(jN~%Cd_L z=2kYf>HHA-9tQ}o1(Cc{w-Y2+%!-i#s!z`E7x@>V`n4p;g>7(9H6Ri}WpzX`x_P#b i(u%3fA(hepxcvh3h8+GsUwqL30000E|HP)ImSyoW(w1n;wB` zraZt3%QXV-cqZBd1Y(^5Jft*CQ7Ru0h^%@0@MDU*y}lg-{`&Rj6iuljAmFYakF)0M zUz)Tobj0`PRS$UkuHh?t+_!P8g1nmnG6%fuIWFj7bL`DT0AvTmz5B;th1i=$xL48j z2}l{(_W-R_gjl=8p$8C(fZY%6$if3`2zdSSM++E3uikWLY2GMh9ueE8;8$z9DNHh3 z(%1F;1XQ~Y5bkNO(bwO*-D2pqR@hky2YiS4)B-fZt~<-{cdDzam&fJ2T?f88lN1qU zn7n$DpMWwL0`!@4^{y#yyH6?98>uoWpXQR<#ErEUy6YsKX{q7q)pG8tZx9be^Q>V0 z)w7IT54i5fX^04yZTA?~7GMB~ra9OYfPk!lhUh+!Wd}=vlrjJ?-5&y= z4Zx8eO!Al}KGDNC0j36ol#V)j6mNHd@=$(rpm|hQdw~EB@Q{_10MwNqAOU%Iz={mUZT+wx|IqyT z@Y4aerE--Kn(o;z9^N;9e`pRbFZvkAyS#(Id-jV%gKcF|8@TJ8%wGTlrz1b4HOH>T zgb3Mh9|eOP#qHDUspLs8NKx28 z&c_Hb`MhAXKu<6_K(mo&g3;>hdA|}WITH-Q;kwfY9WZl(L3JZ`9FMy|G?}%6F{L&^ zt-Kp2zlhYCVBGZM+{#syd=!l7pwIG=n0yk9Vf7J^oD0UV!u1h23Wf)Wl5@cr0uT#% z5{#wy2SOm0C&8Hbfj}?$-kDScc>RI)6osZL($e<};snei&5P=*PkpONFy>n2+UpOb z4-wEyAblvk{=oVWus@JK2%kT&J_PI!qOjoe2iAvx{eko$_W1+rL*VLZWlN7gus)Qb z^M^Ifa_A4N4|c`=K>AR6{DJkMaQ;C0P!9dU=|kcCf%L)S4^AIS=MQx7`}~3JA^wm0 Z!#~3$$ze4X)O`Q|002ovPDHLkV1fx}YuNw* diff --git a/graphics/pokemon/furfrou/kabuki_trim/back.png b/graphics/pokemon/furfrou/kabuki_trim/back.png deleted file mode 100644 index 5904d6e41989037cb987ef486f75220e28c979f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 635 zcmV->0)+jEP)v|Np%JFtfF^00000005IzZ@~Zn00Cl4M??UK1szBL00Ey# zL_t(|obA+2PJ=)c2XNT1771NjJwZFQx;2yo5PYmlbf#^LE2G|^Z8!i)FW{nAF>br# zE)K)jF!KP7TOYgrf4t$nPz>Y0eqW|-pY`QqhmeVV-ko2Oyr%X=Z_aCs3bW2TghQkn zBMnHa^kJMfm<%+~TjUKEAZmfN;0So3n8EJ;H!X( zd6Qd@S`H9O4`JyIcu8l(DDWCUu^hr+0Ki@S2zUi{x&= zSP2+&1103wsEP$?H7VlNR(@kF=8E3~5FxKaDt9Q(DZq%W_xt3DrTn&~LPSvz;PZKD zZPIp=YNH$+-@mfc=AZ)FfR8N8HtA9Ub_<-Ck{i~x0tp8vH8zZO4R*;oXb$XN!2h~)9nc0qKd?JNx#}nf6a7O-f!4so#-M>) z18mNE2;dM0arM@UIdu>@#FysOfEn|T<8=enRhqGve_#D_5uUmTtH=qd$3QlP*Ef`> VGW;b!7eW94002ovPDHLkV1mhw_&NXp diff --git a/graphics/pokemon/furfrou/kabuki_trim/icon.png b/graphics/pokemon/furfrou/kabuki_trim/icon.png deleted file mode 100644 index b3cad982e8bbfe0c7ec6088f4063afb00dc067e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 509 zcmVi+lfKO3m(bod2|>q{aVgtej$ET0ucUS*eg@00009 za7bBm001r{001r{0eGc9b^rhX2XskIMF-~w2Ll8J!$QMR0004CNkl z@jKb28nM(BNtakyXCRhc4U-%yDd@K9yL_-ZwgKHRiY9iH5ZB{mu1UN=`FMl6x*V&n7-vq%!13J~Zz5kNNlps4@Z;41+%b00000NkvXXu0mjf{zc&V diff --git a/graphics/pokemon/furfrou/kabuki_trim/normal.pal b/graphics/pokemon/furfrou/kabuki_trim/normal.pal deleted file mode 100644 index 40203cfa4..000000000 --- a/graphics/pokemon/furfrou/kabuki_trim/normal.pal +++ /dev/null @@ -1,19 +0,0 @@ -JASC-PAL -0100 -16 -153 211 165 -72 73 64 -122 119 97 -224 224 216 -204 209 181 -160 160 152 -16 16 16 -122 27 18 -198 46 25 -24 96 120 -255 59 38 -255 255 255 -184 0 48 -72 80 64 -0 0 0 -0 0 0 diff --git a/graphics/pokemon/furfrou/kabuki_trim/overworld.png b/graphics/pokemon/furfrou/kabuki_trim/overworld.png deleted file mode 100644 index 97cf66d39fd3cc63f2f48910182c4c033f035d6f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 932 zcmV;V16%xwP)<{CGD$>1 zRCt{2RWWbVKoq`6mp!(lrmN2`Lfzssoo(O6Q6qs+l_qo5_{>^0b)~ zsp1zPA!hyn8!H0~|A9NFzI%347Fdw_rhd=wzVCalcP|Lt$9=4$Wmz4FEzA11{5GX7 zP_R52{G~$Oq2!keM$eNl=rqs#DO&XjNQ=;6NeCEAJs^m>yiV7|Y6NfsB_nXyDha7h zI3?`s?}uK{g>+54wge1G1`Y|)8&5=7>76Dx-y0|q5SD8|gRkgP}K-#|=C z0a9_K=_#eYK79)-hiS$^3z&@4bf5_kCz6toYOpvV@)i-l`aa2W*zYYY9q#bi?7#k{p>JFb)XdxsajZph= zBbEX?h2+Z*v;dxnybzi3FtG@+G9z$g6L+f;z}pM4P>$QPXcLw(5JIYsO;1Bn1-2Ln#EV~JO@J?JpT0Nn-OducNy>RRg7rT4;go= zjz-I07q7a~aDF)7gq6Vf`|``c2;lt5a`~gsiPp(rHY2@Gg?qL?%ie46ppAz>5azUR<>;OG;W zQ7@pOVMr*fmjbl5&RD=gFEG1njlu5WG@u>@J3OI*N6kMSS>!_kwo8i!@e1sBMt!wB zIt}a^$H$b^mdEha9~A)O#T?gu(L$L4pVjJ%iFSm&5n+ZxBxInP(T0x00000=vonV00009 za7bBm000ie000ie0hKEb8vp4s!_PtRZ(iYSHuc445v2H{QtBIGlAmXA05#7qfOU?V z^ZdK70K7;&00BTe`5r^^jUOOVc&7+RCM(v*6Z=k8jIE>wm>oDUmK~o`nzGf@3XqCD zA7w;imRaNQ9P-cKe|@5rV+K;T>Zjin0CW5O&z}`uE$i$nfPH8+pgPA25Rq+n^Rn~& zeh7q_DCXCF%sJnV0P*PpOyKSD;q!#7dHndoRR8IRF>n{x{Np?I;sjz<^XQzCm>+y+ z0L%o02{Z^KdLzgq#0z7M8RvJ5Dg7}Ka2ddtjBnp4_4=TJ4FJYd?$wX)zrp0j{~Cx( zW1mDGQ2@U0W*Ydxhyx%Z+KRm@=xjE7V=MrH*MibUDN*PyF$TyUU*#j;X@Jg0c||sb z26zul%{Z(JBMs+$eJ#cSL15W@1)z05gB2+8-UfdpjsmUVb6tH4SCe4+-ZWV`Dwsh1 z0uVEq+AH`3RFXld+bWc>IRcWo0S4v0gjSI;W}5?m5&@!z@BsY~mN`NVzzz@x5VLjB z1M5x2*5f(i^#*{qC1zX&f1B}%!0LVb;Q@ih%=$q0Qt=7W`T?t=8Kr#?w5k!c24o|o z905eBPSjFDQMXDepiQ7{I{|^3mr_ck%_*ep1K1Xj9xd`TjFczZ-cY4kasR&y8iOw! zqCj|vu=fKuarOs?K3oLEX&|xJ4ubqX@&bf!-+K)Nn)^0S{Q%!pzEwi9o*JYBAoW&w z0nBvo6hS2=JFU`w`a|inx$dEf1Be;>xl3r0FvshXARz65F08FZ4 zkK-=@tQ-PzY}H?XtM299!9GCH`$eaeD_>v@2zZP&WKi0-z$DKNpwWVH1|}c~_d_5P z{3;k)ARcakyBH4lt6*qF82~Y~7VQsC0QKMsV7udm0X$v>Lj${802+CHBNzdku)9H< z3%>x64+Ucg>{XZ3fnW@qHTcE1v=@x&NnwV4Fx11Ia0Gq@!o{8 z$ngyTPIUY-$Fhnh9$=YOXa}|mtX35W#qVFs6YGzG;U>puJP)X00Cl4M??UK1szBL00Ejw zL_t(|oZZzsZo)7a2k_KGrEC>kAeb;P7Sn+>d>L44*qP`N=m}c7MN#^2P!9lCsd@m0 z+@%iS_=%&cTfJoX|M(tO6oTNtoer)~?^1k)yQDt1_{I%-M4V3KtS{m*(2=7C>Pi5# zV}m|X04%H~sL9Ek1GqQAKms@(qXZf^`P~U5I>2+Pb+AAmQoVrD0}c3UdJfU`N*$qI zjpvIdhvZ?sl;GGnUCcoN&+C^4VDqjY*xLFTT^bp3(v+KmVDW*D$XV<+Si+lfKO3m(bod2|>q{aVgtej$ET0ucUS*eg@00009 za7bBm001r{001r{0eGc9b^rhX2XskIMF-~w2Ll8TBbO>q0004JNkl_fZ2fI$12LQa? zm%A_b=a(eE_kh)LY%n`g3?gQ2$n0Xw+k7D!0bLDyp;)Ibo~Q)Y-snp_J7J`fTC9A^ ztf|;3_az7^UfiK9*AYx^cDnqNBdT$7$>ggSZ}0>842igx>GP}SD?qv5sGchxE_{yQd1PF+1#LF ziXL{a%%uYEEFHw6w|83gF4H^Ae|gNk7$-*x_~W;unt%r!Xm|<))qdi-c*GyZU@eqK zYSDOP4O_mZx^cp^5yI9q;yq3sAGcxakmgs$c~*rw?9=3Cs5tWRNz&Sq)5r%fkvZRW zV78pm>$1~+y&ZlD!j=y!PjcF1Egvw`SwUSsSdZzC`S=ETOXr3G(E%o6Y} zcoziGLj_Br{R=dB@aP}lN&g4mY_dCVHxVhGL3QE%=_Q;D`&CA1}#oX8|ir1}t;x$UfUb zmaGU+&ZEG|kpzG|)1%L_fIeg1Dz6i;#iWfbqDKyE9p^}ffU2N@z4W}s+TI$L7WLT_ zTXbair|zB-(1wp$^NA9;33!|>Q{(>PiqHv5)-a4)T+9SV0ftXGe~mKMEU0#%*Z>SO zfrHC8ryZUKOcO4%)I52`ADnn9Kyc^n$1lk9#yDo}JR;HhfPQA_;rz#`y$K(ccC?PA zfc16$&Oic~oZyYJ!R4fnlzRy3a1PSdXm!IN> zQZ$0jWP}6~K*!9t8y$P38~MvCGa=#b;rwje%ULrg2QS)nq-cvc#Mcy1J#2E#>9;s~ z>SZSN-PTKgoM%MpX20c6>uLhteov?bNC=1$q|PLkb-1@v(NzMW z5Mi+wfq)VW-0c?bPG#0i0oT-3mS~G+rz{GfGYFvspfTB~f2~Y(kh6C^I!XHQ=tlgQXn9dSnf8qu$}gx;Cf4?5RtHt1T@wnr9tnZDgUll zSd7_-(5$mbfss5>2tt{O>G|1;zzhpu|K#F%lKz&Xl77;2yop{U_(W6;P@XFKC)vXr i=;E`uX-&w#WBdfuOBGpsezQsd0000s)Alr-u zssg|@<~K>o0hPWhbU|6H<)#Td?-$u1$Py401{nP=2>?o|ZB;0}mdR0O%n}ZSx^<g)&d+-UdA1jTC^bC*<~6}#P`|*0G$S~IHhr+nzg|zI^8Q< zltRse#7eohx{kjSg|e!&3t*>|MMYRV3qb7_-xGiWfC)3`7Xsc4yAkVutYziA=!D3qVI=B_z7x8py!*w&pwQMq36Ikj62ip zJWcSw|3CgQ;1_RJ0XLvg(Z!96GdQnEAJBdRk`kZoAb*e>7N7>_kAKIXY~Q}UqU4gj z7~>rPMIn-eJ(hdDgFqk)=)qOs`NA) zW&+K{s_ppG0N{!j5W3ul=N>O94b`=Pfc!jAgJT1r5s$wBxN==UK%V>Yx4%Y22%aeK z7sD~^4_-m|d*D3M8XLK!2dVimUIK9Q+Uk;E5O7g2{N;X0Fw&RXKO`9G%k3W$3^J5U zf`Jsi3Ov37LM;WuZ(O&1W1r<8zhvI7q2jDuh}1ahoDkUro$<;bOG{eko$B7cBB zG@L(>J~ZSHHwDSV(jQ14O79Pf_XpC4())u|oE~_6D7`=U_)8@veVF_~d0_4jqz}q@ ze?Ww#KTP@{$RD5&j6Y05;Qc|khVuu~hkvU-{0;GPI09Fm`Huhq002ovPDHLkV1m4% B4%Gkv diff --git a/graphics/pokemon/furfrou/matron_trim/back.png b/graphics/pokemon/furfrou/matron_trim/back.png deleted file mode 100644 index c4d7eb1175ea96485652277959403cd6f90bc3e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 732 zcmV<20wev2P)ZE9%X*BwY2~L|GfY(zG;mB000p-lzspJ00Cl4M??UK1szBL00IC> zL_t(|ob8jpZrd;r#*IuG180!Nh$*1134u7-GEjiWBCv`)KtpsYU?s)ToBzZXYj(ho?- z>R)vLC)`!qVZfL}&fjz$aO#NLHXtD-@3si;NEw`T0qiyBk1*jj$N76-k9mPQz?UPN zBlRrMe{qRA6gI~|Og(@YNWm#`pRnIH+k{jd(;_S^#GlQ8ybnAK9? zb`=s}g2bGkX?dG@z>I(aUG5Nzq?8qp16)=yE+;!1g+L`o5Q2h8>lxXYe#R^Lt{QY6 zDljQyh(4L8RXVByh1P{xkMztwEQP41#6(Ade(_rnp6q_v- zcJY-xZ_D+!2B3BTzrg$YX}T9EwXX*N8w*SjD1F%i7;;kp{vwU-7SJOhZVb?(;|o)$ zi*z3#sQwYaS~F%2m~ej43OqOf{ucN+GQc$fXU8po%_xTWHrv_==u3A%YoEc5_yaI< zK$=jWODV$JO`tCBE+R{OB8h=npsfIiIV6vinvUaKl)N@1Kc7-e9-rAeX8R1 zW)W%-`yRmMBW|aHpdKj3GAcpcZNC9*m`jXnEc>R8RvkE@9SmO6Mb272^} zVDkoXG6jy-&VM{V*U}hH5YP^zK@Uea^orqN5ERq`Z2jnC;I?GPGYLkAYFcJ1t9caC>epEV3G3K!! zbZ8wL{HWT0#~21bzQ9V3{7_?&5IPeEYT3}I3hwg9)mI)Zb6FDGuWdR__B{E5HUq-yz;+)`OSL4n{0NS;{!;1;lAffl}%XPPgzJFMG$QHHKH#up`s9 zP1&0vbsDofq9I6QGXrOzQw3e|9M_CJ-ouSxS8$NG&1~NidM~B?$sGG5oUl7mim;i1 z=c_+i*B}xIFBv9*TNC+*d}JaM4qmNRzjS1Af;iJwpd_620^(@3lo4G_j%~zo5;msb z_v(9Qher6#YL(kdcm0l#CGa{y`(_<2eLu=z)HVa$GsK54R$s5JK;qYD??W{)0@pc) z@u3koRD@^O*3dFgBl?=8(E#_)$A^;-$@Q^uoRsw>2{R+$WMmHP5C}~;Fvp!ex}c|D zz>NM7i<2BvY|c%E@GcN<3d<1F)BtNCz#?XEQZj+~4H1s+!OpCrF|7_vfs+Mot1Tf3 zRC-&0FcX+!{7o}~0j7eB_J&1vGN>xn62fvTfrgo4=d)=ZEHf|_LreuhrMZBB(J6A= zHiCa#;*n?@_V_WBk+7LIc&mxilo@nHt|O5;Y^5}Hn=ehb7H@;7pO}rG*H`3{{@v*Z zi>T}K!ki(t_`))Z5bXr@vCnHGFt6=*Ys2^iBPxm*T(fW!7&6ZEb~zNtYi1xZuh8Ab z$7cP*v!$jprDv~cVQnsU?G3R5D*X-T8S87c>n+ZxBxInP(T0x00000e@2@x00009 za7bBm000ie000ie0hKEb8vp-2bCw=R}e2RumPGA^LtM zKZ@k{{i5h!eMXbX)s_lK?o+ zO%?>|3IKm&0!c7a*8JQuM%vWK;0$n`Z;%0yK$bB9lw=hG(#)p7^V*-|t<1Q##JAog z2$=0RbDjjUWJ_6p*uTVl8d`=nyFY*bbpt?nvt&v)KmOJL5FIdH^?(mA4Lw+?YJqVo z-}Xk(JH!wCu2I6~fZcbtjcL6*B+XoDJAfPjqgzv7;WOwc2;}Bx05kjFR?5l&E<`H7 z=Sg!o0ksE6nx{gDF_Fs%|8I8GXraZyDmwF6X*l(nvdO9rFnmb zsC-;X87GVO^Nd&0Jy>N0;9`OAM-?DVW#Iw_-)1dyY#6G1dGypJRe>+cZ0#yS0g%H0Gdd`Iph?E7C7E1WQ9lJYG?i4BG)Z$UA5?aO;8URU95Qx(n82|}nIpS$;6$dxm z4_tQ@G-N?4?EudG%K)H$q9QjBWU02f-s|_A#{qzq_22uK1As($lhDiEANyYpR3*It z+wYpcKBFD+*$G&^?TtWw(ZC-L#|pWU>;4#o9PU2OmhAu}5WTrZ;$FXpV9dI==@3Yb z6^syYA#NoEw4*5Hqu72W7^|^#I!aj)UD#vF4s;R7i$IJ z=_nY}p~BQ=)dKc#Plp0hmmoGL!5GvkRxq@a%}FqP#SFyeBp6;`rn|c}_m?U*KMF=1 zsAXzSzfHIRAlzkIKu~BZmWunYR}0LR3U=W22X%7+!I&xAxjp^>eYlzMMaIy!z5YP@ z5RpG%XPM6*NFO5d2WF)9`2*=gME-!|SNQya^dYkTphV{J2hs=mWc^`lYL7pVKA0!+ z2g=an52O#RKR_Sqp+8uCX#D~D;PD5m54H6NG=85ykUbRtQGfUXY(`b|$+eMu00000 LNkvXXu0mjfPDCx+ diff --git a/graphics/pokemon/furfrou/pharaoh_trim/back.png b/graphics/pokemon/furfrou/pharaoh_trim/back.png deleted file mode 100644 index f0bfdcce39fbc58c5ef316f91c8e12bb46e7fe63..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 724 zcmV;_0xSKAP)+2s<(k=|@n;0Yd9A{=7HAnbOaa-rfYG zSOOz7__7Z`D3&^sH9qAxo(g?b#~`>R4<2Cj4#W{D$jn!vj>)hRg$o=bM1&v`NCp`f z4iNUQI2MBE_#VZlD-UpyFLi+|uO>a_0>}8ewlL-Re8wCL-RlpND8sHrfSNIF1JG9o z=$Jt20MrDKT_Zec0W1q{4Fy~kLWqj^0qL>Gg$gxl8Dq!egQzE!agA6eC|@=P$@3o; z5O$Y_#VNlv0r1W4BD*`>r9Es9kp45!Z3CWe48T4slvZY+)CSnI36yq%pReYqZ4)m{ z0-%}1tdYLFeV>6vGYe=EW7he#Sue~opxntN9Bww7#jEKvWV+XgNm2o8X6ixk6fqg6 zf}%tMYg-P2oD_QLD4Ia%e6Cywu>(AMJ21yB0Db;rAo1SV0DS-m!r|WmTn-8!0OsmA zBCLU)`zTPfJ+6qVOWo539oLH~|8#GkG=1L|4Y(KOyxai^6b=AZM{xTf$WoUTv9?<7 zODW%@z9#6UAS7Sex_Yp-IXYNgRgdO%4z@ak+Jta{{qY+li7^r1CxjCK0000i+lfKO3m(bod2|>q{aVgtej$ET0ucUS*eg@00009 za7bBm001r{001r{0eGc9b^rhX2XskIMF-~w2Ll8n5l=>}0004INkl#8BU6mlHZfeBkm44^(eQ^b7=buY8I{|S|Si10GM!}2r`7W6BRE$EW4AC~vg4ZN) zFvT=WU=pAr*5x61RPG}DDC}Iq#q=&0DESkJp29(GrM1fA@sd^sEBJ``5~F5f>_apE zAZRwUZ!mXJFnTyP>$fPdDY+Voo|HhK(4 z=ieO2V#;BRH;b^v-h7A>MMc*1$d$%Huhvj8p8I^jeTKg8;}B`Q2@mT zPe=isw-4(;6k!?&nuM$hrg=K!z*K0x$&#h;;Z>H*d{kcfm6ON^+jbZlSw}uVZ0lbS zi};=J@V&>G4>r0di!&b_2(ooH^C6m*whKPMac%F+$1jwN{7K0CuRj0)002ovPDHLk FV1h#KTGp>U>gBxqb<%_&l>vx5mkH6kF3s&JT(ebXjv zGodDp=LE&kS!W;!)Bzk!pePKrX8>=yB1don+rg5MgdN79n9!$jv~o~5YXTBcj7l^R zF>aBuf%xNy#Y<$y1T_X+@*K4r64u)BjprrG;{>Bll7X+51z_$ZP@}v=w2|B=rqjj~ z33tvKiNH2isJIXWU?&7xiP|nT;*3hm;J6eMk}7XnI#0+Z7;9|Yh!t-IM@X=eq5Y6% zh2pNUds?a`1b&(Bo@RSXRKH?$5!@N|FxHsAJfa#8*l`IFY&<$&|8gw|hS~A7Tu%r( zWqUmJMoY9e`*D3U-&K7FW73ZMLcRH#dAGkJ2=vDIY-w&OHkF0jzmoo+oyG{zn z5o;gzW*7ErL2z!?ht@h`EcC;sxRDBl{s_H%(zR}QUnRYt#>%>GGk5bG-2jGlSQ7-g z>GuE=fZwu&n}qvAK;tZpl{LNS4f5g!yiNIIEDNlgJNzjm@jB2pMbj}is9!`0?OU*- zR*GzZ+th`kgmp@(C5BN2B8&(iUy%q>c&->E0{(JsjA`4WBEU86YKsbgj)#{FFzs8g zqIleb4k#)utzRNccmuj3fNx14W}l+*;|{Sl;{c6P+aVNXti8=p=^J>wLOg^O&mke6 zrbBK)ZlCe_UkzhZD~M*D=ZlX5&t@P+3Q5iL$OL$r=4EG#8;Gc3YaS~{sSJOE$RVa% zs(vc=e#%WQhx1*bop9prDv~cVQ-1W`fr3NrssiV0cJSK)3)f|NsB#>goUh00000GdSvK00009 za7bBm000ie000ie0hKEb8vpi?FD*`uA0T1A-_k-iT;r8uIM66X5;ti z@rimQzbNXBSM&Ls=)#!CQeIt(OL-A+ahU|;uUvdH4~5^vQeH|CFWc}uR73|XW$Xt~ zz=DBmxmO-ZJBFX_~uCCn?nl}O8MqUH}>MF4V?5$^Pj`r(2~cRmkGWP?qNH>6EHeDOI!y zX72}pu7CgIue1Pg-%YUZ1A^@Cr#~&_sk)!HHR`GlynVJja(lZ_u12k&Dl^ECBi`gT z#X3;?R@Grpr68g;14OPSUYJ3ZqEUs+ZPUG?Te-s+xU%1XCjiI(f+72cfo>H`W2z%X zL11Pu>OqltqvqcLlx)o4iwGoG0SUtd2@!~oEZ zT-{U$Ucl;udtgu@s$NTZQ&s%-RUHDPd%kkT<>RK>@!{d(k2^uhI6)+81~9=9>w_DRKXT6ksEr56ZN@X8D=DjaYmVj+SUs~R0^rsmn*e#<)H`c` zL4%Gg3%2Y3^s?0f{`x%MKGRm%=H9g z1nBy7dUn8BFa`$l`fs~Cop8#juYxf&kbi!&_T@89x3gf34dnF;pWpz_f-yFbD0=za z0qyRa8c6=Lo8s&b69d8Bt=4_P7#j!!@g)P{W1az<1`GtirUy(71cnm#fQfos|jZ) zX9M9&uStABXCVCH$6a^#acCfuTQU2%-JT7^d;5!Qf$d$m1b#gbw*Y=|1`_gzRAS@7 zKnfcI6gC~UU19Tp#Gv0 diff --git a/graphics/pokemon/furfrou/star_trim/back.png b/graphics/pokemon/furfrou/star_trim/back.png deleted file mode 100644 index 1e4dd296f595ce138b8d0646a6f1af0e576e615c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 683 zcmV;c0#yBpP)@C>3B!1pNH00YW;v4I9Mc$A!(y}Ld`cvJ9!h?78Us~!X^fIz z#DEIm{1VzI`D&nsOrei*U17k1?K=7#1le0?)oW)?-PN9wUHkwJo?JNL_ zxX)`3JOP9ttRhhK3sK<1bO;K&)(uc=|7hE!06+Kh*ijEy-%;k9d2EK{~PyZ(0TTG=KS->P)i+lfKO3m(bod2|>q{aVgtej$ET0ucUS*eg@00009 za7bBm001r{001r{0eGc9b^rhX2XskIMF-~w2Ll8yZ~i(F0004@Nkld2hDYhrp%MdA7kHgka+Q@KZA6)CTaJW4N^H(f;+RTo6<(73 zxjX-N_eIgQj*%DNkh|v~6M(s}&!YdXA)NyL{n~aRY6>x6k||l`6a|=qLc;i zcuFO~2v_26wS_oEfi+##mhG32CU}YH1T3}%xG|9t-7SQ%&2vgIMD#xPyU$$AWuynE z`Urw!#vqUv&IOkSwV^l7XWXDVcB^t;an60WhZ-8D1EB(F_n0Wh0YPGHx3L|W$itm?Mnk87Xa5GS=^)iEr6|}ns zNqPgA;49J24;E)g&AF$5VQ#RAcntdp+i1Q ztk0p)R*{OdHgxoAldR+-gVYe9LvffHia!q1KO|u=cwyrzarDJ#^yN-?Cy0r@- zA7JdT^Y*nSIkEI)NXB4?4JJt7_w?TXulFou82{J5vdkTwtv{`AJDP)qf7hY0Jz#sT z1N~g=X@Hm zO=}W+E|@v;M2#yAB7rzqQ|S!j;i|ec)j3(G41|CSW?U8mZ7FE17&IvI^8>^exL#jf z+jy#Rsi!886h^Rj28L`zJ{JrmBA+|>d3xMCa{`y!m(H_`AvtMwq(MRw&0tStDT9IU z2R`hOqik?QF3N$R5+S`Q;FyqPJz_g1JqOI#*(2o4mPafvykLiR+#f2?BxU))Sg|v`TkMjd83+= zZg`LzH1-8H)&{7`X0xo@FuO&PAD-j}DE-Rbj^#x7A)Ye!C6!pBEbVqH)0{8I9IsDu zMCCS1ZcS@`d!X}OUNI_$pqBa?D)6FEc* zj*k7)_uj5@tTC1{rDzJADMRy+bgr06C^G6qF7@h7Wzh112#1=%c#A<)Z?+f^EV4nf zr-rJQhuK@BMpRkM7*ikJT(B9N0|QKlM@yD&;`L*u^o${V%tTAe%4DeojoOmdKC66Q z?^Xs2WgwU?fPw!BK9;NJ@*WtVMhh*${$$Q0U>nbZK3dLYhexk@`!%L2!hPz2TVa^5 zfeM^e+|FLXj@tewi+Md$!rriY;Qc9|r{j?LUsAYd+WR=_}0V`K1 z8`+ex9LT1uqT^Vrjyh)t<$d(^ESF4)sQBgAz(q}TO4N^N&{!9mrPgTR4}*KHtWnNLnnU$`#j zftgTmX33mBPinAv#@NLRis22ZXI}w*cKKY?z&c|Q2nkGVZ#V-ojIm3skY@Fn7%v6U z9D3X?%^XAld#*jyz6^yux|A*&aB>CsBphf}?JHQrkcB6~F48xuQX(HC)soxbqIN*4=!9nCpQ$R_J zpgKMtL@}Z!=lspDcv%&udIG5K<24rr*g=%68OQOv;=7^DQv&MRR-P0vwYT#ZRKiby z_CF*L0@%{GzUXZ9Y`Rm~j3PDw5dY$b2Y-`Ogg$_^&KK@h&!dLH&!#{;dGPnV0N6lL zDr=peyOmzo<~;6)Ne}@3Nm0wXSPSgMs@v&$l*jQ;ST6~1E^3J&8A^%5QWx9(O&mWJ zdBXmTkH`Q17i%1~` z;fo+`>It`e2*8j3w4PJ-WZR}|fiGt8um_F>Q4>H#H*&_biKKC8v6fvM9zd)M;B5u_ z#W1f9w!5Xn1w4$$T+Ii;A9KWji_#U)1AtR+5I&}wRSPOc4nOAg(XMt(m&*R(l{M=j zu?%xahNWx3?wC|`4V$hE`aayR?Qq+`nk40r|6E2njheCSqv4P`kqAyvv4MX1+Ks%930D-SdVmATGy1vqO_-K{KlM!jW zMizb^Zi#SFgA$)+v$gg&?UCB%ycPJbQ7GGnArsQ*sQK-YS_>j^H?!$MzKq=_f(XP}fJ~`s+1OJtWj~aFxZ#NFTBZg< zD509q89IPV@$WWmQ9PcW%Ay!$I6%I&Z~(yP2M6@(PMRjL6Gu&yFc1^^d^DnSmsWJ| ze0#6#prS1V9Rxz74~|MVF5T_D)epJVM_f+WoNzvx2U4oFI$E9VJ>u($bfe%njiK;=z%)r4l6YO!hD z|IX6qrFX?~j0PV^zO`M*`PK)p%zJM57(Trp3!7D!8E?sZ_%Q*h9 zPq+a04Wk+VFyW*2wK%Q>r~Ie$55`vsXqXd`=X?w;&ij|~zBvWWM*v3Kb6H?7odxF~ zN@NO(O10R=c%ds%$(g8cVmDyq3g@U1p$1IyFt1! zB$Z_jz6tO;k!AUwER(0-ecQTlTF5%#7Kc+(gfOg}IcE;JON(2Q`|phZ07@oOg|z41 QJOBUy07*qoM6N<$f|FRG$N&HU diff --git a/graphics/pokemon/great_tusk/back.png b/graphics/pokemon/great_tusk/back.png index 0b7c0f6620e380c41170d104d5efaaccc06ae85b..e89f81b6d76c499197e1e826717111be5a3f39ea 100644 GIT binary patch delta 867 zcmV-p1DyPg2Kok&B!2;OQb$4nuFf3k0000mP)t-snbV~(84_(98)a(u zOv<40|NrgiN{Ge5JyYq&i5{}SJ!r+*wy*t<7S(>C&uSkNTz?<=SNe|uK@IxP060IX z{SA;xDJd=VshqII;w(Swwu?U2h4-~t-*%nTE*|vPwHy7si>H-aLYj^lJ>_!#10j{W zO>m&FSSbs7*EayC)He}PNTT0K3fNq^0qAl;ow;q|*Nf80wC}`%SeI$5^|$jq?AkEA z@2PMm%2^2M4u2r=CAc85)*mV$NcSezLC!&3xXXe9K=4LQ$pM*@Bv8ch2LKlZh`x2Y zd?J$f$Z$P^0LV=e08kqyg(ZPPU_`HD90Bs4S^=bDWg0c!Ulj1dm0*Cfa6tjsO8qC= z!oG9NhRJp#st4r)kdqk+z+ti%rpJp`^ik@#OCG{KKz~mT0cU|A!;ki>hWs%?;0^#` z22@>^gh|I{^_uD>C>6BBmB1?i2o#&C3P>m9956~h00QZxaNFj=7>=`NFz{w2ILin? zw=&1J37^#|YrxzpAorB@4Dz}$GMow=HI3XIXstW}F7ntMvao$!^nUGKdUmo9 zyEcw!=zllAG=>!5d83urhP8}G8$BZgPYupGl`uF!sCOiKyVaR7jkIftoLA&VaJ-bv%|isidOHvL)E?1R^RWp! zD4PpMZ44o}JoOs-WjQuW`wkZlOsDQ&=$jsM^mlt~P9(y-JeXgKM zC4_klmw?cw=jcH=f~P48OF;9%02+kHrI5jeu?XRffEb?7)((Ro!ypf$0b)@|4A1BD zAzXmK9gD}TAzY17ZbF09^Z@X9Xdb!e#x^1V6OxXUg4lzq$(MKNH4#?e4w2y?6_Sk< trl^8y`sx@vL%xJD<`4gLf9-1*`vcG_McWgd1^@s6002ovPDHLkV1llhlA!XpFpTSA+yfv*ABP(!4z0E5YzG1`kRI-tEvAAp79XTV}n zo&bP2U|IUQ_5~X~%6XASLEtn2EQ^1@h^Or99)&PY_aEG*@0W!%W7U5qWch2CnfF*o z^Ab;1%WzN79)G!93rFCEAfG^tzdsO`-dFizeeNB3`%FN9a6pev-WJeTo>)ILnfnJM zKkz347r-G)VOR6~#|hhP7$e*_QZh?OvPo?tZovuo^5BywPq8JTUrW%;M3PGgd~Dr* z5_yO)HqkF7q;BShft-6q#vOv5{IP^FI&JsHtede*w0|KXg+BXu1d!xK%xfbz~Qn0Fl=aUO;R|okdoH5ZFVa@4XZtDwUOC z`F^B%qRMe>EbkeZ3!4-h^apgI^s nA0CeOp*Jz6Dc@zL!#9S1kz+Ss5hMAx00000NkvXXu0mjf2is&3 diff --git a/graphics/pokemon/great_tusk/front.png b/graphics/pokemon/great_tusk/front.png new file mode 100644 index 0000000000000000000000000000000000000000..26c6b5cff70a7059b2a73a3f2703d7fc6f70828a GIT binary patch literal 1087 zcmV-F1i<@=P)Px#Fi=cXMVZs3DIh*=8yj#KGD0_Fv@R~V6G?$rMdVFw`S3$_f1O-eqqwM^5D*Zl zz}W8b+BUI0LjV8+y-7qtR9JYjT}w)WX7^D+rv zzFz+>#NsdHAB+D>DDsbt2ST#=1O3<$Qd%vZ5LG{pJs{<^#x0@o-<2_~P23O~|I!-h z^ml}=0F6GczazBz@t8nvDESNF%Lo*GawGZ1LOTQpK+dZAMEFtx0-)c${01NrLT5lj zPj~>}FKTN*<6B>3q&o{6fEG4=FaRu(v5)8_U@SGXS!kZaE4%^F&jCt7^Q($010vibcEK-77oY+ zSZ*gkC3GsgqYM-==MB&?k`+f^s&Yb5{PXiOO^fb;X{(Ym3IMVl;h{SH{1{+a76W7h zAjSeAK^-uT!!Xcm73&Nc+Pc01k^>y#1hs{hb?~r^bw(^6XxagE+QN6>9smpT+{m}s zQqWHCO{O|fXZ*<2!j38S)k@sDKknkC-+alqWrLR z**vt)a{fm8d8P(Rak=d*Er55mnTndrQcYlDJhLn^4EUlA{G`K_Dp%@2T`fOio$u+5c8b87Ty zz67B7`#4LhUm8L+U{iBG5MHXKna(JncRo!V(KbPab{Yoij{sx%IuQ12oeNtw1f7OE zK;>{Q%3xEF4MET{i5CK>hqpTbSA%JnxrABUR|ZUc2Z+q4kZpO+wzjFi0Ptw1{DQEp zaOO~aod7ryU!4ADf;5DsN$U)d(xM{-7A0I5IskAeh7d{@O(DWt=fJN=z&pajZjp=- zpa=JjllG#t9U+7m>7hvyX#yGvjuGyT`rZP2d0Rv7Wg7siD>A@&9|?yXgiaAL5KaU- zjX2d)B!rKSCR#vB3yrcbF8~)TZtzSs2otnQ$|V4Y19#dOD#2D&N<32+gYZGF^0>=jb! z5dH9q+5=YM((e*$0Cnzb^Z`HWeM36jY3HBT_8M)%L{I5HAgTxnn*$qc<@KabS;}VA zx+^;;KaU2u876LsO;a2*b<=qSl)4-Wt9D%Tde;Aj`X7FsVGQOem{$M*002ovPDHLk FV1h#&-#!2U literal 0 HcmV?d00001 diff --git a/graphics/pokemon/great_tusk/normal.pal b/graphics/pokemon/great_tusk/normal.pal index b5c23a128..b91f7def1 100644 --- a/graphics/pokemon/great_tusk/normal.pal +++ b/graphics/pokemon/great_tusk/normal.pal @@ -1,19 +1,19 @@ JASC-PAL 0100 16 -0 160 232 -112 24 48 -144 8 56 -232 48 120 -104 24 40 +153 211 165 +41 32 62 +109 27 27 +112 24 50 +66 55 99 +180 46 46 +184 19 73 +129 87 69 +228 77 109 +249 240 67 +118 127 157 +92 89 163 +184 168 158 16 16 16 -40 32 64 -96 88 160 -56 48 88 -120 80 64 -184 168 160 -240 240 216 -128 136 160 -168 192 216 -248 240 88 -8 8 8 +169 192 216 +238 241 218 diff --git a/graphics/pokemon/great_tusk/shiny.pal b/graphics/pokemon/great_tusk/shiny.pal index c7449781d..7c0d005a4 100644 --- a/graphics/pokemon/great_tusk/shiny.pal +++ b/graphics/pokemon/great_tusk/shiny.pal @@ -1,19 +1,19 @@ JASC-PAL 0100 16 -0 160 232 -160 104 16 -216 168 88 -248 240 152 -104 24 40 -16 16 16 -56 24 24 +153 211 165 +48 25 18 +109 27 27 +101 107 8 +85 53 42 +180 46 46 +166 175 26 +129 87 69 +229 240 58 +249 240 67 +111 152 126 128 80 64 -96 64 48 -120 80 64 -184 168 160 -240 240 216 -72 176 144 -176 240 200 -248 240 88 -8 8 8 +184 168 158 +16 16 16 +167 205 188 +238 241 218 diff --git a/graphics/pokemon/greninja/ash/overworld.png b/graphics/pokemon/greninja/ash/overworld.png new file mode 100644 index 0000000000000000000000000000000000000000..9313520a5eee723fb4c2c46608a714b8f5cb2d26 GIT binary patch literal 1092 zcmV-K1iSl*P)D zi;S3SFo+8FltVCvoP6-1&^;KIEbJxt5<>D7+9e@%umf9Z^>0=yL7}J8&SAB`S2NEu z^J?B1g#K^;kw&5)sb0zdxUEH64Xu*@MkAzN#j+6zYLTE-#t7kgUnLt{s2iK zXswGh>An{JE8(zv7hxos`S1cGy!GzYQ&h!rV6557`O1CG_RBaDtYbt(gGEMLZ;k<= zlI;<-56^=x8ylsJ@ZQrc`io#t;M(PLv(>s$$-RKybkF%}dtj6@!gjFL4g`Y&&nA3r zRnaP0J|uHN#V_Yju<_#AiaA9Ud`WIZdR7(7hf3q}_`Q-FEHb*Fty`_tjZCn>n7?f) zS3}vaV1&#sHa{JG{#r3Ac!Rb`Log^XzC(_`{B3Ca6&%(qefaw5{6|*K60uGwA@C^m zLq(p^##hdt;~%Dr{9u+aX>K@8@0vq1gP2)djF{W|Cjh5*_En4gjpGbI*nJtoa`mlO;j`DA>;Fnpmuux?k-;yO0tVgz~OhZ7!M#N#pd68xv6;Z})mL zWGx?H2bLWe7Y|XKGB@U$ljVqa`&2yabWc@8mioNojx|UP+h@Gf@8|F3APD^a$JhXL z>P3ud_p)ML=V!br2;$B}7g_b-TPoBx5PF*l=Wj2Z@xc7}UGf&s*{JQLIhS;onSqfD zDjYy$bz;G;c>L~~toJfM(1VfQ9Q(Ct&MF)GDBb5sf=$cp359hAE*BW-V-taRfq{nY zms!9b?YX*@o~?5RE-;eR%~4mjvw$=qlz2HK%$Bc5mVIJ5*z+_DS?S9`xV;z`jsle{ zO`^&9U;+~F3yduxKg%HtTy1`prW~!&W%+~&LC_Q=!aXi6+|l~oPH_oh2z#De^e==k z=Vm#?j-A^@gM|?DmQq*<;dKwnA(31D24V;o`!9zUxTOETxBUh8>Th+*<0W+f0000< KMNUMnLSTZ|RQ8Sl literal 0 HcmV?d00001 diff --git a/graphics/pokemon/greninja/ash/overworld_normal.pal b/graphics/pokemon/greninja/ash/overworld_normal.pal new file mode 100644 index 000000000..04bbf21dd --- /dev/null +++ b/graphics/pokemon/greninja/ash/overworld_normal.pal @@ -0,0 +1,19 @@ +JASC-PAL +0100 +16 +152 208 160 +46 56 55 +68 84 82 +20 20 20 +220 212 133 +234 152 208 +72 95 157 +245 103 190 +62 141 206 +136 186 226 +184 62 48 +176 97 134 +186 214 237 +233 85 88 +241 174 219 +100 33 26 diff --git a/graphics/pokemon/greninja/ash/overworld_shiny.pal b/graphics/pokemon/greninja/ash/overworld_shiny.pal new file mode 100644 index 000000000..6ce04a931 --- /dev/null +++ b/graphics/pokemon/greninja/ash/overworld_shiny.pal @@ -0,0 +1,19 @@ +JASC-PAL +0100 +16 +152 208 160 +46 56 55 +68 84 82 +20 20 20 +184 152 83 +234 152 208 +46 56 55 +245 103 190 +68 84 82 +136 186 226 +184 62 48 +176 97 134 +186 214 237 +233 85 88 +241 174 219 +100 33 26 diff --git a/graphics/pokemon/hydrapple/back.png b/graphics/pokemon/hydrapple/back.png index f84712a508af9a67d89eb9b93c815e52122fc87f..ec5f77cabe3b754655835fa4aae16c6f868992de 100644 GIT binary patch delta 884 zcmV-)1B?8<28#!fB!35VNliru=?4lIFA~_!AWi@P02g#cSaefwW^{L9a%BKVOhiyl zM<8}(av(DOV1ZP1_K>z@;j|==^1poj5 zFi=cXMF6+&5D*Z6K>(mND=T3RxLp9&j{(9gI{(ua9jhi^tA8E;`iab{cBI%!@ZFsN zQvh!6KG*;N00Cl4M??UK1szBL00OT`L_t(|oZXYbYTPgohOOXxt+Iq5ylHnKJ@hH; zqV^!{7IFwBr#8?fmp()S8~h5sG`Ogjq3$~vd@7=_;M0N*d4VO@p3;%zB98z6)?|YRB8wb$K;P9poNL?JX4u8Tv04o4U4p8dF&pr)49v~CN zf$snq0!c*`S7}r9NnkjG3e8d~)ln}{g2a=FQsrW+0=@~t;2x+KH~z*MtntPO6lOnE zb+N*YE+AW=F^=;1&(|)%xrmrRfa{2xfrpb$39fY$u>t`tB*yWhGf5v!)D4RbkP16* z*)c0MCVy!M$P(jRz&LvB13j=wro>VjKU59Sqz^KE&^AdTB?S6`vqZt>V!4HXfSM%c zxOfpNiks^|;ZY?x0;nSyOG3R7hhPmrJ#?fjAQdyIM8#eQAW%>LCK9~cf zvH-;PF8Fx=c+&+c;eeo>jc&RC#Ke_&9PToB0)P1R$pXZ*Y)aq!xNfRaHH zSYSC4a9BJ7cxBcAoc@B;g0+rW5g4He#P(kLsD`LoO6OP?fY<_f|7(0>vaMm-m`)IQ zYgGyZknr9y)1J3Coqa~&9g`}+_i5%$9vov(?7hn7$43BfCXhS_ld1KIqG2fYT6B!4haOjJdf(4bg2AP^7`*oXkYPyirE7>HOn_|OnYfH?T*kie)= zC}0R!s2HHwNbtx|AXo^m*9T1i00OQ_L_t(YiH+60Yui8+0Py2*x_BruB~w47vz&k< zm*6uPItA+>YcLo*8n<|9r#K+876SeQLZNGh4mX%&=}^TPynk8_)T@0SGI;2qq4W>v zJNbiCd{XkjI>Y_+-qYzMA@q#EdpYwd(I%9piw^P9MCR1$ko`mbBq1hpt03C>g!ER9 z*i}!8gjO*zUU{B(YINE}FJ6*kTJ;QKbUJJCGX|`GluBV4yDO2Mx6~5vY$}D3+lcIZ zp(gkn0m`q4Wq)+O5a0K2Vt|+!ray3gWq^1sh!DT$p;`l>d?YLbL?A$D0q4ZZiAgXP zq6FYud?`S1g0KUpLkb}V;qK$bBC>q|!hsaxO}Ids!1C-#2@ccnQ4?z*&z7;(R`UG=0ui`nBd~R_{{(S01jnX kNgrlSO#mtY000O800000007cclK=n!07*qoM6N<$f)_q)IsgCw diff --git a/graphics/pokemon/hydrapple/front.png b/graphics/pokemon/hydrapple/front.png index eecdea6d782df1824dd4c7112ecc90d50d6a6517..ca82294df1952bd446323b9e547339c79ceab5e6 100644 GIT binary patch delta 970 zcmV;*12z1I3DgIW7=H)@0001;w}I>c0004VQb$4nuFf3k0000mP)t-s0JrZD5D;Y$ z3?xk)D`5_g6AQf@5W*}v=1MiwB0XQL9r}oC%&K;z*h=u-oqYfRk}^@w000A0Nklw>Ew41^mRsj^7l|837q0%)&d4?lLTb-sk$q?gN=rGK*jcYbL$rR4tth^Snz zzXN1h7Px&YR9j>%zEj0Y{pgwiCX?MU|1c`-x80D75jH~BcE<#t2ss41m2 z^cI4Iw6A&t;k}&tEN+xJbr)<49?g}6+c!YTyZBcZY_`<_W`^%t0H;cvN&apLJobwqD2^csL|fF|ngxOSEF z`fhm*0#$C91TLFW_M+G0qpO72bkVPnP-`;tV&Lp6ri`Zcf3A1Lz|T0T#+x5g4B1XS zHf9g?f!#1o+a|1){0Kbq`yqJny%szV);$N&HU delta 1150 zcmV-^1cCe12Zsre7=Hu<00013M{Ml?001yhOjJdf(4bg2AP^7`m>3XX5C|Yh7>HOn z*ib-7fH?S|punh5C}0R!s2HHwNbtx|AXo_QchqYD00a0*L_t(YiG7tZi{nNV$7dC% z($-rKV<&ef$s%Y3E&^e(6_$g$bb+g{$OkwF#I~-MY)G*wmVaw?ML^aHVUn<{EEjIF z*rUdQkgPRVs5)dapCNC?a`x_!cM41R{pP(l|Nk3=&~6>zPh9*hMtj#0KJmXkdjR;n zb9(8H_Qwxiwtjizn&|_87QP9ld9n}CULsT{ft$h! z`W>5pSu74CzJF?n>m|xpv&{NIh$vq-0y;NEclDDHRaDo|(+_|{z7*YgKp+L*0<(>N ze;_?Lnx~$+67FSaiD0612 zg%|*2cYoYtDH-RGQH&?nS*m(0Mj4CW0brB^*F(qxU@nNL7&}Vo2Aqyi?L>3Z2^93 z#eW-}-N6>721dikSwP!*RU|F%8|c!aUqS*5hnf&|RXo>LH|FZsp8u7I{-nKOKOals z+H!l#qkW--yjoxSLrQzT?^6R*)XD*j0~(MvxUFssf9=<6=tyNnhkD207^##i+P}r? z%N^iiH4hGP?_EXD|JlWTO0k*;vWsnjKYx7x(m(Zk5U2RPoxAl6QeVOmdcz&?(Hh9q zPMfxeggOmzr1gB4ww=!4l}DNqAVi040@()_u7^Ku0tT-rg)%2UclzkM>D%(uevU`BtR>000hUSV?A0O#mtY000O800000007cc QlK=n!07*qoM6N<$g3^T&&Hw-a diff --git a/graphics/pokemon/hydrapple/normal.pal b/graphics/pokemon/hydrapple/normal.pal index 6fec9a795..b29a319b8 100644 --- a/graphics/pokemon/hydrapple/normal.pal +++ b/graphics/pokemon/hydrapple/normal.pal @@ -1,19 +1,19 @@ JASC-PAL 0100 16 -152 208 160 -88 56 32 +0 183 239 16 16 16 -152 24 16 -96 16 8 -32 72 24 -136 88 56 -216 80 64 -72 128 56 -248 160 160 -192 168 80 -40 96 8 -88 168 24 -160 216 72 -240 200 80 -32 88 8 +101 16 12 +36 77 28 +43 97 14 +143 19 11 +189 28 16 +194 44 58 +230 74 53 +211 34 61 +95 171 29 +250 136 107 +204 170 118 +164 216 74 +240 221 157 +125 0 0 diff --git a/graphics/pokemon/hydrapple/shiny.pal b/graphics/pokemon/hydrapple/shiny.pal index d3d0f68f9..35e42dc80 100644 --- a/graphics/pokemon/hydrapple/shiny.pal +++ b/graphics/pokemon/hydrapple/shiny.pal @@ -1,19 +1,19 @@ JASC-PAL 0100 16 -152 208 160 -88 56 32 +0 183 239 16 16 16 -216 136 0 -192 80 0 -32 72 24 -136 88 56 -248 208 16 -72 128 56 -248 232 144 -192 168 80 -40 96 8 -88 168 24 -160 216 72 -240 200 80 -32 88 8 +128 65 0 +160 53 43 +43 97 14 +184 93 0 +214 143 1 +194 44 58 +255 211 22 +29 171 38 +95 171 29 +255 250 137 +204 170 118 +164 216 74 +240 221 157 +0 83 0 diff --git a/graphics/pokemon/kecleon/overworld_shiny.pal b/graphics/pokemon/kecleon/overworld_shiny.pal index 77cc0112e..d12afcf8b 100644 --- a/graphics/pokemon/kecleon/overworld_shiny.pal +++ b/graphics/pokemon/kecleon/overworld_shiny.pal @@ -14,6 +14,6 @@ JASC-PAL 96 168 120 64 136 96 232 232 248 -152 40 64 +39 44 149 0 0 0 0 0 0 diff --git a/graphics/pokemon/kingler/overworld.png b/graphics/pokemon/kingler/overworld.png index 135f79b3265f3a35e81c0896d3f955b571b4adb3..c67ce3a53af2d0dd838dbcff67818aa40e67ecfc 100644 GIT binary patch delta 1028 zcmV+f1pE7v2bKsWiBL{Q4GJ0x0000DNk~Le000310000W1Oos701t<|*8l(j9+5I4 ze@mlhnE(I-vq?ljRCr$Pl`(JQHWYv*z(0UbBy(Oxx!onI3A%|E zH;6W{Uc7&hge1#X0h;bn5DDW=&fXCcf8xO_;rjsq`+}{5*1}Y+^Mi0@QH+GE)vAC~ z00pguTqyv;wU8c3sWMubsFi!B5zeR?F$JN}nk!EZJ0(g{!B9G&$0y(a4t^+ay zfl;^vwqa=#;wxoX;+e*AB=q}KsDed869s5p#w<|CQAnIAKwgCDE@S>BLx#k2fAsF9 z`JP2W&j}!tu%<^&iTz~zOmS_Rg^kL6kQZ7fv}u(i>m7)|;D4fmStqnXn1W{mu-A-) z`;r27EwLM(tK4eYTr&oFA!MfHVwYr!A(y~CyCC$bJlQ+WgAju}=fE{1VIe4>+O-gI zVnF3348)l-r4I_iy2Sty0(4*ue{ul^1CWCdg8~rCz3J_swNiaOzY z46wB>J^LVRO1@inr*bs@*s3UferjLctNMti+RvB!ovEdUARTzi_!yeuLC<_DZJ2Fj!!82dmH#I zh?iDqQxzfzGYx@jBYQ76=$}75-*6`+E{8f2-hKH?pT5ho-?m;@Upn{FZC?YI7=%1r zT34iPeQ`owZx^0e5I#PBe?y5tAg;~AM)LaG?d|D%jKWD*PFQI8+PE7q^H!o@^BdH6 z&r01rw=g*#rkUyQcs$xuX^vNXF#Rl);&ia*aao@QCq|+5LMy@d%?y$`?7Lq+RmGP- z2jTiQ6U;2xVi=F(VcT7Cw>`{;(=?3dap_5i=@fDLN9TpZ>x1LXe|hGwZ+vs#onETq z@LXM*ZX(Jwx=YSsiZtRyli#!rbcztxj+j}!OHiMnHcPz#0`FEv$Jl=Q0 zakntwel`jtSvoevU7yTB7B2_0_%|a-c^pBd9wB5R%>0kf-~blyKjv@B<^N!t(|%0=00000oQd{w)L)K7q~4Sz_(%@jli9{@}0hukj> zyjesUe4EnghY+QQ9-vBYKga+_j*HpMS zuzE)lM-vM%5 zV|vhabO)3m1b=n1?8?HU0V_W$pgwWk6B286!C4=d)B%Wi2TEt$>6+63HH=bVpwl~p z6_Aupy-5Q2!lI(H&ugzYgCn3WqnJ-4Xr_NDg-w8b2K=hqVqrQNJOgS5H-NJNzUsrV zbpT?rL||(p=h-&)6|Tz!5x?t_Kx4Xq2FPH&B;=zQIDZ_Vtlf)#!8iaXC028UG}E=T z1#k(wTj|-)oIaodvY+H^fLsZssxXsh9oH#9S}LGf901b7wmoGELY*66xPq8+BEN1< zdIhX}hXXDKQqr^+y%{|CG+c=K-zQ?8X#lakm^l9oALL0XYc^b zoO$0p(YVMvUHS$(S%InYU9HbHJ{T&mIE75a=(4{jr! zNr#hE!BMDsa`|i!sGShK_SQ~5e&lW=l8phsB=oW*o#&!&y57&a84OH0nw)_BTr8~0nChA*p48j9i1SK)8{`Q|@szW@^Y V6i2-A!q5N!002ovPDHLkV1iyc#}Rx2q5k66faPc|%%j000D6Nkltdri41{B> zHFdz^{onRzM)D;o$)4p0ZCd8@Xe66F9{+NQ;HLgT<)5VwZGRHC$Nc$CB+{SJOQjS2JPQ`2rA#n>{P-JWt_A5YKjsO8YAS51ZMB znopM+!d52kl*{Y6J`qB%YKt|OH&hQf07m!<@LE-AQ@UJn9i5yM7GwcAJrF^F zd<3|@d+}bVo`1j~2mE@{!WTf(g@x4x>jH40HK;=lRerwFH|QCISI_A=54T`R3d=Z- zPXG~55ApfnvHD|J0KkAB0HXlRPy>w_g5UrU^>Dyl2!a4LkNn}}l>h+r$MY^l>K|Hj z_5k32co=|7p}z&>oS8sf^r_E6ub~6-Z-A)%nf_TUbAQm1nr|&geNQO#_kj8&LS_J3 z_C)Iv7OVxf&huHH`5j<0K*CelLao@b9l#DY>}cUrl>i-LBu{|-F9N7EX@Egs6c_?~ z%%1B2zdbWdTYgWUAbLU2x=%v06XiS%kO^o6uMrc>#Mm(TLQWL<|ssFV`ezoeJY#qA?L16zx1FMq!%rW)V*VY~& z_11zN1l*B={YYHh;%66aJ_6tbGAaWQ=u>5Qey0T>T%X?oxz;Gk_5cGgUG?z%9)y-m zpS@Pjhk6e*4+OV!h1eGl|4y(Nla-nWAbMcQcYg%+_B*G?!}EK=9gR!@s1txDC=fX& z0Hu_70u7MBit7OM2&?ivBBGIorv|a6QaYgR`-XPqp?~;P`o%5S1BIwK!tagxT{khi z6R3$S^yw{;Ed!>HkRM#0F&V}Py;XsZh%)H5*S4%fX{Lt zegKSb8|sx9Vd{h61wa-00HBC@bc5k8^ndXJ=n*b}IsmTU?3##GPl85*(?CusIl$!- zUmUy=e~+&Eoqn_HQD<5TEn}EdJMR z6DN>=@!UQGq_1CJ_3Z`liJ+7ZeR(qgLI>OvbjW$omGWu;ujC+X_a0Qod6Ip@aDVUE zRZ6^(Q|MvhHv{qj;PhRtKv)QE0B#Cd0aF~OM=Gt^PKJ$bACymkX<#|Ma1!8aO4&yp zZ-lvZwEJEU(9&2#*_#Z4{<5$DioSHx--mV}maBEZ`$%d(l^u{?4&WFj``6_J{XNog z4v!4fYj{3ah8F*tx7}?i&549OEIt5%qjn-3(6(~7sRCd|(sKTmx*$r61NDAaYFY?3 jf`d>e!3#43?|}aRX3A)8;z9<300000NkvXXu0mjf_R=o< delta 1256 zcmV49IA;dGD z=l%yGgvSJasZs1tF}gj*g1~3O883!g`j^Bguy*_K9l$B#890k{OC#_L@2Gu9_%4C= z!Ut>`l>snYz6HNTaYL4X?z1WY_(3!KG<$d<5()So1c@Q&_yL_=HvteGHCYq@SlDlP z=)SG?FkVSCS$_=V0nl%NI02jho0KG(4*(!P6tqf$(Psc`5?^ZZI~CcH6MzuD3U~oX zfH?p@{~2{ZsbS^73&0@y{5$WTRDjUorN?goIA9*Y0YPEFRCg(~KaTJAOyeU4W}Z+F zK{++dr4-sP0dpEbNFd102vB>0c`jPk_McG%Vz(5OU4Ln>H6I5=tnA-_+)&YG52FjP zp8pNVxiughAQ#{d`!}HFQW_Rd%D6B8k4zzoqh1yYfY$PDa7lMuz_>lwN zD2_Ucub}Wco%jaq8##I~pS{cp2;5~$$|L2U!&#;ccLcd3nm3gFtPEy$d#KD%$>*bBFgpa8i5>ZP1= zOn)_m@aX;CXoSa~$eo0z2~%zk3|iiFDPGC$L#B-QBoGko?4-u>^Hh{P@?o`jl0;Ik=M2GcFV;&9G{G6*#UpFignBH8~GIN0lGM&^M5Y8LOxZ18s_^-v6g zCsNM+Ca@=!(N=Y{_S~)gVWa3H4Y=DI8WQ1U)qA^{yL}wPyyv38#W@I3^jeI~mVfow z<9wgVR}EZAAm&Wxei0@B88@N!2Cw?G$NUhocfvUcm`!ns{9XI()!_9B!2CGdN$G@L z%)FUo_QNhBV@=J4I4ejvlonf`P_Q2|Z;cuKB0C_=H6RZK1hA!%u3LQo z&gNq&*?)DTmxFNR$v#ygu-`rR$YE|PeRO+aB;)}|2Fc2>=w$wk;odneLgWTq5TeQBz+3e*7!o#t3D*kuBx**I_8?hb44jj^~Y zL47jYVZD`Y7fk|+(2Ek_`rV-2_Of~N4jlE+ic4OkRv-9-z^Nfj`;~!~sw)`ER#s_E zfF|BNa^p7*IDfL^^zQq*`3eHrX#X&Q@%_%Ad*ls1d|S)9w1!Mj1sN#E$+a(&T}z?j_L(mRG~=`Fiqb+FW(j% zUDrk3=YKz5I|yoX9|XK4vYNNMpZFo~$L%V0{^zYD5`V2q^?}z^!F2{F!?HrKiqxOk zTdeBTP{IqL9`gKM{hh%lAYutVoir5^mh$fR&kT()8P{XEP{VkdzcPRTNhAXgf{MS= zje7M(fh4VmE9&qAO!!MtfDD4+e?+mAfP+A_T=7D#S$zgYt7TnRxE-<43ERcmIL|sG zTV^T5uYbXTNUnHM<=XXFt!iAqE~PL($pZX`40^dA(iLe;SXt7I%pNm{xFR3=oAtmi znN(dSrU4X1LVR0J`QX4q!0{y>R4_;qgodx(($j$ek$|l+6T699_#~?Qw_wl(t#>jk ziLMMNenNIE3oCX1>IvRoEs!O4yo5SbG`WHYgMa1KaA9W%^mw5x)gOz&GeJn#G=PQm zf#5ehf`E;7S9q)99kR>vNhg8(_mKtlkdf?00>h4ajpn$a-VX`=mlhG3pg>v;d?9|> z*zBUZSTcN~5b?+Z2I5YDg1sG~NP=?_QHW|V%rlEG@vH_5JTU^n!qWSx8?uZ6Gm`@O zM1MQbrk21TVIae){(u7)48&s_1Q1b~PZ3lwoSHAu#fW!dB)Av|VPB#E;8|YrA$Br* z3N9y%@c3>S3CgnQZBFrMGRDcn-ohX)V}4}WBLTW08y*O{kf3_T;VC200Krcc2Z51M zvKSaCU|@F=aCQa!C8IeSBmrWH(;RTkWPcQ-5aAoP?5%nI+Z^tMd%OY~iF=Q7LNio2 ze?@Edm|=4kfAdA8LXH8Mb9T!BNqiK97(RQom%&H!{f;rhUKj>JIFKe*YuFwc?s$&O zI*-#g3c7aaf|qI>ZjTcr@}2s_eU%LJ9A4`TM?LCML@`|jXYjn<2@X8}F`PVmcz+%Y z@yTNNY*&#HB8i{$SB}35GBW3DCkqZgJ^C@8-|LK~KqIeMC(fIw^ zJ3&gwPbTLLf2*p&!0(Tshonpi{0$1K_&WjYr-bKc@Iv76qreZ@>ABqs5(4A;^bqa@ zbeyCFx+s30N0q+Mjq@`ccsbxOnqh-!NO(NMba3&T4b#(-17CA0Oa*UCV(`qGc{(Q( z-^PhkeDpX$4$?g*3^$D*_;cXI1j;NvWr%Wcjt&AJZG#tmJoaTBdCR-s;r{_|T}?s| SW^4xl0000J@gX|K z5aTZ?LKJ+$M6}`KeTooX1d>t$URA|Z+#fTcaeJ;vzN)vYZm24Vps` z{I(cdcZyZTM0grQIKvwOumOQ;wZ+t0S5TB}BE%#>*(n|j#EbMF{XrWW!1z>%f(YP* zD{T2b;8X;d-aGK!I4U*37}bTVO)tZM00331KYrk|)nF1n34;Dj0P&_?A;T$90-I@< zKUekJ*nb%ehUW8(p|_kt04x3S-b3yIyCNJNS~ow4MhPVs-5B&Q{7%5coFN501SDYu zn-mDB&nIOgMxwC&$Oqn{5L$~ZqJ2m=C9n;!(d45a>?sa>>nGkB7$ZKN0*nDGjLmNFkPC-p!Jt{ECby< zXiM))>o#be06|#35maAAqYDWH3phY9Zv^PQz5X1o=~_8{uw*e0u@FLRVSxaYAjJuo z9e=2hV-e7fW}yY0OUW9c#CM#RYU|qYXD(n0XziS5m7Ro$E-avPzpoW|xr2E4Br@pB*_ z{x@O-c2v(JII3@OGB17rCNkXoq)-c=Vqtc*(S)KaRWKPkDD1oO2g9x&5#XzO5q}^M z2HXf1PXZaZ);j~{;omXvZKP{81}<>k)w?l>&GWW_z1m|5+@5`#GzOmdIDi2gm}LII zosIeowowcMAq7v{hPEf_I|0qxi}I%!ff(O_zuoYH^UbF3MNL}?R*tRO<2-u9PYJj^ zecKZ$rP|BM{uWkc;%dLxl%_*=3M^xi7QQ`QF&wf|l@)-I^e+VNviJ1tmOni}Ijey` RJmvrZ002ovPDHLkV1j%UAYuRj diff --git a/graphics/pokemon/koraidon/normal.pal b/graphics/pokemon/koraidon/normal.pal index 151d848ab..ad38b622a 100644 --- a/graphics/pokemon/koraidon/normal.pal +++ b/graphics/pokemon/koraidon/normal.pal @@ -1,19 +1,19 @@ JASC-PAL 0100 16 -153 210 164 -51 55 62 -103 96 105 -237 235 230 -255 118 155 -6 6 6 -255 73 153 -168 150 153 -159 65 193 -18 26 80 -36 49 136 -0 97 173 -119 32 32 -255 70 57 -185 57 56 -253 214 0 +152 208 160 +95 46 56 +48 49 65 +14 28 103 +81 83 94 +255 127 39 +176 57 72 +250 80 71 +255 242 0 +24 48 177 +57 99 240 +166 91 227 +243 75 239 +186 183 171 +16 16 18 +231 230 226 diff --git a/graphics/pokemon/koraidon/shiny.pal b/graphics/pokemon/koraidon/shiny.pal index 2d198cf72..613608d4e 100644 --- a/graphics/pokemon/koraidon/shiny.pal +++ b/graphics/pokemon/koraidon/shiny.pal @@ -1,19 +1,19 @@ JASC-PAL 0100 16 -153 210 164 -51 55 62 -103 96 105 -237 235 230 -168 150 153 -6 6 6 -255 191 0 -168 150 153 -159 65 193 -18 26 80 -172 24 67 -255 11 119 -33 34 50 -82 83 113 -67 68 90 -253 214 0 +152 208 160 +28 29 42 +48 49 65 +96 30 38 +81 83 94 +255 127 39 +64 59 74 +98 98 123 +255 242 0 +172 49 49 +213 74 82 +226 127 103 +234 198 4 +186 183 171 +16 16 18 +231 230 226 diff --git a/graphics/pokemon/krabby/overworld.png b/graphics/pokemon/krabby/overworld.png index abe66ceb6f23e5f1a2767efd0237941f3c5e1255..f712b6f6ff16fbd9e82d5265d86fad74e07e7174 100644 GIT binary patch delta 538 zcmV+#0_FYK1-AqtiBL{Q4GJ0x0000DNk~Le000310000W1Oos701t<|*O6T*e*xD? zL_t(|UhR=VuA49vMX^_a!I3gFFQCtqm<<^G+cD@PWdU8mSEY~>6g-l;nG{gfBZzoH7JlD;`Rtqg%-GUJd2<|~U|%quS(u|`(d=bzudzFi0G zPZ!6{NQ|eksEIIPbpa2BaKvwrEh(vC$*Lh7&-I73@5_w!+4DI?t|qOg5t+@NXClm0 z!XMF~)e;7*+q@75t>;BJF4*JtxMdXz#=>!$4IAFv(}0Qw#X%tsqFG4*h=k)CE6)jR cczb{32OcVXK-Skw7ZwCq0A(3Y zBq*$KusE=y;lzmxFJAmu&=8Pid&Cwf!IEJ=%)F@g$1~CU0YtcUE3G?e~xkY?e3p&2orQo2&b71bi;?x8|U!O)F zu`Vv3=Izyq`*N^JEqHZJ#MM?#F!%Bgz8B6O^X4yzzIU^{*x6y~s_oZ}XJxQ^ ze?PD-@AVCn#DxJn-%l=JxmC_oa+gW0A=*M%@s(UgZtep9y-ZJk>y&uL_e|ojC@WbV zBvragk?|#8MyyYLeL`TX9p_(()RiC3R6erOk+mweeC%BodoFegW5rCdWqlndRo4ql z_^8#M_%A+2@txp&NBQZekNj9$wej1P^XsRy&0C~gcr{Du zxOB&{r?MyXcfJqo>FepAD)>-~!-DIhW4R~8q|TRon=VLh_&Px#Fi=cXMF6nqcqlOVV0b7{K=`=GSiqRrh?o!%5I~SGO> z000000ELCkAOHXav`IukRA_wjZ1JFis-(OGkc44A)1b{WY0;G1)0$7zR;l+`YrLt820T6N21en(e6i@X} z^MIVQ={0@s02+jxKf+LoBD8>PGf<}#y1dpqKq+~n;1}l>f)U8&HvlCNh4$n6pB4gH z8anO(dQwWE{IG^!20%tBxY3uQCx-S@n7IUrpjM>BD*zTk(GgTnL~QyyfRsQcE>a;f zM5)lVg{Sn}1^}%!Sp&)B@byf}i*^gxHr2ZZ@)X$@{npydltk;2SIl{%;@_H#sX6WX zK(V3b4p73}GeJXvTF-z<{Yk+nRBHb^`AiM~GozeBnA30Lk^(q~FbNoSuQj6y;aLP! zsg?rJB49*ZQA;UlHHA?#y!6pnEaGuJFkaBbXcge61Be9hNMUgrq2VQyZ-g)lsGdOs z1i*Y8n$icqo&YuqjRye}MbLG`5->oJK%9VfOHh5i08(H8N=3URi~x85k_a7eL!f#D zAb^Gr(4(Sn^&^2w58w|#m;q4nhac?#umFw{v|2wAWF41N(KG@UK;n?F+0iLLB$>k- zxHWE?!5JVg=MMyV4a8mN8<>9sU<2w6z;uY! z#^3RG{2QaMpAQ-+rn7C)lLm^87z1rFK53wsUOE8kzMlpl=G*K)Pw&((`j-cgQhVax zrF|2-fq$?v(Ef_NTQld$!a^(!2$S=JSwP(T2OQjaFUjSVp#1|5ZvWlA-!>rJzEf#> zVJ^}?pp$vOYe2Ytm%f2s-}(nkiMx590;sTb`(G+H_3x&?anDL1lwtqHfcr1hZuM4# z)=EUz`c4pp%3(oG1JKXT&|zM@AH3IV@50ZGuQ<&7WdDHr z$vJ2Jdo%;)`UieCwB<#Or2!EJVOAed#pbAa$KeBK*0lqm?uJv+|MP^dFW54WQ_2MQ zJ4=A751r2>@&DyO+&l*^FJRMKGb^!lwWa~8XO>wcttWfBc{u9Z08G!~7sPzS+M4r# z>UvUu^u7c!03Qgw0s=r&K$JKd4)eSONFhiH9Jom$<4(LK^b%UvP5^{o@{eVKk$dT` z_!B^Gfj)HPJAJ6})W?vBJ`zk1UwXP_g;?Lv*CTHuyam*9tXyuI#WS1$Zo=OJ3TObr z0q`8A0M$?IzF&IelFB8Aw}2||4PUkfz>3h9Wp&~20RH09WoH1a2z_Cf5Z(c*z4&Z1 zaRuo9#_a!l8x;vBV@)jW8?Pd32xkA|TOW0`#{%GS8+?l;_W!MozS?6F%NiJF9z6tQ z%md`oej7qMRW8OifXg>Z2O#_gm>V6CuSHk}1g|1L2tjW{@G5?h!xu&1F9A%%4v;O{ sG9br&Cm`FWT|cdj7>@_zzupG;2d9rbbYMJb3IG5A07*qoM6N<$f@8T}8~^|S literal 0 HcmV?d00001 diff --git a/graphics/pokemon/lurantis/front.png b/graphics/pokemon/lurantis/front.png deleted file mode 100644 index f73999e0d1470085c0540f2bafe3e8efff58d20a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 790 zcmV+x1L^#UP)Px#1ZP1_K>z@;j|==^1poj5Fi=cXMF6nqcqlOVV0b7{K=`=GSiqRrh?o!%5I~S< zczAgD`1rWExWG72U>GO>000000ELCkAOHXW32;bRa{vGi!vFvd!vV){sAK>D0&ht~ zK~zY`#ndrt+dvcm;1eFSO2X7&chO<2p&lA+wM!SPhXr1PiC4QqS~SQs=)m?;TF9DC zC8O2QkP{iwC4(ksum_+2Q{SoSP)X-3g}y;2^uBxVbR38NQ|OvB^ZSWSNnXKP{*(d( zK<#zi!Lk+x(U5&Y$gEMF?|DS4jr)WQ+-hL=p8$zuV4&C&$V&Jp*)`-ul&5ab^UY;k*u>f{aVqDRCcuCgLv zw@L@5hqyxq8sv*WWozRA{SS{OG|}}|5$Jl|x%0^EP5?qiHxGp$V1zh_AAWLp%+80^ zU`V=*vF@t}{RJVc2+-o%r6V0gI>)9rV$0%YsC313++-;=FmAA$eQCE;zJaqyDL2Hh z+M!acMCS9=CV_$T3IK;0o9~ui0pOQBk^sKE&p|~2)XYJ!P6dc$zz@=VL{;Et4i@=X z1r)LT?Avag9I4Q1F{(>|A{N(LvTIoj(E&Fu7?CYfOtgXvPY&R_MNg=gOBvXG;^%`z z0$^gioAY>@RszLL1W>wx57a7OF$Mr@yHjvTp@g+56~JPi08T)g*y36lK!+T-T!3PU zmYE8`=KwY-Uh#dQL{lu`4@k;DVQ`RE0(2aAEs&?x4i z(Z)I0XW3spRQmA@p*Va35zPt!Za4sH=nGKOBSe=a5DBo&!C1W0!ohwk8u?qp18|09 z5pVGDIGAFmN6!F?{&gVq3t^k_ Ua7E2JZ)uB!2;OQb$4nuFf3k0000mP)t-sn9!gd9VtdeWJX40|MCEgimbxE z-ynp)Rj%WVimVV25}ugK!oJ`C|NpS400000>%Bdw000ARNkl8Ds;ZK+21P{vPm_I`IuD7iSR5FMd>y44i%D3y;8igI{E3UMi^BKQl}= z+;C4^6?9~IY9L}{uPspir=fSxNRec1NM?Rv!;M4wn0JFo2f-+1aC=AM4G z%oluHu!GkTk&w*A>@#twz zpB-!{h$xQBV#weht}U5M5&3(OO^X=u+VIML*+gt~!NmoZh6P$I1zWt}eePolouIV% zuCUZEhJkbEb{;fjoMNnX1t|rd1yxb)yzU|bvmFrylz&*?D-azo1h3lZK2lKoA+9YT zphlrJ#ClPLs&L~WYq`ZyQOk0xghwR4A;T1FDMVlO&R{E|nP@6$+*y#; zl@!~?lFNsTtQ_p&nyn17T`Yl>473eyA5zflw%Vgg$1DL6EPXh>8Rj2UfF@vm+4PZf zEr8Z01Mx+9bb?!cPK^bHhTg3}i=eGKTA&>diGP6htQS}r+c^z57lxZqxQ`fyVA*cV zaL6F?9AHacfRElc_9bu^8tsT7aAkNZC?@zUQw|Sa;ncvqtD;k!`gRfoZUggk3g#HQ z_q%{2b-`>{M8J3aUxxI>Aa|c14LPNdoPypAdrKY(qzdfV1<>pHD}~ezlEvDyP{9ww zlz)N_`i5irquD{1!6cUs*qYuSIiVX5>h+g4e9v&)jn7Ta*i(OQecw}JQ>>!!{C>JA<_fy<4aHILs{V@gn%6O~A zL_t(og{9ZolB^&M2H=(@6R}F)|7}k;7F$}-L)G-$%>Nl6(0|V7a~f#B@bhwL5>tFD zASWpw|4YCav+$hZ>bZcJ6nG)X<6}|*m&XD>KhZ~8NWf)zAy6JUzaZzI13Yi!JY|=6 z0wZauCPeOv&|&j}nW zZHTrLsQC$i9|f?kW$WlTQcbu?ej|DSP=?~`+MEQ5YJS6G9SV|Pp_~MZ$_E2Op#gx$ z)(%>dk)U}2z|rKf6;ObCp#Yxp%fjon(HhDCIL0M(0Dp8r2?#JQAp@WQH-!r!IAkiA zFe-u9Zifn}fPn{0tOD%2qn`p$nvxh24;60b;P$-;ybJtX7LrtuMkTvKMOiU2u=V3?*)rFdH9#$cuorZJQ8^U;EzWkR0tx_WNrjW&~g5=kqKvn z4Hmip7k|LFK>>)!MYtCEC4k18{INl^npL4=(FLrLn>-(ZvNP>$dUun>+dN-Jd@;By zF$YLq@7cz1{rsmpfqb{}1YIrSCf@k`E97+$wJ3VF%3$?~%v0NI6sOP6*Z)hB>3WcWiB|6p>d|D`to7NJ@ddW>GDogeohOKuJF z?pGzCnO=U@OOQ%=uj`sa1%m5=r=RsfJ!bdox=N_a&>@U{3&dXmk+A7G|9sYV8~cY5 z2|D#KF!m$c#(!?(nx`j#D)fHMc||lCL}_ggkp8-cqCP?1eFzypFfgO|HSntU4H1MM zCPIK2T`Vv5`u7!h7)a1#_^c@#VL$R8RY`#FSak2y*IZ5n0$wXa5rCi}X)hWHa7O|F zz`qbyzqYJ7DY7|A6=0486#H>kP6k?OrBGiA3DC#$B7a(YArOF3D7O(Y+zsJz5jxbY zMvM?#O6d%k_4!0F^{nGt0HW~PVRSU2`s5%pyI=InI0G;}^)~>)H!lX5{LI5V^da6D z2+sysIhg|l%3KC>H-8QwKeWn15X9B!0H!!GdsZOW>Rx3xM|VW3H8p z*xrPNcIQDXiMALT0K)O+dg$(Kmsh=79@GN>kubuFqwWY81Yo~kXl5RC76Sohz+wr{ zsrPjU@NL8qCxH4s5!iEUA#)dE8v4|AT>9k`ae+SDZk80`jMfr}>6jtO|WP z7=IY?vP)P2p$`HQg@n-txC;zCEy;@gThD-Q*B0N4c_2Vwq0dId6_^EKatfQ$NTF{e z#rmpxo}uck3Dd$T=AmacyCjiGZNWsuyMEVDM-WQ0$*fSY2KHhW(gd)W@TFA-y?(cU zt^olk_NoE65w%(&O?{ku34JepUxr&0v44U%UeHnfZtCMmr5J~vhketwkHNS!s`?nm zWH6wk2KZ6t)XCQ0J$`WaS+!22nSOgo zFY`Qv{$~f*p?Wyr591$MoH=ES S%~PBJ0000i>|000nlQchF<|NsC0|NsC0|NsC0|NsBZA+nSJ00W{) zL_t(og`Jj-l7k=&giFAfs^I&-?d=AzKUc4K+_ZCc+>cENgn!%Z`>=s`{?va43}bDw z_O|N3^aSvuy6*?VPHcV9FK%Em$T`#_a#w?Z@S@+pgIQY!WML!@Th|4est3S!ZIMmWP#yrlYnolZ z+u8sKWi*c@w0{IR!0U$#8HU$!?RoETU=S!u) zL#d9%w*w7a0GK5|L}395Fi&F6;{ZPs%>$_ZT|b@z3zN&4e`^WImkb1#n=gQQ{^oc| z4=wdA0M?M|r40Jv#rz?F=`DTRcapClJuEc<%zxXqt?BOrR;qcfW6i&A+x>ob1pfI5 z5W(jG2!B;SSv5fU-4SPcG$GM+5VjTsijYgt^}+ak0!TOjAAoxgV!;Y-U7bic$$%CR zN<0A33n2xr;8wk-plWA&!NHMAZ2L9lEzZ7|nm%U45%lf0^csPPmzxu2xW1T&!ck+kc2|_(h*ne!Qkz$7^9mM?9*;=w+TNP@ZF;L^% zMrYdRqXQJSV(TqvTNUu$?34;PsD-bbefE8zS$8EZI|Bgs@cXWUH}kRWsX!5XLy4@j z>=9yuh>oM53H2au{z%XwkyrqVHa$KEV6o3v*Lt8LDeSDJFb7545?tskso$BF5I)=+ z>VI*JOD4$P65SI@23LBrxF!ytrHls6Q|t!j75rdAgTC*p_`gnScf;?T4BU zlw5i)N?eF>2U;5eTO!rBxqjj)kXn@-*iQhw?g+m`l}Zr0i%p(A23`+h*XN8K^=m^l zg18zN0-uk1rVcZfZh$pn;rEte225S--G4l{;jIK!rM?-fK3h6#515I!A-tcx3sr!Z zWk>RW3E{lIv?BED)Io?1;7|)srG7eU^;bglhOYknAbjf!4?+)EbN?yWNRQPzJ2T!l zW^5rP8|u;80?@|~l@P;Vldn;f$Msk{GY(#Jc)rO?$+fk7rhY@{`wy;{OEef|Ji*;>P+&cjgc6-hq&)NP*ax#za z{=VP+zTf@6dve$46Xy7OkN1Wk$X6SuP6T%q{~IwJTvO+m?t~7$C@b-K>xDI|F+)K3Ti0XxMz`dh<8b^7>2PzQtS#o3+MEVo*gtDQN%h zt0-+zr>3;>H4hB?Fix7#9FSBI;CUvrSsuA#*ov&ShcWUh+h}l5$LDC%->EL|)sy;NVu_RncFO_Ui7H6OV*7l0RB5%?~tLFTvYtv268C zv8Ssb#HQI4u&k>LAjo4S6BDD?#>Bix2_&*( z*+ymDX;skKjHFUQrC*+Zz(xJeJ2itIu01~pLVHBh50^Y}9SgqKrR-|=h^{-Ad`RS1yPc*sjlwcg$3Dpj zXbO)mIW-kann%CR-Ve(7*Zl`S2|qv7c?wsk>ASx*HjIK9t|8g72>?(g~c)K*n zquT81XsEler0IJ<^v6B%#hq~l+oSi6Xsr5DKDO|?1(~+L-Q9O+!xc|>PCD`}sv7A5fJ#>wP~1(Duxgq& zfq70M%bLq61p+V*zlhIl)9L!@Eo`3(Ko60Vu!%4sDl(fz13g$ylLtup0{T@CHW_rP zD3NBZxptD)S>_kP|%=oh)W!2qSx;c6?H%ZH~`D+T=gIAtXn3U@zd8N#S6 z8HOTRv^*S09BoZ+qCKWO=T!xWSdDZ|bt%cHyO}XO) zT)jhNHeoT+VE^bV*cW!@SBgPO(X?0^4oXRZWg${hCPoNSf+7Z5j*+B+kQ>7PgPpY+ zI0s>;ql`dDpcN=kw^s19zNMNzI2uPb&94KH3_)ec0LcWRzGOxGj`1Sf2+@D(5#a_5 z*kXWRuMKQnU?&vyZ-sq&@te+X_~~1R-*5&%Jv7NH={qFXkX)~%z$<}=s%uEDS5n}W zz(dvbf0N7mys3$KNkGwTy$=P$kXDCLf+s_2u$TCS!nvGd-! zu%r0qbhe@AeUG1)bsNT+mbAx5%xD?YP!*K15E))jk^Z}y&Zv3mP;hXe5L)LN?tmgw z;i9_h3!rr?CX|##bqpKk3Or{2X&h8Px3$7j$ohtq`P}!`zj^fX{`BWH`esdiVuC8* ztq}(*>!NFO8&;hg)i$mW+Bx>qw9NRjoD&b57f}Bg)^*EfTytQ3mF{rxW@yT&zlXZ^ zwTa(__fGJ5?*=#eqhFRxV4A{yzkP4+Ke>df%X^+RYc3j#Z|EDCkN@mf5cFy5S-rNd ze8)vf^G4(B#@2H2t@K&A>o1z>@+0*pKiDaLH0$=H2VV*vtCr1cIoe!v0hzN}Tc(+5u&92|e!3*HBvS?aUJcb_Ei=++z` z*NsXv*WZ_(SbF-BLSh%*3{CBs(w!El&iBwRYTvWv^@uNIQ1l7UErsL6lNtpFJJL!U z)TZm+HIIw3eN#8KEKK)I_S!Wwqou2Dixck|p5OWIbJ>0MG`>`{ngsR!=**&j1NZaG AdjJ3c delta 622 zcmV-!0+IdaB!>l%B!2;OQb$4nuFf3k00004XF*Lt006O%3;baP0000mP)t-sn9!go zC?G&UFc1(Bh(Itv7!bfv7}(h0hpG;7LS5R7l6|l(BD{Koo}$oqyQF5w$Z1N>+SlM_CJx zQ^!gM$7@`8&fLLn*C`7K!YK0bb64)&4%%hiRs7ax9HjRT%Y z&jTXf&l49Abq5J9K-z&PBM0Eg77+3}XCr_WxPjOToB-bg*RGBP$dojffCyXwQ?jZ? zDiBa%Z7Vo|3V#ttIx?T;_$Uh}u&@9Mn7gj<&;pNGIOg64H!ae*fLHw85#P=O0`X}S z2n@<(4EStTfix?Fbq7?GBfvM=+aDqKC4KwU@QCp7_U-TU4Ys%GcMqlRUu{v#U)vw; zBG-4=0YzW1%5JweYtqu`jcyeH?+Rs}@L8^3v8n9rdw<>m?+SjmUXycEVhL70Bdo4_ z0OJc96{aa00IXqJq9H^7ujMn)_cJrsV3Pxo;Q009nk`@S6b?X}!OP*l?AI-j(IFcG zy91FYnM{%_VuL*VECIgmrjXMnNZPG*ocnDF%N-T90Aw;80(@7RrH*pQ1sO6a^^lkr zIAW;1@Y{IIs-G=B{nHf-3iVZ(;~g%Q1e z_%1(f#PsX_ZGPG)&umvz!E1T;X(rdk7QiC-1q!&7hdw@zgHsd;3AmP@)gK-rf*;eh zoI+qLyB01!$*m#aLN2QlD6oTzQ%bA7k{st@N4TWLW>$MfU}zH;Cr!)ZZv~U|dA1{5 zqQH1;8y6>H4}YPIs?g&n5^#a{mC@J^-kfN?bK?6-;34<8W`%b9lzVY`X0-e|_~E5w zPCVPawpHHXn|;j7?y$^~BR{GdxRru!(t7wextX1mpiT`gw4~Ws5(>SRB*gm!A8ty@ zigWC7lV}Hp`f1VOl?>xYB8nqRvJfa=6yLbu1)@oF zjq5IjGb`6R>QJbD(ooHVHu+LdFe@a2-8$t)4C{A=LQvn7J85rdxZYAzV$#qbj`TV> zzEqUpR74u~PPf$jJ5st$pzk@J>WzIF9$tHo64>XiCb$LYSvNtbuRA_aIZqoZ&L*=kXz4t^k+-|6X|o^+BCn#VlmF^~TxD*lG)zk4!(W|~a)Dh;+U zvKp_*^8=G`K+4H#mB|Hw^S5-F&;gYd zg92jLI{FMUlKx8^)Y3gEpzv2;4rzlO-{%jJvauui-P%r6fRopcwvG4>P1&uuD}N95*%n3YEVZ~&H>*1IJ$vln zJt#bB3Inc^guV7NYLGPhnT6VB{g|H0UW{%L%D?z{@kWm)c&o}r8-pUguIiGN_0aZ~ z7(KTr9_-8hxgU1WFst4v{FWrFScFrWFoqeTSF)I73YY0{#O@El`Ma{w5PK~od$ir= zU_Kj{+ker(g5kSl#j6NiobP?@#`(fKZ+`E<^WBc%XUp+ZcDiT&^?G5-x62c4Yc(3U zdC)S|k}lkKSb$SrG{JnlU+ya${zLWdI*t>k_{XnoF2WRgW#zhFG=NdhbRIk43J_t* tw^Nfp@Ju5_OFgd19?wQJ#x(!;Hy~#o{q)QXstf=C002ovPDHLkV1jwFIf?)P diff --git a/graphics/pokemon/nickit/overworld_normal.pal b/graphics/pokemon/nickit/overworld_normal.pal index faa146c08..ff8c34ace 100644 --- a/graphics/pokemon/nickit/overworld_normal.pal +++ b/graphics/pokemon/nickit/overworld_normal.pal @@ -1,19 +1,19 @@ JASC-PAL 0100 16 -255 0 25 +128 196 156 8 8 7 -0 0 0 52 51 48 -21 20 18 -121 53 31 -185 90 59 -36 14 7 -255 255 255 -210 184 61 +91 41 25 92 92 92 -0 0 0 -0 0 0 -0 0 0 -0 0 0 -0 0 0 +136 59 35 +185 90 59 +210 184 61 +159 147 159 +223 218 223 +255 255 255 +255 0 0 +255 0 0 +255 0 0 +255 0 0 +255 0 0 diff --git a/graphics/pokemon/nickit/overworld_shiny.pal b/graphics/pokemon/nickit/overworld_shiny.pal index 50a884559..7327a9c8b 100644 --- a/graphics/pokemon/nickit/overworld_shiny.pal +++ b/graphics/pokemon/nickit/overworld_shiny.pal @@ -1,19 +1,19 @@ JASC-PAL 0100 16 -152 208 160 -0 0 24 -0 0 0 -8 41 115 -0 16 74 -115 106 98 -164 148 139 -24 24 24 +128 196 156 +8 8 7 +51 76 95 +82 75 73 +92 92 92 +122 112 109 +167 154 149 +210 184 61 +159 147 159 +223 218 223 255 255 255 -213 189 57 -90 90 90 -0 0 0 -0 0 0 -0 0 0 -0 0 0 -0 0 0 +255 0 0 +255 0 0 +255 0 0 +255 0 0 +255 0 0 diff --git a/graphics/pokemon/ogerpon/back.png b/graphics/pokemon/ogerpon/back.png index 8cd9136f9e142489ae9f2ba778bbd5499c0171d6..0884029493b01542fe9a780d953189e0fb5b3628 100644 GIT binary patch delta 687 zcmV;g0#N;f1iJ;07=H)@0001;w}I>c0004VQb$4nuFf3k0000mP)t-sn9!gsD=9#5 zHVE1q5b{+=fLzP0006xNkl+#5jcs>%=34I4!BDYz)gYz%=Z9pZ{ahLCa@Bx4+(-`3pj-j!w4b^F-#v?cu0-{n5N4X z5X3~wkPRpc0B0-=Am1HZ$OgIvfN*LCApkTBg+L!uBS4m)1IR)s2*k9mnSjX?gHlvA zT|Nf@k0JS52!EKUh*8z=46ucOMV|7F#ivveR{>D^%uv@TBfRLVS`4%V`wVSBWmJ9aRryH(Lk3(o z#Rvh63HBKV03m4WDg$GJ(Sm;mSa$%oA?Owu0A~QUA$A5bK}I)z(tu5fcYtQVX@It1 z16&_zB!AdiFae#=J2U{41p|N?K&2845%hN40qCa+plVmk^Grh|!?290=o_IQM7s5Z zThQ8$p1yT0BNd?f4@JK`7ql`Ahbz^WI02*zcs`$E;TX`~A|*k2e6oYZIFko}OxPrF zL|7c!O|Sq&7y!=E3&7hZsC!~R$qfMTvH)8P8Ys{=0TbZ$Qd>c(G~t`SRsZ#?^#f4} VN@DVE@T~v<002ovPDHLkV1jwiACLe5 delta 501 zcmVvJ-lYHk|6-&VQnX^E%@~VfIse{4-ke%|ds<@v00E9kL_t(|obA%RYQr!P2XMKA zy(TdfIv5f|=#UOIf^K~YgZ8wcB4lcp%D8xq1=;%w20uVOXn*UREs)Kx&}ZmL@n(tz2xS#KTmW9xzF7-#{PKWzf#0O#YgBL=4gq(YL9QOe-Rlx9ifsdR6GHg9C>74jR zen2+X1B56cvpn}O9vLIOcqX?jvH>{DZqtC(O|lRf!`RL>z{KMboiBtC%zM-Uw89TD zg}xAP`4MThFn{s-L-j?L9}V3WlovomPmV5R9hV@BAVdd}0tglXV6W}I#ls2&F=LF! z9gvn80aw)?5dbJgWLyj4G)-9xv@$F%!AT4OCA5GQKrT8AlKLx}TUtp8c}59jM+bI2pvu@5eN(Ivlt3_1CUk-Nql~>*z*Jy0arf?Z0pQZIWfLS^tUTA9 reV%TOta^aVfLIA`6j1%ffPYZGU^9f6(9)#r00000NkvXXu0mjf!~50Z diff --git a/graphics/pokemon/ogerpon/cornerstone/back.png b/graphics/pokemon/ogerpon/cornerstone/back.png index ffface9d68eb79b66fe465e3f7ec940a6be32543..a81975d346421c67f3283346a762aeed6532b601 100644 GIT binary patch delta 670 zcmV;P0%84}1gZs)7=H)@0001;w}I>c0004VQb$4nuFf3k0000mP)t-sn9!gd9UUwy zDL`;GOH52zU}}wGJ6o$UBC$-O%^m;RMgW$u0Mq%Dn3oU`5dHoAh)oxQ0006gNklQwD!zT3)oICcWrwtxTnPEoGkKXot>EFgyC4(u4<3=lnlQcxpkJUTm-}gpesxOz8Eb4)!DEBG;vgiK@MX6V%#1Y zAw6W2WD8OOsy}l6@qCi2V5*+y4!{a{UIWl3fOeOm0G@Oiu#xFt39vVe+-PJ0iSTd$ zMnPSva*_)m5gsmJRL}r<2?`*Ue=QA%bNa6R*B2kv4=M#j+h3OJdjJ3c07*qoM6N<$ Ef*O_&7ytkO delta 527 zcmV+q0`UE+1)Kzs7=Hu<00013M{Ml?001yhOjJeg=Cm;}F_fH?5D*YSb1_=1Fn;0F<=<-a-HW|D??ri()w~8){qt00E~-L_t(|obA#-OT$1I2JnLj zg=|?fUZF##wx`h1A#KG$m)<83E|95UAzh?`(A?&zqm5AEmVb^Seg!wbg0qW*Zs*8m;kbqp#C+6 zP73^81F#c7*w%Xn?4g{SaFc<^VT?hi2CQ^P1l5!)A_0;LA8LVPSr#jS(hd_!5Q{dT zgch&_$b+^6JAaGfDNQ>CvO)tkIk0uWv~nOSY8PQ{tbeEth+F`1lhqw5kckfT8bG$A zo8*RkO5RHj;);tVAa=-#UKK!uikI0V{Q{7c$o)ha@FB?n7%0$PoV|SvQa~6#a+6zswL0%@fTtB^Sh R%>V!Z00>D%PDHLkV1lFl;^6=Q diff --git a/graphics/pokemon/ogerpon/cornerstone/front.png b/graphics/pokemon/ogerpon/cornerstone/front.png index 9b7f2792387428bc1e2c71509de805da7ee5df96..7e1286799295204709889cfb5cb82168ddc3cf16 100644 GIT binary patch delta 905 zcmV;419tqg2a^Yo7=H)@0001;w}I>c0004VQb$4nuFf3k0000mP)t-sn9!gd9UUwy zDL`;GOH52zU}}wGJ6o$UBC$;9odW;bMgW$u0Mq%Dn3oU`5dHoAIC=Ds0009KNkl6faVUUdGn@fBn-U9? z$^*x2dVd&Td?S0ncRgCrg30-v<(vST0DN<9fYTBvYv3#w8(0jOFH)cY7DGtb4QbMsCVZmu@8Gk_;pMbMtkYodWaS)^U1RQVl31Foh z#!vw8&^PG2K9&wTL7#z3L(_mfB!ZkCSEP^C&_SONWBgR^r5uEO2R0Qu-(U<5rwoxx zc}>zH9HWgwxHl{fR?i6M&fFPb?QKqOS+Dd&FN^%B^sfOg$yZMt=&>RKxmDsBm*XGrf;kK-xL!&C0000n;0F<=<-a-HW|L&Xsi()ww2HIT!00TZrL_t(|oQ>5nNE=ZY0N@KJ zWc6JjV4eH}Z*a=xnafp03SO{Fg_3);i$m_<6@)?|!yR25B7fvf1<7<2p(!g#D8X*7__Zfq#7Iahja=QR+P!R*ST9heJ z7NQIScL^|q7k@g@Du!}&7lpEDgGW6O9!&LvAXpA%3K%m8FeuQOs4t}qWU2#hzl<#a zJb-o-*;4k#fCn=|RlqKEN&$@du@M38fPxU-5CqnjbcuL10x|WOG2Ei;uBS`jh$y9k ziK%|2*-}7^mME*$AgF(09`-Aot1j01h$sk;3PGvA)_*^$Rrs5(0%9<@7eoQiTf8_u zVqkx|!4j6(A%iM~6{__k@`xLzI1cyn?1JuxQHwHrO-qihVnj)=nDe#55@T_Wp+fZQ%zj z1C-eO{u<^5f{w+;fn^d>+HPasXROf?!z~O4rGRge(odDI^HyLX*hvE&SI!f)p7U0S zV0Sjv0WVavi9vgB`Lr0(5*LeShwi>#Y7} zF@V{@=_|?e=5&`zf1!3jvAYsT1#~QxbvJYw%AOh|mTF~P zr!MWDDxm4zl`wM<%-*LS#%8gZxG(3zh9#5{<<c0004VQb$4nuFf3k0000mP)t-sn9!gsD=9#5 zHVE1q5b{+SM(Pv0009#Nkl1Pm>dID&G`ZfiS7A^@8(1T88 z2BvSd(-m+|;HW}^dN>TzCcuvH8G*G1LgC*tKs6ay2*C7LK+hQ-)jp(pDuW|4MAXlW z!7wyh0JvS(Ta46`>uq$Z1;G?Xkb206=H-#h0B@NpPYyd^SCjenn$JmWx{H9UsbnTo&&t(TnaS+l;0{CQpzb^af}&|N6xNjuj55ezG7%Z>+BgZ-DDl;vL{8 z3-5sE7X16f&WAg|V++FX6Bf_!fX)jr16YUvgvXywY6XNdf0F=&#YbOG?jULqu^8q& za!*g|LDT74HX-Qj75f~ZCf|gRo}Nb$wJmG*bN_VWFNU5mN^go)zS19Y)lXZ>ZTkc1 WOgD8(>yVfL0000vJ-lYHk|6-&VQnX_3oB)erIse{4-ke%1X2uEt00VkSL_t(|oW0dQXxmsE2k@sH zX!b*?+=?^3s;E%NaPA8p$}NV6GoKD=wxamyuzTbTMK2`N!GF=%SxU<_*x|S%6x8Hx zUYfyMhD>Q8i??34j)g4VOz!vO*p+NK-TJ_`;C=l4z4y~Ugudm-O%9fR$ejPKJUO!L zxyfP@EICef7OX=2D$U&h%DFGVa$JP;89>Vlr8tLh45|p1W&zbHEf?_`gj;r1A@iUD zfKdsSTty=@tAALfe^xf6S@ST)4>XbjM1sF)NS7()J|P5?bcJQ|<0|dYwGA8tOp3FB zmY3JMo!y{G%iPBiWRM^UV1wnYZY$&f!lIA>H-1lpe5<`50LX`ih+v7Nbds)-Z*J{Z zxcn6&awX`eB6u^Oe?~E_a07rNchWdX2nF+yh0rSxz<)vXb4h|e=aYH7OoI?w&AdN! zal9A(^bR5#{cXX=MtKU+A+0dne!)aXe1HC*HwG|d9hE<&Y=e6Ec1Jgk_XNiOd`bZn zG@-`~>vvxKW*mz{BZ|R^oEL8-PyPj^$&F+pb?+<(*QBfy*u512b%=|LOeM? zgFYky3V*oQ#?MEiLj5r;;t4q;ECt{a2-(MvcX7dg+!4{=r+zvC!-0Nvd4U1Q3a6H@ zk;e8EDDlzeCB_#Y214K!%f&1SP+c5#_o5NL7>$NP9NLbnH&_y=MjUZ58hTeoTikLy zy??!gaie1Kx-_~9_}$B+gF_cL0E`o^PpJy~e}BC>+0FX14w~Y?(}&0>ZJr{W01T-m17a~ zgMX&(Kn3&MWG67slJ|xp*v?xoSF=G_@L^l&d89DJAW^k!2galOh^6PJi*;%am|x7f z$JlhkHMi!}?CihG;pt3u7R1LTFdiU=t2cl`6~6SvfB=9x3xQS~z_(wleg%-P0F^AP zF#$7A;^~Vc0004VQb$4nuFf3k0000mP)t-sn9!gpDJfSE z4?=S>N=izE7#PkuF^yt7TCFjn%^k*^Dfiw|0Mq#p5D@?W{{R30aeC`o0007LNklbJpzu?D_yGZP)$iN; z1YGugUj%_++ujARo)K(dd)or;dn056js?6$HUJS=KUsKaYzGj50fPm?UIEye0_+8# zSH!!%VjihYbS>aTR~jG;1Z$zlFE^%|!;a7vn*7p2+4S6`hG-VF{0=}ITOhl7GRe!kJhCCHtD(9jtGR+%7VJhMNT@(1%e|;Y9|Xh%|vcVmi-EzzD)9 zY8t)=1ertflL;89h*8wVfDZ`O!V6iRfP_(szC8lE1=c4-h^hcpf*Sx4WPK~oh26j{ zpsqjag%F+rN!E7&nc!X#x`|r}uzG-q!MP%eyy}xA@P7f&o~mFk#(vgn2Yo4}>01In1D@dOg;4dJz|D{of~zM2 zKr8_yftP_708bA9YZsM>ACzvhN355Z`fYD$} zkS$mOo`1Fy7z1O1nJ@xQum;8iV;kTJaLxeJ2GxR|p^vXFKwFp$WD79ylL2T8E&!)t z)x*Jp52(A~Com7R3uuJap$Pytfc!#}C+X24g32%fQmTNwQ2mkLlr^LS(jZUrIxMs5 zL8PlcEJsj?mH{xOrsdLr;{V0^L$^X@NJEvEw^t5G1z=lo2`EPzdjkIRDF9{R36KdU z!6g9D2M}QZ96n&Mpx>aA0TAIh)U^_Q3mVWK0s&COljBSVIvf_AIoIxdq5~lCAX9-y*PZ(SL+pE9z`X}Z zb;vA{qXcsVezs8pU87S04zMwm05_*{MrNA65**B{2ltlmHfo?}9+;^+V*y8yDpp8M z&!^KFV~ks%0)MbHhc?ANV_$d-1xU@+x9qb3fVRaND9Hia0eG#?v4)jhfB;2n4Glq* z1IBmwqWq&No=H-I*yfxQy9o@EgvE@Q$ZAH!2=a)4D1jY@A#Z@j41)-86n#JnCEz&_ zi}r)4dW-s&MpOV1p#Vt*A{8*g3SdO*5JnQleE|Ci@PCr0GYTL&DlqN<<&06@*Thre zE)_UNymtYdAtJ`7fKXaL=9n#NKtxh!PfHLGR)WEk1f%U8`F$z?c0004VQb$4nuFf3k0000mP)t-sn9!gpDJfSE z4?=S>N=izE7#PkuF^yt7TCFkYodU+3Dfiw|0Mq#p5D@?W{{R30!A=NQ00099NklkoDpL??t@X@NJJ##r{sxxITHhExuJb(V*pug&8`Wu4goHs&@ zy|V2t?+9@m`v~g$0H_4jkE8Sfa@{%QUjQ_lh#X)9Iq2yF#Q|6s`U3!0qSOh1$jQA9!ZJ38Tb~!Y$eRlFBle3JrmK3 zat{!6f`8Zapx%=O!42S0R{fx{xdvDRw76OmI=TTb^qU_uFv>JP)8ACLMN;MAgrY? z0XRyUyo^TBLfQeGac#hx30aF;R7Oz75m29bmw$kO6E&<3d>6d{+aL7mvW#T~z(eRa zpn5BUScirIai|2jeaZ^-s0rvRV)Uy>_$Yr^Mb(>V2p=iNv{hT*Pz$J}ic!KB+SQ9P ztex;P=WG4LjsXkCch+}$q9-~Or0?|xcuKqb#etrR4tV@zfi}Idz9zf?KK;nM2mEB= z6?V{X!QW5tBsl`QEfC&M&^*5bMsL6dKqD$3cE37_H4v%30su?hZ%(>arU)!J1mz5yvRK0OMh-t2zh!L2-;*I$mYiE zQSqdw{RO*v=+X0juW7e7O_e=p3i*Bd{k{H@Hj46JYvPf5;@Kl2ky(^)V=v=sokNbu zh@u_?QWGJ7h%rjbF<=qIc>`I-V26niY?GYl?UPKNvHSp#7a)-@KtKTZeHShL1&*wX zgYGuga2*0%qXoU(Tk?Gfyd`;77w+85CusHl<{IV@1%<;jtG0tLGXT&vVncxMpUtAv z_UsP;SATMn5m4ZE>+DGzp-myyi-w76egp{57N@`4?K|NXOBRa&l`LS)Kep!X0$;ea z)TpsRu!b>a^L%y=X606BwE>gw)O&+c*Kk&;^OLrJ%qp~G)c}MEy-TXHvZ8uUAdCj3 zB@@8W^Zq@CNS-m$lwKNX00i0zw;w2VIK$R8?SC@g0R%RD++QDe>rj8KYpYkR1IY7W z;O8?gT(-O3I@dJqIs_y?&|zFO`KCJ--0D}@c!!x&njVBTmk|8w1#N~uCCdi=-b zs(&_^N=L+ZT3FV-!mRQGU<5d9}sx(}Kp z>Vnu!By~m89t2dQx&+!Xn$qHWREoN}1)!*-*vD2fy<#B=REUbZ8Y(i;v>YTvmEyjq zii~L)ps48;GjY00000 LNkvXXu0mjf6u`8v diff --git a/graphics/pokemon/ogerpon/hearthflame/normal.pal b/graphics/pokemon/ogerpon/hearthflame/normal.pal index 2ed9b8c05..a7a922f08 100644 --- a/graphics/pokemon/ogerpon/hearthflame/normal.pal +++ b/graphics/pokemon/ogerpon/hearthflame/normal.pal @@ -1,19 +1,19 @@ JASC-PAL 0100 16 -238 230 180 -74 74 74 -213 156 24 -255 222 65 -65 115 49 -90 172 49 -16 16 16 +152 208 160 41 41 41 -238 57 41 -156 16 16 -82 8 8 +87 15 15 +66 115 49 +74 74 74 +132 24 24 +206 57 49 +141 98 59 +90 173 49 +232 157 2 +198 156 41 +247 222 82 +0 211 249 +16 16 16 255 255 255 -238 156 0 -123 106 49 -0 213 255 -139 98 57 +0 0 0 diff --git a/graphics/pokemon/ogerpon/hearthflame/shiny.pal b/graphics/pokemon/ogerpon/hearthflame/shiny.pal index 81f60abe8..4724e3d7d 100644 --- a/graphics/pokemon/ogerpon/hearthflame/shiny.pal +++ b/graphics/pokemon/ogerpon/hearthflame/shiny.pal @@ -1,19 +1,19 @@ JASC-PAL 0100 16 -238 230 180 -74 74 74 -213 156 24 -255 222 65 -65 115 49 -90 172 49 -16 16 16 +152 208 160 41 41 41 -238 57 41 -156 16 16 -82 8 8 +87 15 15 +66 115 49 +74 74 74 +132 24 24 +206 57 49 +141 98 59 +90 173 49 +162 205 29 +198 156 41 +247 222 82 +0 211 249 +16 16 16 255 255 255 -164 205 24 -123 106 49 -0 213 255 -139 98 57 +0 0 0 diff --git a/graphics/pokemon/ogerpon/normal.pal b/graphics/pokemon/ogerpon/normal.pal index f578e2234..943a658de 100644 --- a/graphics/pokemon/ogerpon/normal.pal +++ b/graphics/pokemon/ogerpon/normal.pal @@ -1,19 +1,19 @@ JASC-PAL 0100 16 -238 230 180 -41 41 41 -65 115 49 -74 74 74 -8 164 156 -90 172 49 +152 208 160 +44 43 41 +64 112 54 +15 106 67 +75 76 76 +141 98 59 +97 167 27 +91 171 49 +84 182 101 +232 157 2 +219 156 94 +255 218 70 +9 164 156 16 16 16 -8 106 65 -180 222 164 -255 255 255 -98 164 24 -82 180 98 -238 156 0 -139 98 57 -255 222 65 -222 156 90 +178 216 161 +253 253 253 diff --git a/graphics/pokemon/ogerpon/shiny.pal b/graphics/pokemon/ogerpon/shiny.pal index 02b6d9c5a..8fb51b7d1 100644 --- a/graphics/pokemon/ogerpon/shiny.pal +++ b/graphics/pokemon/ogerpon/shiny.pal @@ -1,19 +1,19 @@ JASC-PAL 0100 16 -238 230 180 -41 41 41 -65 115 49 -74 74 74 -8 164 156 -90 172 49 +152 208 160 +44 43 41 +64 112 54 +15 106 67 +75 76 76 +141 98 59 +97 167 27 +91 171 49 +84 182 101 +162 205 29 +219 156 94 +255 218 70 +9 164 156 16 16 16 -8 106 65 -180 222 164 -255 255 255 -98 164 24 -82 180 98 -164 205 24 -139 98 57 -255 222 65 -222 156 90 +178 216 161 +253 253 253 diff --git a/graphics/pokemon/ogerpon/wellspring/back.png b/graphics/pokemon/ogerpon/wellspring/back.png index d90a8afe3e1b8b657db69502f6348776e129a214..b9346bfc654471460a8881e8439e710112f92e80 100644 GIT binary patch delta 716 zcmV;-0yF)V1lR?T7=H)@0001;w}I>c0004VQb$4nuFf3k0000mP)t-sn9!gsD=9#5 zHcL!Qjbb}nt1+U@9sk-!3_*bpUbO>(0wz@f}UX*NPp%Kz)jFB#9<(r8KUIMH0pI{`!3MxsX(W&qOu!(F2`K=xU;r=! zs8|9Ofp5nJK$jYTb<6jRLuLl`7@_DpVH`wy^@r_3Ydc2zZD^~C0h<54=xRt8X2 z&ooW|G{EEWm==6Mdne#bP(Gj4!DXCD2apLO!9_-dYeRbo7Jvu}ux<3W*xMoSk2@$p y2u}+jEpWit1eFk;Pqr19iW5Hhx9Y!swY~vQ_Fah-DP0Tz0000WlPuCx7J!FJNzQ z`F;F;e;jDq|GDntdCT6p&-uPjm>f=wj;vexyOw}s5jT!KTx#Z)cSSrojvX&mgNJSb zz_|}$MIMJ}hXnQ>R)~E7VH@aV;Mg2i@S_l2!si4!U=&3VvmYaXKRS2R^%dYPV0xVI zoDmCX2hbyLO@9U>#u$Ya5TH$>O-5kO*eeRmO*DH`a~9xWOGFNsi#>(8on-|GT)xvV zkmP_-ccW?axhcNHyabDkQYx|*NQ;hzP^THO0FXxn0tH!`rnCVX9fpwLEc$>FD4;oz zi}r)0dW!m%Mp6J7fq;1h5)2q=1t6kz5ym`S^Z}RyfPb63>?nYoVBpvR%8o-m*X6(D zy;R^F@!18SLq;4gfgq%QnMXFR0U1fG6DdI;SP8VL0*BSZ&-b(djIyGk4b&T@^rZy4 z0+W?>vfgt5A1xi%K_b{Bw5;Lp`Kytq3XmO8E5U~XYF-Ptg7XJ&k&ItQlUySJ0000< LMNUMnLIPlds$=9I diff --git a/graphics/pokemon/ogerpon/wellspring/front.png b/graphics/pokemon/ogerpon/wellspring/front.png index 556f9f268872ac9c0ed7b15dbf7ca6ad3c9ba59b..4a7b6cefe098669f87948606fe2c8866a72d4a05 100644 GIT binary patch delta 851 zcmV-Z1FZaw2i^vd7=H)@0001;w}I>c0004VQb$4nuFf3k0000mP)t-sn9!gsD=9#5 zHcL!Qjbb}nt1;-E0{_}Z3_*bpUbO>(A_8 ze+dAI6TR!A0Az`Z@TPYzbN~QiE@22xAt_x59RP^CKId2n$gh8{XM*GK$nrh_iH-yo zx_*5;>M0K*y$9&L)dVJuogjMnB9D@EP)$lRMU0Vu7Jze@uLvb|3Fet!JeLpzxN6~o zQ1vr3;=)KUV1EUi6QJl*g#3ws;XwFARQ((?>&}o z4&Xa&wLy87Grnf{M8Fs)U5W)@;0n;^DBpQqv*HUv9*o;G;WZ!@y#eN#E(O8=!xpgX z3!w$DlvFE+A`~!9+ZRBipH)i{7-0k)Dez+iUja)4fPXlKzyLf4yukFl2<+`k2&)m& zjN3T+lN_D^%sa`$(f~$JElDaG5BgJpc&E#@D1b&VQcpyxMZ5wCAw@3S;(c9KCI|qf zDU&`UUI4HF*t;chQvm5@Q{ZNh-!d@oB>@VcF{pJ0kO?)=>S>{$0;&bGPEHmZff)#9 zfNq}Xg@2$H*t*GAE_2b36Y3O7nyZOJi$$FWvPdQt9R{s&@EjvoLIp5FO8VHN3n2m6 zVkCXSZ4d%2qz0gj_a2X^1V)HcYN)VnN+8A&u&yV21Wj|aZbk?(;H#cSaSJ#wz(%lD z0DFKNy)iflk$~pFTTmJ}4@SVRyCl;5Geh)-7=QFiH*e)?!Y*DA8o~RZ25;moi5B6Y zHk9!Aq(-kJhLi&zbDp2{qz#}rd1SrOI~S3ixV{tK2_Rzm>lX)ftWdz~Ckt-Z3+plA z4bXE;y$1Yb;T_O#LBCIUCpiMTEja!@;o|unFlYf502d+weD|jlN&z|28-QV<|I3NC z0Zi|lg$a(tqM! dKed$G_yb(kL7lKpx=#QA002ovPDHLkV1i0ouC6b(Lnx)CisFwz1|yU`;)uu;jJd&Mg0Z2U5`RMFH6g@WE85|pCV1(P zOqnw@9owd31`p}GljHhBYM@IWB!lng_kTK_WJUQe_2}^fK+_*+fN|#EK*}^<$pmaD zN;PKPqSO^ag9dhOcD+bxBs4vfX0xE!6oBr*3`W{vGgG8ma-D9i*!G;mVnA~%5_^o< zEH)vEpe|$e8Gm4!iWt%JeV@`*2DLc3-lS&fkb0fqwB<`+=U+|D=asvDCxB}CE{w=( z?$iZ#N^%+M^uQ2+j9MO}c(_2kT*T6XT0Q4FER*97RBd%Wx}$JI=%QYlJQ?CE#W`cr!c_%Uwzj;3Ho2 zU+QS#j7Y#k^ZxNsmk&XhJZv4@TqA_~5#S$2$A3~KZ8&gd*xrAtBeZapp9YFTmV{{U zUw;*#AAyMnR3(J?C4wOVog?DHI+=X_RBMwgW_1u6{E^D^I;3QvjizI$ohJ&JS&!P_ zEC%xoCBElK*2vbvm2P|rL7 z*n0y&Wr-R0VD>#3{m`V@5X26V))j>Q3NXUD0BDZwpty{zraKz|G@Zr%Y^7`SHWNUF zR&jSjWe%&0jf7T4+;ys~P!|mpwKng>ZUiZ8?1}~si?$=C2b?+q>N%N|SSnGIPs~jH Y27ghvGnl9eVE_OC07*qoM6N<$f_H?O%K!iX diff --git a/graphics/pokemon/ogerpon/wellspring/normal.pal b/graphics/pokemon/ogerpon/wellspring/normal.pal index b91b6ee25..f77173492 100644 --- a/graphics/pokemon/ogerpon/wellspring/normal.pal +++ b/graphics/pokemon/ogerpon/wellspring/normal.pal @@ -1,19 +1,19 @@ JASC-PAL 0100 16 -238 230 180 -65 115 49 -90 172 49 +152 208 160 +44 43 41 +64 112 54 +75 76 76 +141 98 59 +91 171 49 +232 157 2 +255 218 70 +12 65 129 +15 94 181 +3 129 229 +59 213 249 16 16 16 -8 65 131 -41 41 41 -0 131 230 -74 74 74 -139 98 57 -8 90 180 -57 213 255 -205 222 255 -238 156 0 -255 222 65 -255 255 255 -156 205 222 +156 206 220 +206 221 255 +253 253 253 diff --git a/graphics/pokemon/ogerpon/wellspring/shiny.pal b/graphics/pokemon/ogerpon/wellspring/shiny.pal index 4f4e60c15..f284e35c3 100644 --- a/graphics/pokemon/ogerpon/wellspring/shiny.pal +++ b/graphics/pokemon/ogerpon/wellspring/shiny.pal @@ -1,19 +1,19 @@ JASC-PAL 0100 16 -238 230 180 -65 115 49 -90 172 49 +152 208 160 +44 43 41 +64 112 54 +75 76 76 +141 98 59 +91 171 49 +162 205 29 +255 218 70 +12 65 129 +15 94 181 +3 129 229 +59 213 249 16 16 16 -8 65 131 -41 41 41 -0 131 230 -74 74 74 -139 98 57 -8 90 180 -57 213 255 -205 222 255 -164 205 24 -255 222 65 -255 255 255 -156 205 222 +156 206 220 +206 221 255 +253 253 253 diff --git a/graphics/pokemon/oinkologne/back.png b/graphics/pokemon/oinkologne/back.png index 81810c233fd613adf011c9bbca4fba2cf59b6386..42c6c3bf303b3eea890e9a7e4d606f521beda196 100644 GIT binary patch delta 445 zcmV;u0Yd)o1L*^hHh-DZrFdv?u253Qy0pQ1fcW6(a3Db0q^X!VXvmOI@KB(*xVR7y z5cueb`1tq$000*XWC;KO0cS}>K~z|U?bX|sgCGnAPy<20!T$f}P9j19<>ow&=b;Z> z>+B|Y>9V|e^QId(^0e(7NX2<(IH!_;nC|-@myQEUp;%VVOn+Ze8^BtB5Mazk86_Om zIou9g0Bqv~_gqDHuE826yQ%)2rD`}0LX7j;pb!5zW@sCzVCJdxQrlo+w14R)-uBi(=5eI?@$$`?tczK5|Ns9vJVExl z&G+f+|Kje0JX*q0!twwB0c}Y{K~z|U?bgeVgD?yQ&?-)YEP2HL|Lxcg2_Y{Gt!6Re zO5H&3sS{At*XzlXC*}YkBEaoBE-^O=t-s$ggyvSCdrQhi1An!$9CJZHS$WxoYXYXm zv2Pb}(63cv! zfCL~Bs6BnOjJdg)1|IZQg~=^!Fqt%q^Zcdw16-$_~7WcP+-WAP`J3b z@PLRA5D@t2i1_&U0001J*mukT00C%8L_t(oh3(eCmV+P+1<*o>K#l$X&mDq@U^RfV zoAIsGp4=vg9$&8~PyTZBn!DwsZ44?Rx>Ij+j4^7QAWYF30Dp`Dbr%SN_e`)baYg|q zQknS!`I0Cr8T$0cL_H9%UCWd-|y@9+V5ljJKH-LIO zh9sy#APBV9SAvyyQhgIKyx9S=K;uARY(VEtI2fzY0etO(iip3;6I=l+@hgCdIDtHZ z5`e_W^mq77$1Cfv$FlRtbNIZao3!osR2~>LOPX%Z*v`2qd28!%mL?pOc-002ovPDHLkV1f+*&1(Pv delta 575 zcmV-F0>J(11LXveF@G&kOjJdf(4g2*fcT)ukSIX-c#s$v80f&x*`Blbpa}Tz@Bjb+ z@!#V3$O!oO_^6-@Di*#DGh4QD0V_ zht(?49L5-&PSa0clXK5}Zk}%uithnHi~_h`2LWc3fACg}On-3mUBKj)Vs$yqWx}%H zUcn7N6Py#sasz;fAs{Bmyxi~u1kZ9@$@S&4-TUBftFAq+v9}Yi& zvTvk_pGpEUA_;nX>WvR$g7}+T}_V74nn0VIS)!2Ke4Air1I0ddP4+Y>SXfJPED{){-c{!_T)lod*k05dsab&;xiXC#lI~0)OO<0YK@5=dsc;Hq?IUmbC@@ zYsJU}to-feX#qSSKoMxD)c{T4@Yn(rll%h!ve|bLs#KX!y=@M%5uvUtq6sMZtq2t% z4X0`mI5tpL|3sietPyYo7!WEz+`uUWlmNlrfrda$fGPis=m2jCRfMwfxX(d+yK+y! z10W300XR+pjIYB9Kml2R6BQIa4G_%F+a-YEzqSPr0rvO#G2o|vpg;1CHAclEgf##F N002ovPDHLkV1i4e1f2i? diff --git a/graphics/pokemon/oinkologne/f/front.png b/graphics/pokemon/oinkologne/f/front.png index c3f10ed9f325e3c30e22176fa67146585769956f..a4841d6b0ff8b8b78f2a0778bb9cab2b3a0d209c 100644 GIT binary patch delta 682 zcmV;b0#*Hk2G0eMF@G>nOjJdg)1@dF7+5GMKrk>^KtOm%K!7kXuxMDgP+-WAP`J3b z@PLRA5D@t2i1_&U0002*GGJH$00K=(L_t(oh3%HxlB^&MMGXOjCi?%MJGr3J9vgAy z=~Q*PYDyXRViN;#n!fRk@rdz{`ci&{aL&~$ip2xKh~f}UZhxL<+HMHF_t-~(C^(#{ zT;S_q*D*#gLI(jp1S6=b;uOF+D89x=g3N%9h+GJP7Xto(O*|}XK>7QL0NxYjoJG$< zzV(L%UPI!4ljh=@0D{i~FzW&cyM>q%)qK(?01BSMCaLQnuv`#LTO3YduXMFD^k zk_~!$4B&$WoqxiKzSz4UjSxZ$07)d$6+pu+@s&)^t4=9~cK}Z=ucHUZeysq0^#*7N z*0fY!pL{tnPs2s;3u0BEnl#y~^p?dOA_;ZFcns~UZVAQ#N|5IPcLRJDJ+oklYJsGuJpmX&&cIqb zdKS`Sfb^1TfcDW}0PqdaJ(u^0Er8pdsbJVZOfg;nBJ%JEzwK zM8yJ8)8;FcF#vZrZcx=pIvOK?@|K|#Y@b!?BqPyzcsw>Ie~713e&c_P9~({}7Z3iT QQvd(}07*qoM6N<$f&i2)J^%m! delta 734 zcmV<40wMj+1%n2VF@G&kOjJdf(4g2*fcT)ukSIX-c#s$v7+^q1Kqx5qpa{rlSO5S3 zkXTUo$O!oO_^6+|_l#|*2F1bPY`e_zD=@+Gu0${7O{MydMcx!dRhUn zg22w94Nx{9`|Pl!hce1yV^y<|Km22w=V@vP{wx|^_-Fv0nChf724I>VkEsRNF2;U7 z8!$ko4PXrb@(Td0$`Qbp!NBsgXBL2oNS^$hTz>>$u79K6Ym2Lx^#sE7c>d*V{wFhZ z1RP7~02_Sz=^N|?2|?(nENnr&f&^}x?V@Egd)BMoGpk0RPCEeE#3hP zkwFC{eH-8q^G_Fmqy83<$_7j=;AG$qFsMHR*n`&@$fmymc<)qgdmGAbDAt2J^fEe#F zknDIQ-B?NM$uXu50Nxc+d9yRqg;mGD*ZZw&Hh9U^^LTgI{(W2Y8~-}K0FVkR`Px)C QcK`qY07*qoM6N<$f<9_aegFUf diff --git a/graphics/pokemon/oinkologne/f/normal.pal b/graphics/pokemon/oinkologne/f/normal.pal index ba2c645dc..2dc009715 100644 --- a/graphics/pokemon/oinkologne/f/normal.pal +++ b/graphics/pokemon/oinkologne/f/normal.pal @@ -1,18 +1,19 @@ JASC-PAL 0100 -15 -152 208 160 -216 80 128 -248 160 200 -144 40 64 -248 120 144 -24 24 24 -96 64 72 -64 40 40 -248 160 8 -200 104 88 -0 0 0 -144 88 80 -248 200 8 +16 +153 211 165 +40 24 24 +88 40 40 +64 48 48 +88 64 64 +120 72 64 +128 48 48 +176 104 88 +184 80 96 +200 144 80 +184 184 184 +240 128 136 +16 16 16 +248 232 136 248 248 248 -168 160 160 +0 0 0 diff --git a/graphics/pokemon/oinkologne/f/shiny.pal b/graphics/pokemon/oinkologne/f/shiny.pal index 9a427f2a7..ed20dc8af 100644 --- a/graphics/pokemon/oinkologne/f/shiny.pal +++ b/graphics/pokemon/oinkologne/f/shiny.pal @@ -1,18 +1,19 @@ JASC-PAL 0100 -15 -152 208 160 -216 80 128 -248 160 200 -144 40 64 -248 120 144 -24 24 24 -232 192 206 -217 158 179 -248 160 8 -248 240 240 -0 0 0 -241 223 226 -248 200 8 +16 +153 211 165 +174 80 82 +120 104 112 +193 122 128 +217 164 169 +200 186 180 +128 48 48 +248 224 232 +184 80 96 +200 144 80 +184 184 184 +240 128 136 +16 16 16 +248 232 136 248 248 248 -168 160 160 +0 0 0 diff --git a/graphics/pokemon/oinkologne/front.png b/graphics/pokemon/oinkologne/front.png index 22263f09036f9766a95bd0d10fb3faa7731577a6..d3fd42dd299046b26a129117522fd4b03c2dee40 100644 GIT binary patch delta 606 zcmV-k0-^od1c?QZHh-DZr63R}C?GH}C^$zxOh7nLa3DZlR%MttXvmOI@KB(*xVR7y z5cueb`1tq$005~+aYFzA0tZP%K~z|U?Umbd!ypVqV zT?36wd_sUipOcvo020$4Ko8~Plwbm#rb%+jAbb@71F#TQ08G-<56?j~OUfFjmr^nC z2EacVK+-Gc9e+VpaTP>0V=Fa=Y0}vM2 zwk$CM#H+PmTR$R>#^z_<!p32>6B}9O|8L92(}kR0%u%*=b%8jtyK`_(^E!yMF*J0~de|p{c(DtO()PfN-Wi zxzQ^^iI$u@0DHB4ZUC6ydfw@80qXtZs&)7Fy9R6sa}d|KQ78bQEu*yQF2D&zvNAw) z+d)|a>QDtJ8q31YZ{wO^FG8Nr4)irOw=LL6S`29I?E~oBKo>xkfet{qb3n-=-2g}u zX#j+m?pG_l6%OH|@v84{VPMnTeF*?UN*OdS^Gh6!d=H=sfT_$%u0_bZ+ZCySC}lib s8GLI_D#{TDfP*S_8__xEC;nl41LYkcPG~h{y8r+H07*qoM6N<$f=U(we*gdg delta 559 zcmV+~0?_@51=<9VHh-Mbq=R8G#ZZF~5D;KoYxdSb=5eGuGDuTVXdfXh|Ns9hD=Sx1 zVMIMtMnzwPJX-%^NUHz<0oX}IK~z|U?Uvz=gCG!uJ%+<@VtD_zys1|MRemPAO zn>ruEvVzm}=+UFUlBGVf&(wW}*yqT&HGBaOanTIWjS4X1@PB6Sedp(ha|75DN^!k1 z#x#uNKLJ>+wG)CjB89y_TK9m8V6_AI&3?0w=aTaTz|kQ9^&)_)0b0}mpjm+cu-2*8 zUjopgv&3(0DjxrkOHM;6Zzyeo;Um{sr)=Szrb*W@T|a0j~HfR;U0wrL$%L zmRQ^>0#>&pgnyi`+yYpB7Q+uAHDJ{{!l8efzP`VWCx8UC5nKz<$9@t(HyH~7sSKD~ z!0E#U$?pX)OTBx*X#}MH3=1I$ya1d>P_aL&Uf!?5y9kpka{VZD0p0+n<~h0!Xb5XR zgOf(+32PU?9d}|Oti`^z?hyb9S>5p004^867XJW%dw))}+fw;#9|S~IfcSgZzukWu z5D6tf1lTJxK%m?Nq=EqjAc-&>U~4$k0f5VZiXi(i>~Im&qUSjtPlVI0AflIgIX!}?v#{^d+z4V=6jTjARxUdDF6Tf_I0wH00009 za7bBm001r{001r{0eGc9b^rhX2XskIMF-~w2MjX?!4P%g0003*Nkl*%9r)81<}Hhy{pc*g{o2M>Kr{1|A?nG9yB~0lY!CBJluy1RjE` z#OQNoP;c?@{q)^;XUmMO>wi}kRC&ttAh3~(FuG*CWPaatdwiBseDyxT&g+FUqce>AzY( XOsY)IQbIt300000NkvXXu0mjfro+1G diff --git a/graphics/pokemon/pikachu/starter/icon.png b/graphics/pokemon/pikachu/starter/icon.png index 737fababd7d49b68955719525024863c8f2ff490..891f0d1b3e870760b696c9a5b4cb5ba286147e4d 100644 GIT binary patch delta 361 zcmV-v0ha!i1B3&RB!2;OQb$4nuFf3k0000mP)t-sVw{6}dwadTwEzGAb92q4toF2n zTJFV*#jGjz_9^yaQj~km#iY%>DV$F>70Dn_-fGS)T5hjWb2x%~w zhaL55?Qk}i(rCv<7kSdw34VYe*CnO_SxV5K0NE1d2y=$M_jl?0$P@`Uo9Z(xF zQqMY2?C3wm#|V1wuv1Kzkf3^Ly|?C$F~&Kdd6|KuelS#j9p?dOhwA8;=puvZ1dk=i5U**H}vwU~~O`{m084N)W00000NkvXX Hu0mjfnDM8! delta 378 zcmV-=0fqjA1C;}iB!3`dNK#Dz0D2?<0Dyx40Qvp^0D$QL0Cg__0P0@=06Lcd02gnL zEp)*E001yhOjJc;oP&ddbG^O2|NsBJq(S!fDb->@_LM1$d;ele&F*uY|Foo}#s6xo zoMK{HK|w)TsgPs<008t!L_t(YiS3lp3d0}_Ma7u($>jh4c7HLtQcWrh_OL z5#glt1)jZbP|F^+yF2_Mqg$^DnM-j$-AEb;oQ$4(z{4; zJrT1VL5!^NeUDa%;`(-{-WEjNUR-ZW=zj}{5|Sc9e`}pmgYY9-g+xX~eX#`$(9hsW z?DmLu28M*~!E=Tbjvuv+;IU?$eia>Z3utx&I>h@vCFXtqkBvacMr;Ja!yp@hj1f1l`oDg7 Y0hC4(vH__#b^rhX07*qoM6N<$g3({C>;M1& diff --git a/graphics/pokemon/terapagos/anim_front.png b/graphics/pokemon/terapagos/anim_front.png deleted file mode 100644 index 4ef2270bd3fc7ffcd871bdb2a7066ac9f84946e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1284 zcmV+f1^fDmP)EX>4Tx04R}tkv&MmKpe$iQ%gl!9PCikAwzYti;6hbDionYs1;guFuC*#nzSS- zE{=k0!NHHks)LKOt`4q(Aou~|?BJy6A|?JWDYS_3;J6>}?mh0_0Ya# zo%23%gq3BL_?&pcpbHW|a$RxxjdRIifoDdHY-XM~LM)bgSm|L_HZNsGzSbbDicWQdq~1&~DoH_pxoaPXPZjaHV(swH7e@NqV!Z z#g2f%ZQ$a%t0{ZH_D#NPe0^u?W1M(KqFRp<7^J&F!tTkJASrOI@XJfP+I| zyhPdS9`Ek&?d{()o&J6RQUP+ARLkv00000mP)t-sn9!gm8f-Blg=gmBJWQaVKyBn_ zwEzGBbE4}s$)im4%$elL=Jc)2`+z?(!vFvO$RMlR00092Nkl#o`BGSqu3~8Ia}j zuk2TfBM`)uhk&?bAHXJ&esj(bregRXguE;%0e~9-iB*c10BM30`~>oEn-Y?TK=Du8 zJo7M~0Jd4?p`Uy9&-SGiAQzoPxuEHNa*Z~R%70f1LOrb^(IO++EJ0k(`3EkfXQpm6v#B_k6u zKWG5xeUg95fT02?8j=xY9PF9;e>YoB6&tbPh$kHAK!&l*Wk0eU#% zXF%)pMp-TU3YMP$CA88AZOM6^*GrT<((#qobwfcXFetAg4oG_edfRkj`@%c8c`Oab!MHfCMeOe@bnxyt}kGd zcs*(N0Qq@vVd{(c)vH&p{-~bRp5ia~j3UhhUq?bO_}U9tJ)MA4A7S+n#F`hBrpW5* zX4DJ9;F`qU?-LzkiS8BI?YGL)eHgPpB$%88DVNBPjYFGOt` zXauQ01r0ELZJ>2$Cjse}JjK0kbpSHov&XTP&UDf3BFL>$`UX@p@>Fye|FR2&QSG{n zj#rVY9L^<+VEg{uKWNr$dY6{|0bcYE+8dn}XRZE$)XtX-1xSH+)jz;?(E=sf5U%8$q*waPPnG uAGGwl{z1e4_7C3vff3&R!4JY+#Qy-a>^qU`TAK&}0000 z5R~Hc)b;=W|Np=5zuEu*0h38YK~z|U?Uu=MgD?<8t;MdIh57%_%`6s)fdnB{;5gw;GAw{HET%8VJ+4`m#IuTl^ZMhWGmVq=UEnqS3Z34fTw&pbQ@ez4uX(8N}- z`hf(;2|5fCfeC^JPy&q;m`qqk2@Gx@ewr+S+F=5q8Rq;!m;xwa#-CDFjk{B=OI?;R zgt<*d7(u-4<~PD}mC*cahKq!h>sHS+8lVB57cv|Ks86{N;UGY*BHa;=0$7Aez=bg$ zuAt^Qfc+;r0e^^lfZ6-bHLXM1jUc;9*V$TxU<=3%Ab5_@V;JlV*!#1du+o9hGc<+a z)1FxmH|nT+uT;dmQSz!pI&I2QtVsku8Ob)#BmC;Ow~>&w8F?e(PrIiBIDA_$v#cUz zc%czsOTVrU4*6PXODEJgUT}_~^hdy;e`Qok@!`vNi#DpHnR2q*%>wKM8$52M`242SBLZG7>-# fpaXF0)}+1wb0Qi;Eg5c200000NkvXXu0mjf&Fbe$ delta 568 zcmV-80>}N81mgsdHh-AVpe7n@F(QR$=HWa{prAl)om!uO!Ul|Hi$eea0mVr~K~z|U z?bgwHgCGnBP@!lh*!cc$yFenK)i!Z=`zJK*!3-OQn7&ij(21fbF z1eRN?fOCvO$em5VnX1I(S_I^>2sm^?jFw)CfZGjgRzaHG1RRXZQU8sb!G2|QLZf8m zQ08I=cCGN*-W8B%0j2I45Nh2pC=#Y=%9r3mh|wtI(J8-D5kW#Q3IzC)|Dno)vjLo+ zIG+U~OhV`zV1FSvJ&+f!16G+u&%;V0E&z+HYI;PJe{s1oQy!91tx4ORoG4$=4pyu7%G6xC5*kkcDdiPUbI_k^m&!0G5T4GXsFvuM(W* zvzqfW3o-EKWj+O3o&`FguY`B`Bwx1-TncBvAy2~jFPmR|ax!3u0m5tm0000EX>4Tx04R}tkv&MmKpe$iQ%gl!9PCikAwzYti;6hbDionYs1;guFuC*#nzSS- zE{=k0!NHHks)LKOt`4q(Aou~|?BJy6A|?JWDYS_3;J6>}?mh0_0Ya# zo%23%gq3BL_?&pcpbHW|a$RxxjdRIifoDdHY-XM~LM)bgSm|L_HZNsGzSbbDicWQdq~1&~DoH_pxoaPXPZjaHV(swH7e@NqV!Z z#g2f%ZQ$a%t0{ZH_D#NPe0^u?W1M(KqFRp<7^J&F!tTkJASrOI@XJfP+I| zyhPdS9`Ek&?d{()o&J6RQUP+ARLkv00000mP)t-snbV~qA!#)=s6JK3RaMIJIE|A| zz$?9+D2l%<)3HH>^QGpQ5D*ZLkKEMt|NsC0GHhKm0005rNkl5LyuBSt z!_qUB5Ik`x0da3o9up5jJ0b3XlX_;NQ*uQdC$P5rU6qd#SkpVaZuce}P>qid0RHU)0Gm@rRe^ZCKa^hqJbi=E0k`*5jsXxuJP8bKzM+?3 zCFUD5rv*Wp2>0)-WmCUcgPiLLZ!OYIyc2wFZfUX&kRU2Os@V)3?Sh=$Q?dv|Q15N3 zr~o5cR5CeCNG~#+K@!{gl~M#AfI7dN3+?*3kghJhLtKwIzM7wMYlA>g)`B!Rfp?Jk z9lMsJQtt_1$6?ATX9?KI4WS49mPi+(CZ&fGC5igWn@#WpsE)?aNIzLq z`-&^VOhY3=>e>NSTb=R%2@LsC?$Nqq1tVoPQwKQkwF@c( z8xt+9hNA5Qa0uT2)9ncB(}pu^zWdd!uWns< ztPTqBwY45&jlTD%uDHSA0U+@fI6SaKpyB)M zWMB`#55!?!D?l3#Yz%|7F?dUJzYf@A`|KZp?b3(Ad}#OqI9t$XgGL9o1L*TXQ?2Y> z>nyOb&tUTpX8_KO_|W@Gq(MYFg$7X=ZonU+GkFl32hoTSm&fApz#txn&;1w?#&rDd zBQ}UHP37ekB=PbhYIPcgDi+1zOxfRW6wEjucw38qv)ev;lfx+AvV!XB>#{p#7b3z4VIKC~_=O4DV8h1Y&3@KoS#gWWss4%H z)a))&-rcHbpMaMZRmJiqzOb1p>l}GzFmauQC;j-k2+5VwqO))IZ)u`jJKp{7{Xu+z zl13yBpS%rzSpKqnwe(SSaiAkQGGe0pTD9%hhCeTT`(u7p!ss-=qXK=e)IOS)-b<0GT4gbaC@e=E&JJt zm%GC&ZYEy2Bz*S!MBS9<`6(Nb@ndfgPcLZ^b_(VmV6qw~dIyUdE-ZAvnA}3SvB2$G z$I;po0m;=2ZJx1vtTgJy=HGmL*N(%dJ}SKs?>p;la^<+F&dVF55B`yIA}!d;B;2KO z#d#Hpdh$6%Z@B?Z$&OX7`hkv)18UJLe{V}PMs_@Y|5|munGiBmw_TL6UI=o~qzVZ) zgiHN-h$fB#%QZ5TVv5sZ2ZrMdO|QaG#IozD%EH-Qj83WMi)(`ak*S7M5of} zWPl*+6V(RTL{{saF^XOeF{(#&Dy>1KQ4=vvSf+_L2uLI_Py7&HoK`CBr&sIyQ~-KV zO|X_qqd?TSIO?Y!dV_ZYAn6O}Pd)S@iCUBzjOsP* z9HFAIXdHm*!K$>+mc(vczXv8kv?@+(_5xymhBT-YAI17CHf+YcolgS+?)|)&76{++Z%5$z`Ern9k;qVTjG-(%2B44ROs>a)jrj(Z#{w zI8||QG)mQ~qsKp#hfVqt>X`ibVD z-WxRwUD*57`xvV-UnL^Zd?|P^(z^vcoPf&BaRRR1DMSgYqft;j`qK5oxav<*fi7c0 zFp!bVa8t0!Ob!hq%V;Rb2M(8^;Bq+#0y92m*J~68BdkL`qJfS;E0CV%-%vys^FdAd z9Bovh*eL+P$Pk+h(f(5~YTt&bSk3sbV?Oo2G~t^8pA;G3*E{Dmt3>aUA@k-lH$`YP8KDey($ui5ogt}jyHi@;yA>;EQ~^~cvKR1N+LGJ=;S zC{=wQs&)YV)*LHUo_Vn~H zJ-6a2dM=RWqHn#ieuK7mg;wr|%QN7AGpY0S`*ZHd0^=@VU*cF26A^(4kD%lnQ*^>_zy zVM+Y+wpaGH!7DbWtqoipA{0I-KUh+-cYW5Q(Ra?RtEd)x@IBkVZJhk>T~hM&s>p|_ z>PpMf#6z?1iz0``cMI+}b+)dQJ_#LWWA8HpANekDwL@Wh>(O&Lg>T%8Cns8NO*7TM zyCxF;F$~G`-8Jg0pJ;KBw?pWyuEhHJ9g_+98OG`E3;sA)k`x&5TV7FNYfEZ<{-K$> z#-#hCzKP`Cq6H|3`hR_TG@4X29kguZN!S*ktp`qJw% zWO;4tz60Fs`msC;HUg}bp9`2=qsoTojcfLM#-cHnY;8-{LpA$H1o+Z2F2;Zjfn^swp$JiO3 zRTH{jT06m|vV?N-#cE@agChKSTMnVAqtYhA!SV^UvTE9{7+e26#2j2sPR_4ers)qQ zEnGh5jcw+W;P4wg;wHNDnTvThej3zxYHy8I1|gH9T9}mjB;(Q1#ipq>E4rNH=cC&S zJeFUzOjDG7``o=|aN4)KFLt;i>x}6^=PYdX-lKB`QqdxfbI`dscEg=bM8_R(DOU2Q zKRzS8c`5M}+{!-vVs`8KgO`Q~Zx4xdaJ}Oax~3pPaSDX%Rv8Oe+*i(fzz6LB*Uq+rfm2U(ZIB!c9d`0Qge?Vn~4n^ z3Atizr|7KN^T=}{B6-hFFMSa$)371W!>19)n{*%SGS3RlmC|lg} zd;7}~D^GXL73`n+t6%%;&YCe%6{H2bZFBRwiKUyLP85c}Bri{`v@3nhY7wUQ;2aeB Vw^yuNkOj&bPU0OPKI|El@^8Fi|L6b! diff --git a/graphics/pokemon/terapagos/terastal/back.png b/graphics/pokemon/terapagos/terastal/back.png index cfa96b0ab0759268db77436517b04a7c45c58f88..083593c6fb55cb4bf1b73b1825ac4b6964b32051 100644 GIT binary patch delta 789 zcmV+w1M2*!CXfk`7$67(0001;w}I>c00D$)LqkwWLqi~Na&Km7Y-IodD3P-i0d)a? z{&{6`0000mP)t-snbV~j8XEUS8voTTJ$}GGRmMiq?CrN#lTN_DC{Zlau|b6MrRJFs z5D@jC-v9sqIKlEf0007uNkl$2N02!zih!f`;@@Bg-479=~FOq))Bb;kHy zoJji#&`Li)S6p$$6<7Qz%kcvThY z-w?REQ=z8bmcF9 zJpmv@Z$A>)?nt%au~U$sr0oya0LUkRWTtIt*sdL+0=#2kd6Y#%22f~Wb}z^;`50kv3WLaht{mWLj$Y)b*M{ki=? zu)TJUNhgBv%m~e40YeY}@}y!S*N987nl`^ki{|~nU2O5V&kmvh+bnZ`$Z6I~55oO^ z58a@p4WehKJx~wZ6Mk5VlKY+d1n_W}4rAy+@J$SZae>zI(JM^=SLTOx&GR*kcibwz z1|1Ho%PX(rk-`Lkum*tlOPr-?W@mQL?R)6Mjan&80xEa`fG}$i#Q+Yq?jx!X)q}J} z_H>;lwW9{%=qrGZ=}Aav3$cV`4Z`U#VJZ&OJK)uW1;ATg)245y(GS2L06DqXj(1d_ z8+qEsJoSF)cdP3uOCQ%|0wgX4$+I#xfdj7W9&d!MbrwGaF7K@Qgt+30|2}>JQ(-+Y T7@-rV00000NkvXXu0mjfF)nnI literal 4904 zcmeHLX;c$g7Ont-;)sZ-sIg54X#q`ANh+&EK*EwEK?Gz`Y^fwwq<}0W0Rk>3g0?6s z3gdvd;nJga$nii)<_A}%nB+qjO{t+diGEutf|%&V|E)91|boaujr^YU)J_ucQ^ z_r3cr6l=r7f=4+{a)cmglq^IV0eU~O+1Y~c*x-~F&^2JOGF&F}hK7R&fTY+#6cPg( zWsq${v4u#luRwDFHi;qIB+4*rzaH3=d+k30+p`yA18g?M1{wwW?Vxdh?F#xb(1}+#+}8)oB;5s4r{P8DG>J_)nUyO@!i1BysqNJwlBTSoJTIV`46sOzFQ=dOHnpCY?mDf_l9zTwpp?Ej$%y8OzyE&Zl^>MPgbCqX*K3Mb<^Llw#=Z8a-<7zgI z<}!UN`uCcbHEZSfpPZgY#m2>X%$~jzZqBaBkB{+L(G;H^_hjpQZqW|+jV^gVFr!Zu zF9_XWE)jl{B>rJ!X8wZfi?$zMxZ`;1HCrxh>v z#n#@)th?m<^u33{>seX$X60v-8)#K4+I-(h7JZBGnmqy|{9as4o&CL~joFYSy#DrB zQ$?8N30MDhM%QF{!jFaRLBV-bC^`4fT}%s(?66#!lJM^GCi%TB*%hlIMwor~>b#+V zO26(hL1l+1Y^sHN&D&^8rP?%Mbzi>D%vkdF!G{*2zSSYh$x!0AG2a*DpqYq@HO0z9 z#Y&xqiK=u8jA_>B$peFYe9d}PnT(le3M`S(O6aXs)pQ!6lF(y#a#*epz|=%YmH~^* z3X4)^B`ZZLy6Giy?`MzL8!xAKaCO%Ai@G%LiEETPAOJPObmFdD){ zm@p&IOr&$@vmI$Z1{E%jkOuWqfF}uEZ8GV_ELKKF1~Y@p)EN?4Y>`OBf;lV>hXD`_ zW2V-Gni*Q7J4w;QA;pYJ1EDt&IxUUlL>0O;lY~wO^R&MBGQkn{%hn;yofOg+Ymz>K;ygAxl&$FwH*!4xWGzrQ}skYe4AO3A`f zFb#kj!K&Sat5<0oQSfx`EDzVjs6(T;az;FhR!w3TrsbB`mhm{PTP^f?rA;uOckU>;3 zt+a$0Mrb%s0^G1v?c7A5l(5Lm~-Uc>ipda-E96GyfNwygW1?fCon&LKwmNnbx768x@JA_B{1GrV!Sv zM59?Rg&0-#Y{7`8V=8N$fU9RpsYbPl7^oh->Do6={6;FUIUs{@wt#^sa4rK;A|eJV zhCfI^2|j8ZiGvpd-)a6wT9mP+lLSGt?M)3P3Oh%xA#t z{}hbXyI~etGx~Py!}>2xe5`;$MF#lwjDg|>Y9Xt?81`yLmYv`6(|Z=b;|hR!Xpv9S zcSx=wxjspOPXZ5R*N|MFq`)VEhqCMcCYR&D>lCI1e+6ZLm!;V17pdSy3l0yB3M_6Y zUC49r&I}6*3cB+}oEKxCyl7|G*IHDx_}UHGP{tLsE}cQ-Pp7^>~QNMD3?1d{(m zpeW`BOQGChQ^8cmm#C5yt=Nw&!M zmycOhT6;Y!DevOqrOom`e6W2#)$?6?<*g63yEe6APOaR>nXR4QL@iYBUOm1}HDL{} zTFvG&?$z8)?$~~cm-h7T(em;F-VOJq*MB7nq)V>8JA5YnXr~5wzQV1QT`=*?ZC^Z5 zK&6g7R`QhtQ^`uKo>%?Ie8EucL_1J*;NGjw`Xz#yZZ~sF&wrhBEv!45iH2-A5 zqv(_0;dizrl;j9%l%kh$kZ*zrhZvg6pc0bd{^W4Fz5lL;WI_cLysIr^PPvN;>Ljuv+OMnxy!k~ zj-Gj?#hn#)6G>`uD;%@1b@i?f*HYgeoOD}oV5ju(D4VNGH$umsPmslCc-O5FI()xr zOzAPF# zo@;P+-TSAu29K*-iyvfn9R15e=u{vSviQ(p+$9p)u=MR2`mpMopI2IqQ;cv^N97f zfAjELDfDMdny)T$6M4SBx~#A<$ls2VQ-9{jD~r;poLY8I_xy#eC)KpNEqr&Iz1>mz z%cSVW+A=$f^PZ-IpS5R2SXx}2;{O%@X5wqn$wMP4NeyGCc!^IGin@kv_FcKl^+fYY QkgSj_Fid)6PD1v-0b+CC^8f$< diff --git a/graphics/pokemon/terapagos/terastal/front.png b/graphics/pokemon/terapagos/terastal/front.png new file mode 100644 index 0000000000000000000000000000000000000000..fbdf844767e75c862319014f7ce61695796d7bb9 GIT binary patch literal 1216 zcmV;x1V8(UP)EX>4Tx04R}tkv&MmP!xqvQ)@*k4t5Z6$WWc^qEZ}d6^c+H)C#RSn7s54ni!H4 z7e~Rh;NZ_<)xpJCR|i)?5c~mgc5qU3krMAq3N2#1@OU5R-E(;FK0s*Jm}d1P0Zq5f zY&s?83oByy6}<=`j08e5vy53u%D}h2?x~mRF3z+3`~Iu}wP-OQAQC5;VcNv&#EDJY z;Ji;9WffT^J|~_q>4LKlnXct28y~B}Gy|=*4k9#(?lH&}ul&_p#%&PJrMuaHV(r8%<#5lk`SM ziyZ-j+rY(jM^pBI%N=0&$&gLim4dW{QVDoJqi-qzL$^TxsyDaxIZhvd9L*|o0~{Oz z<7LWT^Lck)_uT&NY0vKmR1R{Q{&{6`0000mP)t-snbV~j8XEUS8voTTEiH^bRmN3S z%JN2;lTN@WioYz=u|b6MrRJFs5D@jC-v9sqIwMR^0008JNkl(D`YFoJtmkYBBTodK0*j3jj_nS z1QI+nGbZss1p_`cVTIoy=pDx*fR?+n6b=G1SW4I+hPQaNXgJQ23IOh+9SxRv)@2R8|D>l_pyhi2WxxfAM1(Fs>=h}sbhUmg; zUM52=T4sks=8F!~`)$le)AOb05Ky(}&pKpH513Sek)kqgLVNsY22?(skZ|R&oga~% e+WdF@r|S>e)H~k$c)N`N0000}NG1=j?S7&!<70001;w}I>c0004VQb$4nuFf3k0000mP)t-sn9!glNo@{3 zZ4eL;SWr+XC?KeynB?T-ue86BVHJOLC-|=b000nlQchC<|NsC0|NsC0|NsC0|NsBM zP>VwV00Fs4L_t(og}s*9vcn(o1`0=zB%oghB4~K2 zAypuI0Uldx{>PbrV3Z3G0W90yAYcVGIJ5G(%cfEYJPdpZ>h{O2fmXahP%=P#C2(a4 zjCdAk&No>!%TNm3l|WXMM&N&L1Umkk04Yp@{2=WL1;4N6FF(==+`hnzGN4AlhNgx# zqo6jlgV1KAt6{8SKYuDmVOj^Lg8SPG0W0cEDmudDO3a}Vj7%d`B{02|jtxrS-SeGw zs(^ud(ka^Fl)!M`daPlYfFb5_HwxxCve!nEaMJaRHwmD}b8~cyYC}4NdH4I4 zPO)hP>D*ylE~!mxkK3OX_q^F8+Nsz!O$r_EyS^GXMGA?>1NZ&O8lMgMa$W<&D2Q7$ z@blFma@_HL!S{m@<4p}MkGSA5u;DTVSkMEH%PvDt3$r?cKq)G<>V$aCi>WpOd1PaJZo}kJLnQxk)En5SO zRj2$IS#qWT%=DHBXzLMUC9ox`b5J5bOV&jK8UcA(1y%VjcBpUfPQR3I)MXB3&& z?Vto##EE}n?iekWs}5xlTX#g>1XVjtV9)>@nQhV33O0(rl)NDPgxeaZJWJpl%a=C9 zFerXrOn`d~bUQ=F0$(1*%`=k6Ofbe))I;1pnoD>pXZoLa_xNrs=;ku-==b{Wb$-TD zBxAO!F9*1pJj^esa#r3R0F#%q-ve~sslnys_Yy050Eqf}Ieoe?8m#7`Zjj$j-pGFy ZAz#+z9b9#Aq{9FJ002ovPDHLkV1l@F8_56w diff --git a/graphics/pokemon/thievul/front.png b/graphics/pokemon/thievul/front.png index 447aeaf02bbcb6814713859e7b962979ed6e0830..941b0b9a2a153789de96f30a16bf4889a1f3ab01 100644 GIT binary patch delta 760 zcmVc0004VQb$4nuFf3k0000mP)t-sn9!goC?G&U zFc1(Bh(JC-7!bj1LD<;fpOc@(lmGw#00000000000000000000*z?*k0000GbW%=J z0RR90|NsC0|NsC0|NsC0z)*`r0007JNkl(0f;LAdX;AYGMzB#PXJH#V#;@rq<_S(giKiUBOrLJf2EY8)d70_l7PD*dJF^ukjtO&{}ljM;}nBnOx7s) zH9$NQ+SCU^5V11mjMP*Ydz1by$C?=gQ%FX*-fG#Flhm`-{YJ1v67;F)aa3a<*lCv) zcSqa+7V}*m;rbmh@0_AfIj#t;Alv7*O=MQGW@w7IQHt2dF>=9E#;x^js6KBSrX2(Wd}9pH~WOn@==Sb~nI1h}~hpb~UAm`ZTy zpCxHn$$!-WM(MIp5?Esa!mt+CNGa%H0bL|4^Jx&H-TFE;B?*uRZ=rk2D z5vG-L0I=sfwf5FzJ3zdB)+LU6as#0ISjrt>ZQ3uSS+Rv3%R!aGW`Rp9>wtD{B>xDq zt<|>2{vsrQxlM!tz^ZnDZ%yBzCxA2ux1LWcAvMkb8Kcj+EP!24 z1F+=M#^U6&0h$1H`Zm@;lYAveslYOGot4|Sw7;vw^`>43Qa(`D)b9WrX5Xdmki6bQ qPyFTs>9(}m;kr$;P5c+XDgFVHu^IQishB4K0000Ia?h(Ivd*x=ZR0I;CAP)JY!00000 z00000jZ75g00009a7bBm000id000id0mpBsWB>pHl}SWFRDVdv<&@2C(?Af%*IInb zA#0Z+jvj|daI&*a8bl9}xDm&qHdZ+nJFA?LKpeP4h-lB1pjdqZ&KwE~FHq&Bm>qw_ zEpqw*ox{qz^P8Ff?v9t;A8X&?w|p~-I{@J}0}cX~H{Jq3z?_}!faOI&qrdGunZDTq zSe`Xe&dxSKD1Wt00*6Pt;%vS}WACXr-&Kp|bJ&N+u)A>lM&S4yz%ysjV75Ma_WV8g zM~%Sg+w-3Q!`r}vD0*2C*+=O4`s>ZGX{=OAMBDzPRMNi*7&lsKzO7hw&eTjVYc-~- zFiLUU>3LJB)vO}y(ywM_$|ZlX`n^=(nWhproK}F!gMV6=s~_rJM~#FK0K(S#HjriC zX*vR9L%ksq0{GM|qy4ftA1SpZ*3Aghw5m_n8tnJ2jf1k#ECkY+VMiKV%s))f+Q z4WNtVlwqC&7ujVAOi;wQ0+y74?O*))R>sG;-!v#|65S4 z20)#OjDJm)3Yh2HWb*F{9W#~eMPn0J0lEN~TpM5<*c*UutOA()fcZZ&JBkJcV0JOr zn@;U3b+Ez=CIwZFZvmJwSQ{Xccvr#yK&+D1FUC%y=xAsFk}%(BXveDG3UYvJT+h3z z0xVCdJ<}X^bjS!8(Cz8hMGXr?LI6KGWNe5nK7SZZ@Z|JPDZ+u!rOgQ(`>0_6T{W64 z#0K!`og*N87_dF)q|kj;10(?<4Y=F`7(qwWfFRreu6b9C)d1hbaY+j`pnO&=Y%?q$ zQUvMf8NXKp0%?Fynm-Kz4i5Q?62bxr(nX&s;9=A95D7PQNfX99zI4lU1TgM%FW@eP vFe>2ze#t^Grw<-5^vQBbHow&O!WjDp2JiC^_|{QM00000NkvXXu0mjfg7swz diff --git a/graphics/pokemon/thievul/normal.pal b/graphics/pokemon/thievul/normal.pal index 3f3b4bf6d..74565685e 100644 --- a/graphics/pokemon/thievul/normal.pal +++ b/graphics/pokemon/thievul/normal.pal @@ -2,18 +2,18 @@ JASC-PAL 0100 16 152 208 160 -24 24 16 40 40 32 +64 64 48 16 16 16 -104 56 48 +136 64 62 64 24 16 -192 80 24 -136 120 136 -136 64 48 +193 108 65 216 216 224 -216 136 0 -176 160 184 -80 72 80 +159 147 159 +197 148 0 +0 0 0 +0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/graphics/pokemon/thievul/overworld.png b/graphics/pokemon/thievul/overworld.png index c835302471590213b2bb7dd54ba74c9a83d344cc..53cf0b5b0e93e5ffd993f4a432d2f13556a7aef6 100644 GIT binary patch delta 785 zcmV+s1Md8+2b>0w7=H)@0001UMu)cm0004VQb$4nuFf3k0000mP)t-sfW({#2nRGX zFk2}ZTwGj;J0rPTJJPs4pOc^8+TZ{G|Nj60{{R60009300RI30Hu(oJ0000GbW%=J z0RR90|NsC0|NsC0|NsC0z)*`r0007hNklRtice~r~G@}0DpK}K28#wo%=J##R)cn55iI@ipC%AMW zpC1|UN&a*Fxeq-E_WLL&!UN~{>_pi?Fon2$e|B1mYUE2l9B;EZmm)CSZjh^48d#k) z$EGsCmjT!sb05gagM-oYBjUI*EmV!h^^7xmu<(xnoNz*0|vmC#x#g1^QU^ z99J_9G=DFC*2W=Fu2V!O#dF(C5_^+gf53y2jdFdE)bExH2L@>1xRi@_VvIWM0NrT41L4u-&Nwk(aN|5c zD4|{#Y9v4D!1|5`2GV>yHsBN(_UQB@1E!a@ai5=zKmP}>iWENo|LqSqToUu-piRpF P015yANkvXXu0mjfx(9k~ delta 930 zcmV;T16}-_2CN5=7=Hu<0002CwraKj001yhOjJeg{{RRG2Q)J<0001aH6Ile61iGC zBn}7v|NqjsJzQK|u&}TI000000000000004MF!ab00TEkL_t(|+U=H2PZL2H$Ddsm z77)vBQ7{PD_GA#SfCupfi)mtFjGR1~s9ylXK@z`&i5~zH;(x`9;!9#Y7^GsNiJ`E( zBsGDyLXZ|?*|s6lQg+v6x4ZMqLXADk9=7?-Gdurz=K0S|0S=$T=RbMG(#+Zoj6ioN zgBdqHK4w$Et9KSXq_s@OAt##x6(TSVs7IO1It18#0!+6ccHX%oH;MPnJrS#f2Ct}= zfVPtt;JKX3VP3C>J=VM#LFTu97-A>RC$|xgXn9ir5*yds-VWp~0h2vnh%G&$np=S! zVp!mtjDHCv5@IgzHf;IeYql{-n6Gvx;+$D(aa?nAX;S(<#>SAB87(j;Bd)x}EfpdB za7Go<;$43BGV=m4msL~6eW18Hx*Bw{o;?-`f)W&t1wZ*Q3&%f5_P+K+2gG0^>@gFu zcplU_lQ}{g8 zSwehN8O)*#b!G|H3S3|}1Z+%8Q5;Q6)=@F!1GY6lzBd@{{-MQ6BVWWwJ`Wz?f&o=d zNff8TU}vD`J6cCR32i-wWnAO{qs34HA)TWETVnwr25o_9$-(5X8+#802A}8!D1^oc zkAEqeDr3P3P0iSG