diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 328780f53a..6ba63f916f 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1877,6 +1877,53 @@ .2byte \species .4byte \ptr .endm + + .macro tryendneutralizinggas battler:req + various \battler, VARIOUS_TRY_END_NEUTRALIZING_GAS + .endm + + .macro trytoapplymimicry battler:req, ptr:req + various \battler, VARIOUS_TRY_TO_APPLY_MIMICRY + .4byte \ptr + .endm + + .macro trynoretreat battler:req, ptr:req + various \battler, VARIOUS_TRY_NO_RETREAT + .4byte \ptr + .endm + + .macro trytarshot battler:req, ptr:req + various \battler, VARIOUS_TRY_TAR_SHOT + .4byte \ptr + .endm + + .macro cantarshotwork battler:req, ptr:req + various \battler, VARIOUS_CAN_TAR_SHOT_WORK + .4byte \ptr + .endm + + .macro checkpoltergeist battler:req, ptr:req + various \battler, VARIOUS_CHECK_POLTERGEIST + .4byte \ptr + .endm + + .macro setoctolock battler:req, ptr:req + various \battler, VARIOUS_SET_OCTOLOCK + .4byte \ptr + .endm + + .macro cutonethirdhpraisestats ptr:req + various BS_ATTACKER, VARIOUS_CUT_1_3_HP_RAISE_STATS + .4byte \ptr + .endm + + .macro photongeysercheck + various BS_ATTACKER, VARIOUS_PHOTON_GEYSER_CHECK + .endm + + .macro shellsidearmcheck + various BS_ATTACKER, VARIOUS_SHELL_SIDE_ARM_CHECK + .endm @ helpful macros .macro setstatchanger stat:req, stages:req, down:req diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s index 03d72f3ea4..350ba2cc04 100644 --- a/data/battle_anim_scripts.s +++ b/data/battle_anim_scripts.s @@ -5,6 +5,7 @@ #include "constants/moves.h" #include "constants/pokemon.h" #include "constants/items.h" +#include "constants/battle_config.h" .include "asm/macros.inc" .include "asm/macros/battle_anim_script.inc" .include "constants/constants.inc" @@ -1893,7 +1894,7 @@ Move_AURA_SPHERE: monbg ANIM_ATK_PARTNER monbgprio_28 ANIM_ATTACKER setalpha 12, 8 - call SetHighSpeedBg + call SetAuraSphereBG playsewithpan SE_M_SKY_UPPERCUT, 0 delay 60 createsprite gAuraSphereBlast, ANIM_TARGET, 3, 0 @@ -1908,6 +1909,10 @@ Move_AURA_SPHERE: delay 1 end +SetAuraSphereBG: + fadetobg BG_AURA_SPHERE + goto SetHighSpeedBgFade + Move_ROCK_POLISH: loadspritegfx ANIM_TAG_WHITE_STREAK loadspritegfx ANIM_TAG_SPARKLE_3 @@ -2378,7 +2383,7 @@ Move_FOCUS_BLAST: monbg ANIM_ATK_PARTNER monbgprio_28 ANIM_ATTACKER setalpha 12, 8 - call SetHighSpeedBg + call SetFocusBlastBG createsprite gSuperpowerOrbSpriteTemplate, ANIM_TARGET, 2, 0 playsewithpan SE_M_MEGA_KICK, SOUND_PAN_ATTACKER waitforvisualfinish @@ -2391,6 +2396,10 @@ Move_FOCUS_BLAST: delay 1 end +SetFocusBlastBG: + fadetobg BG_FOCUS_BLAST + goto SetHighSpeedBgFade + Move_ENERGY_BALL: loadspritegfx ANIM_TAG_ENERGY_BALL monbg ANIM_TARGET @@ -2497,20 +2506,30 @@ Move_GIGA_IMPACT: loadspritegfx ANIM_TAG_IMPACT monbg ANIM_DEF_PARTNER setalpha 12, 8 + createvisualtask AnimTask_IsContest, 2 + jumprettrue SetGigaImpactContestsBG + createvisualtask AnimTask_IsTargetPlayerSide, 2 + jumpretfalse SetGigaImpactOpponentBG + goto SetGigaImpactPlayerBG +SetGigaImpactOpponentBG: + fadetobg BG_GIGA_IMPACT_OPPONENT + goto GigaImpactContinuity +SetGigaImpactPlayerBG: + fadetobg BG_GIGA_IMPACT_PLAYER + goto GigaImpactContinuity +SetGigaImpactContestsBG: + fadetobg BG_GIGA_IMPACT_CONTEST + goto GigaImpactContinuity +GigaImpactContinuity: playsewithpan SE_M_TAKE_DOWN, SOUND_PAN_ATTACKER createsprite gVerticalDipSpriteTemplate, ANIM_ATTACKER, 2, 6, 1, ANIM_ATTACKER waitforvisualfinish delay 11 createsprite gSlideMonToOffsetSpriteTemplate, ANIM_ATTACKER, 2, 0, 26, 0, 0, 5 delay 6 - @monbg ANIM_DEF_PARTNER - @setalpha 12, 8 - @createvisualtask AnimTask_WindUpLunge, 5, 7, 0, -18, 8, 23, 10, 40, 10 - @delay 35 - createsprite gComplexPaletteBlendSpriteTemplate, 2, 7, 31, 3, 1, 0, 10, 0, 0 + waitbgfadeout createsprite gBasicHitSplatSpriteTemplate, 4, 4, -10, 0, 1, 0 playsewithpan SE_M_MEGA_KICK2, SOUND_PAN_TARGET - call SetImpactBackground delay 1 createsprite gSlideMonToOffsetSpriteTemplate 2, 5, 1, -16, 0, 0, 4 waitforvisualfinish @@ -2525,6 +2544,7 @@ Move_GIGA_IMPACT: blendoff restorebg waitbgfadein + waitforvisualfinish end Move_NASTY_PLOT: @@ -3437,6 +3457,7 @@ Move_GUNK_SHOT: monbg ANIM_DEF_PARTNER monbgprio_28 ANIM_TARGET setalpha 12, 8 + call SetGunkShotBG createvisualtask AnimTask_ShakeMon 5, 5, ANIM_ATTACKER, 0, 2, 40, 1 delay 6 panse_1B SE_M_HYDRO_PUMP, SOUND_PAN_ATTACKER, SOUND_PAN_TARGET, 2, 0 @@ -3464,6 +3485,7 @@ Move_GUNK_SHOT: call GunkShotImpact call PoisonBubblesEffect waitforvisualfinish + call UnsetHighSpeedBg clearmonbg ANIM_DEF_PARTNER blendoff end @@ -3479,6 +3501,10 @@ GunkShotImpact: createsprite gGunkShotImpactSpriteTemplate, 4, 4, 0, 15, 1, 1 createsprite gGunkShotImpactSpriteTemplate, 4, 4, 0, -15, 1, 1 return +SetGunkShotBG: + fadetobg BG_GUNK_SHOT + goto SetHighSpeedBgFade + Move_IRON_HEAD: loadspritegfx ANIM_TAG_GUST @@ -7264,7 +7290,7 @@ Move_RELIC_SONG: monbg ANIM_DEF_PARTNER launchtask AnimTask_MusicNotesRainbowBlend 0x2 0x0 waitforvisualfinish - panse_1B 0x1DF, SOUND_PAN_ATTACKER, SOUND_PAN_TARGET, 0x2, 0x0 @ ??? + createvisualtask SoundTask_PlayCryWithEcho, 2, ANIM_ATTACKER, 2 launchtask AnimTask_UproarDistortion 0x2 0x1 0x0 launchtemplate gUproarRingSpriteTemplate 0x3 0x6 0x0 0x0 0x0 0x0 0x1f 0x8 launchtemplate gJaggedMusicNoteSpriteTemplate 0x2 0x4 0x0 0x1d 0xfff4 0x0 @@ -14012,7 +14038,50 @@ Move_METEOR_BEAM:: end @to do: Move_SHELL_SIDE_ARM:: - end @to do: + launchtask AnimTask_ShellSideArm 0x5 0x0 + jumpargeq 0x0, TRUE, Move_SHELL_SIDE_ARM_PHYSICAL + jumpargeq 0x0, FALSE, Move_SHELL_SIDE_ARM_SPECIAL +Move_SHELL_SIDE_ARM_PHYSICAL: @ Modified Body Slam, placeholder + loadspritegfx ANIM_TAG_IMPACT + createvisualtask AnimTask_BlendParticle, 5, ANIM_TAG_IMPACT, 0, 6, 6, RGB_MAGENTA + monbg ANIM_DEF_PARTNER + setalpha 12, 8 + playsewithpan SE_M_TAKE_DOWN, SOUND_PAN_ATTACKER + createsprite gVerticalDipSpriteTemplate, ANIM_ATTACKER, 2, 6, 1, ANIM_ATTACKER + waitforvisualfinish + delay 11 + createsprite gSlideMonToOffsetSpriteTemplate, ANIM_ATTACKER, 2, 0, 26, 0, 0, 5 + delay 6 + createsprite gBasicHitSplatSpriteTemplate, ANIM_ATTACKER, 4, -10, 0, ANIM_TARGET, 0 + loopsewithpan SE_M_MEGA_KICK2, SOUND_PAN_TARGET, 10, 2 + delay 1 + createsprite gSlideMonToOffsetSpriteTemplate, ANIM_ATTACKER, 2, 1, -28, 0, 0, 3 + waitforvisualfinish + createvisualtask AnimTask_ShakeMonInPlace, 2, ANIM_TARGET, 4, 0, 12, 1 + waitforvisualfinish + delay 10 + createsprite gSlideMonToOriginalPosSpriteTemplate, ANIM_ATTACKER, 2, 0, 0, 6 + delay 5 + createsprite gSlideMonToOriginalPosSpriteTemplate, ANIM_ATTACKER, 2, 1, 0, 6 + waitforvisualfinish + clearmonbg ANIM_DEF_PARTNER + blendoff + end +Move_SHELL_SIDE_ARM_SPECIAL: @ Modified Snipe Shot, placeholder + loadspritegfx ANIM_TAG_IMPACT_2 + loadspritegfx ANIM_TAG_LEER + createvisualtask AnimTask_BlendParticle, 5, ANIM_TAG_IMPACT_2, 0, 6, 6, RGB_MAGENTA + createvisualtask AnimTask_BlendParticle, 5, ANIM_TAG_LEER, 0, 6, 6, RGB_MAGENTA + launchtemplate gLeerSpriteTemplate 0x82, 2 0x18 -12 + playsewithpan SE_M_DETECT, SOUND_PAN_ATTACKER + waitforvisualfinish + delay 0x20 + playsewithpan SE_M_GIGA_DRAIN, SOUND_PAN_TARGET + launchtemplate gSnipeShotBallTemplate 0x82, 3, 0 0 24, + waitforvisualfinish + launchtask AnimTask_ShakeMon2 2 5 1 4 0 8, 1 + waitforvisualfinish + end Move_MISTY_EXPLOSION:: end @to do: @@ -14024,7 +14093,87 @@ Move_RISING_VOLTAGE:: end @to do: Move_TERRAIN_PULSE:: - end @to do: + loadspritegfx ANIM_TAG_DRAGON_PULSE + monbg ANIM_TARGET + setalpha 12, 8 + createsprite gSimplePaletteBlendSpriteTemplate, ANIM_ATTACKER, 2, 1, 1, 0, 7, RGB_BLACK + launchtask AnimTask_TerrainPulse 0x5 0x0 + jumpargeq 0x0, TYPE_ELECTRIC, TerrainPulseElectric + jumpargeq 0x0, TYPE_GRASS, TerrainPulseGrass + jumpargeq 0x0, TYPE_FAIRY, TerrainPulseFairy + jumpargeq 0x0, TYPE_PSYCHIC, TerrainPulsePsychic +TerrainPulseNormal: + createvisualtask AnimTask_BlendParticle, 5, ANIM_TAG_DRAGON_PULSE, 0, 12, 12, RGB_WHITE + waitforvisualfinish + playsewithpan SE_M_PSYBEAM, SOUND_PAN_ATTACKER + createsoundtask SoundTask_LoopSEAdjustPanning, SE_M_PSYBEAM2, SOUND_PAN_ATTACKER, SOUND_PAN_TARGET, 3, 4, 0, 15 + call DragonPulseParticle + call DragonPulseParticle + createvisualtask AnimTask_SwayMon, 5, 0, 2, 51200, 24, ANIM_TARGET + createvisualtask AnimTask_BlendColorCycle, 2, 4, 2, 2, 0, 12, RGB_WHITE + goto TerrainPulseEnd + +TerrainPulseElectric: + createvisualtask AnimTask_BlendParticle, 5, ANIM_TAG_DRAGON_PULSE, 0, 12, 12, RGB(27, 27, 0) + waitforvisualfinish + playsewithpan SE_M_PSYBEAM, SOUND_PAN_ATTACKER + createsoundtask SoundTask_LoopSEAdjustPanning, SE_M_PSYBEAM2, SOUND_PAN_ATTACKER, SOUND_PAN_TARGET, 3, 4, 0, 15 + call DragonPulseParticle + call DragonPulseParticle + createvisualtask AnimTask_SwayMon, 5, 0, 4, 51200, 24, ANIM_TARGET + createvisualtask AnimTask_BlendColorCycle, 2, 4, 2, 2, 0, 12, RGB(27, 27, 0) + goto TerrainPulseEnd + +TerrainPulseGrass: + createvisualtask AnimTask_BlendParticle, 5, ANIM_TAG_DRAGON_PULSE, 0, 12, 12, RGB(11, 26, 11) + waitforvisualfinish + playsewithpan SE_M_PSYBEAM, SOUND_PAN_ATTACKER + createsoundtask SoundTask_LoopSEAdjustPanning, SE_M_PSYBEAM2, SOUND_PAN_ATTACKER, SOUND_PAN_TARGET, 3, 4, 0, 15 + call DragonPulseParticle + call DragonPulseParticle + createvisualtask AnimTask_SwayMon, 5, 0, 4, 51200, 24, ANIM_TARGET + createvisualtask AnimTask_BlendColorCycle, 2, 4, 2, 2, 0, 12, RGB(11, 26, 11) + goto TerrainPulseEnd + +TerrainPulseFairy: + createvisualtask AnimTask_BlendParticle, 5, ANIM_TAG_DRAGON_PULSE, 0, 12, 12, RGB(31, 24, 31) + waitforvisualfinish + playsewithpan SE_M_PSYBEAM, SOUND_PAN_ATTACKER + createsoundtask SoundTask_LoopSEAdjustPanning, SE_M_PSYBEAM2, SOUND_PAN_ATTACKER, SOUND_PAN_TARGET, 3, 4, 0, 15 + call DragonPulseParticle + call DragonPulseParticle + createvisualtask AnimTask_SwayMon, 5, 0, 4, 51200, 24, ANIM_TARGET + createvisualtask AnimTask_BlendColorCycle, 2, 4, 2, 2, 0, 12, RGB(31, 24, 31) + goto TerrainPulseEnd + +TerrainPulsePsychic: + createvisualtask AnimTask_BlendParticle, 5, ANIM_TAG_DRAGON_PULSE, 0, 12, 12, RGB(27, 0, 13) + waitforvisualfinish + playsewithpan SE_M_PSYBEAM, SOUND_PAN_ATTACKER + createsoundtask SoundTask_LoopSEAdjustPanning, SE_M_PSYBEAM2, SOUND_PAN_ATTACKER, SOUND_PAN_TARGET, 3, 4, 0, 15 + call DragonPulseParticle + call DragonPulseParticle + createvisualtask AnimTask_SwayMon, 5, 0, 4, 51200, 24, ANIM_TARGET + createvisualtask AnimTask_BlendColorCycle, 2, 4, 2, 2, 0, 12, RGB(27, 0, 13) + goto TerrainPulseEnd + +TerrainPulseEnd: + call DragonPulseParticle + call DragonPulseParticle + call DragonPulseParticle + call DragonPulseParticle + call DragonPulseParticle + call DragonPulseParticle + call DragonPulseParticle + call DragonPulseParticle + call DragonPulseParticle + waitforvisualfinish + delay 1 + createsprite gSimplePaletteBlendSpriteTemplate, ANIM_ATTACKER, 2, 1, 1, 7, 0, RGB_BLACK + waitforvisualfinish + blendoff + clearmonbg ANIM_TARGET + end Move_SKITTER_SMACK:: end @to do: @@ -23296,17 +23445,50 @@ Move_SKY_UPPERCUT: end Move_SECRET_POWER: + createvisualtask AnimTask_GetFieldTerrain, 5 + jumpargeq 0, STATUS_FIELD_MISTY_TERRAIN, Move_FAIRY_WIND + jumpargeq 0, STATUS_FIELD_GRASSY_TERRAIN, Move_NEEDLE_ARM + jumpargeq 0, STATUS_FIELD_ELECTRIC_TERRAIN, Move_THUNDER_SHOCK + jumpargeq 0, STATUS_FIELD_PSYCHIC_TERRAIN, Move_CONFUSION createvisualtask AnimTask_GetBattleTerrain, 5 - jumpargeq 0, BATTLE_TERRAIN_GRASS, Move_NEEDLE_ARM - jumpargeq 0, BATTLE_TERRAIN_LONG_GRASS, Move_MAGICAL_LEAF - jumpargeq 0, BATTLE_TERRAIN_SAND, Move_MUD_SHOT - jumpargeq 0, BATTLE_TERRAIN_UNDERWATER, Move_WATERFALL - jumpargeq 0, BATTLE_TERRAIN_WATER, Move_SURF - jumpargeq 0, BATTLE_TERRAIN_POND, Move_BUBBLE_BEAM - jumpargeq 0, BATTLE_TERRAIN_MOUNTAIN, Move_ROCK_THROW - jumpargeq 0, BATTLE_TERRAIN_CAVE, Move_BITE - jumpargeq 0, BATTLE_TERRAIN_BUILDING, Move_STRENGTH + jumpargeq 0, BATTLE_TERRAIN_GRASS, Move_NEEDLE_ARM + jumpargeq 0, BATTLE_TERRAIN_LONG_GRASS, Move_MAGICAL_LEAF + jumpargeq 0, BATTLE_TERRAIN_SAND, Move_MUD_SHOT + jumpargeq 0, BATTLE_TERRAIN_UNDERWATER, Move_WATERFALL + jumpargeq 0, BATTLE_TERRAIN_WATER, Move_SURF + jumpargeq 0, BATTLE_TERRAIN_POND, Move_BUBBLE_BEAM + jumpargeq 0, BATTLE_TERRAIN_MOUNTAIN, Move_ROCK_THROW + jumpargeq 0, BATTLE_TERRAIN_CAVE, Move_BITE + jumpargeq 0, BATTLE_TERRAIN_BUILDING, Move_STRENGTH + jumpargeq 0, BATTLE_TERRAIN_SOARING, Move_GUST + jumpargeq 0, BATTLE_TERRAIN_SKY_PILLAR, Move_GUST + jumpargeq 0, BATTLE_TERRAIN_BURIAL_GROUND, Move_SHADOW_SNEAK + jumpargeq 0, BATTLE_TERRAIN_PUDDLE, Move_MUD_SHOT + jumpargeq 0, BATTLE_TERRAIN_MARSH, Move_MUD_SHOT + jumpargeq 0, BATTLE_TERRAIN_SWAMP, Move_MUD_SHOT +.if B_SECRET_POWER_ANIMATION >= GEN_7 + jumpargeq 0, BATTLE_TERRAIN_SNOW, Move_ICE_SHARD +.else + jumpargeq 0, BATTLE_TERRAIN_SNOW, Move_AVALANCHE +.endif + jumpargeq 0, BATTLE_TERRAIN_ICE, Move_ICE_SHARD + jumpargeq 0, BATTLE_TERRAIN_VOLCANO, Move_INCINERATE + jumpargeq 0, BATTLE_TERRAIN_DISTORTION_WORLD, Move_POUND + jumpargeq 0, BATTLE_TERRAIN_SPACE, Move_SWIFT + jumpargeq 0, BATTLE_TERRAIN_ULTRA_SPACE, Move_PSYWAVE +.if B_SECRET_POWER_ANIMATION >= GEN_7 + jumpargeq 0, BATTLE_TERRAIN_BUILDING, Move_SPIT_UP + goto Move_SPIT_UP +.elseif B_SECRET_POWER_ANIMATION == GEN_6 + jumpargeq 0, BATTLE_TERRAIN_BUILDING, Move_BODY_SLAM + goto Move_BODY_SLAM +.elseif B_SECRET_POWER_ANIMATION == GEN_5 || B_SECRET_POWER_ANIMATION == GEN_4 + jumpargeq 0, BATTLE_TERRAIN_BUILDING, Move_BODY_SLAM + goto Move_MUD_SLAP +.else + jumpargeq 0, BATTLE_TERRAIN_BUILDING, Move_STRENGTH goto Move_SLAM +.endif Move_TWISTER: loadspritegfx ANIM_TAG_LEAF @@ -24023,6 +24205,7 @@ General_TurnTrap: jumpargeq 0, TRAP_ANIM_WHIRLPOOL, Status_Whirlpool jumpargeq 0, TRAP_ANIM_CLAMP, Status_Clamp jumpargeq 0, TRAP_ANIM_SAND_TOMB, Status_SandTomb + jumpargeq 0, TRAP_ANIM_MAGMA_STORM, Status_MagmaStorm jumpargeq 0, TRAP_ANIM_INFESTATION, Status_Infestation goto Status_BindWrap Status_BindWrap: @@ -24049,6 +24232,32 @@ Status_FireSpin: stopsound end +Status_MagmaStorm: + loadspritegfx ANIM_TAG_SMALL_EMBER + fadetobg BG_MAGMA_STORM + waitbgfadeout + createvisualtask AnimTask_MoveSeismicTossBg, 3 + playsewithpan SE_M_SACRED_FIRE2, SOUND_PAN_TARGET + loopsewithpan SE_M_SACRED_FIRE2, SOUND_PAN_TARGET, 5, 8 + createvisualtask AnimTask_SeismicTossBgAccelerateDownAtEnd, 3 + createvisualtask AnimTask_ShakeMon, 5, ANIM_TARGET, 0, 2, 47, 1 + createvisualtask AnimTask_BlendColorCycle, 2, 6, 4, 2, 2, 0, 12, RGB(22, 9, 7) + call FireSpinEffect + call FireSpinEffect + createvisualtask AnimTask_BlendColorCycle, 2, 6, 4, 2, 2, 0, 12, RGB(22, 9, 7) + call FireSpinEffect + call FireSpinEffect + createvisualtask AnimTask_BlendColorCycle, 2, 6, 4, 2, 2, 0, 12, RGB(22, 9, 7) + call FireSpinEffect + restorebg + waitbgfadeout + setarg 7, 0xFFF + waitbgfadein + stopsound + clearmonbg ANIM_DEF_PARTNER + blendoff + end + Status_Whirlpool: loadspritegfx ANIM_TAG_WATER_ORB monbg ANIM_DEF_PARTNER diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 6373a7750c..b94a9bb92d 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -367,7 +367,7 @@ gBattleScriptsForMoveEffects:: .4byte BattleScript_EffectGeomancy @ EFFECT_GEOMANCY .4byte BattleScript_EffectFairyLock @ EFFECT_FAIRY_LOCK .4byte BattleScript_EffectAllySwitch @ EFFECT_ALLY_SWITCH - .4byte BattleScript_EffectSleepHit @ EFFECT_SLEEP_HIT + .4byte BattleScript_EffectRelicSong @ EFFECT_RELIC_SONG .4byte BattleScript_EffectAttackerDefenseDownHit @ EFFECT_ATTACKER_DEFENSE_DOWN_HIT .4byte BattleScript_EffectHit @ EFFECT_BODY_PRESS .4byte BattleScript_EffectEerieSpell @ EFFECT_EERIE_SPELL @@ -392,10 +392,164 @@ gBattleScriptsForMoveEffects:: .4byte BattleScript_EffectSparklySwirl @ EFFECT_SPARKLY_SWIRL .4byte BattleScript_EffectPlasmaFists @ EFFECT_PLASMA_FISTS .4byte BattleScript_EffectHyperspaceFury @ EFFECT_HYPERSPACE_FURY + .4byte BattleScript_EffectAuraWheel @ EFFECT_AURA_WHEEL + .4byte BattleScript_EffectPhotonGeyser @ EFFECT_PHOTON_GEYSER + .4byte BattleScript_EffectShellSideArm @ EFFECT_SHELL_SIDE_ARM + .4byte BattleScript_EffectHit @ EFFECT_TERRAIN_PULSE + .4byte BattleScript_EffectJawLock @ EFFECT_JAW_LOCK + .4byte BattleScript_EffectNoRetreat @ EFFECT_NO_RETREAT + .4byte BattleScript_EffectTarShot @ EFFECT_TAR_SHOT + .4byte BattleScript_EffectPoltergeist @ EFFECT_POLTERGEIST + .4byte BattleScript_EffectOctolock @ EFFECT_OCTOLOCK + .4byte BattleScript_EffectClangorousSoul @ EFFECT_CLANGOROUS_SOUL + .4byte BattleScript_EffectHit @ EFFECT_BOLT_BEAK + +BattleScript_EffectShellSideArm: + shellsidearmcheck + setmoveeffect MOVE_EFFECT_POISON + goto BattleScript_EffectHit + +BattleScript_EffectPhotonGeyser: + attackcanceler + accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE + attackstring + ppreduce + critcalc + damagecalc + adjustdamage + photongeysercheck + 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 + seteffectwithchance + tryfaintmon BS_TARGET, FALSE, NULL + goto BattleScript_MoveEnd + +BattleScript_EffectAuraWheel: @ Aura Wheel can only be used by Morpeko + jumpifspecies BS_ATTACKER, SPECIES_MORPEKO, BattleScript_EffectSpeedUpHit + jumpifspecies BS_ATTACKER, SPECIES_MORPEKO_HANGRY, BattleScript_EffectSpeedUpHit + printstring STRINGID_BUTPOKEMONCANTUSETHEMOVE + waitmessage B_WAIT_TIME_LONG + goto BattleScript_MoveEnd + +BattleScript_EffectClangorousSoul: + attackcanceler + attackstring + ppreduce + cutonethirdhpraisestats BattleScript_ButItFailed + orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_SKIP_DMG_TRACK | HITMARKER_PASSIVE_DAMAGE | HITMARKER_IGNORE_DISGUISE + attackanimation + waitanimation + healthbarupdate BS_ATTACKER + datahpupdate BS_ATTACKER + call BattleScript_AllStatsUp + goto BattleScript_MoveEnd + +BattleScript_EffectOctolock: + attackcanceler + jumpifsubstituteblocks BattleScript_ButItFailedAtkStringPpReduce + accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE + attackstring + ppreduce + setoctolock BS_TARGET, BattleScript_ButItFailed + attackanimation + waitanimation + printstring STRINGID_CANTESCAPEBECAUSEOFCURRENTMOVE + waitmessage B_WAIT_TIME_LONG + goto BattleScript_MoveEnd + +BattleScript_OctolockEndTurn:: + setbyte sSTAT_ANIM_PLAYED, FALSE + jumpifstat BS_TARGET, CMP_GREATER_THAN, STAT_DEF, MIN_STAT_STAGE, BattleScript_OctolockLowerDef + jumpifstat BS_TARGET, CMP_GREATER_THAN, STAT_SPDEF, MIN_STAT_STAGE, BattleScript_OctolockTryLowerSpDef + goto BattleScript_OctolockEnd2 +BattleScript_OctolockLowerDef: + jumpifability BS_TARGET, ABILITY_BIG_PECKS, BattleScript_OctolockTryLowerSpDef + playstatchangeanimation BS_ATTACKER, BIT_DEF | BIT_SPDEF, STAT_CHANGE_NEGATIVE + setbyte sSTAT_ANIM_PLAYED, TRUE + setstatchanger STAT_DEF, 1, TRUE + statbuffchange STAT_BUFF_ALLOW_PTR, BattleScript_OctolockTryLowerSpDef + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_OctolockTryLowerSpDef + printfromtable gStatUpStringIds + waitmessage B_WAIT_TIME_LONG +BattleScript_OctolockTryLowerSpDef: + jumpifbyte CMP_EQUAL, sSTAT_ANIM_PLAYED, TRUE, BattleScript_OctolockSkipSpDefAnim + playstatchangeanimation BS_ATTACKER, BIT_SPDEF, STAT_CHANGE_NEGATIVE +BattleScript_OctolockSkipSpDefAnim: + setstatchanger STAT_SPDEF, 1, TRUE + statbuffchange STAT_BUFF_ALLOW_PTR, BattleScript_OctolockEnd2 + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_OctolockEnd2 + printfromtable gStatUpStringIds + waitmessage B_WAIT_TIME_LONG +BattleScript_OctolockEnd2:: + end2 + +BattleScript_EffectPoltergeist: + attackcanceler + attackstring + ppreduce + checkpoltergeist BS_TARGET, BattleScript_ButItFailed + printstring STRINGID_ABOUTTOUSEPOLTERGEIST + waitmessage B_WAIT_TIME_LONG + goto BattleScript_HitFromCritCalc + +BattleScript_EffectTarShot: + attackcanceler + jumpifsubstituteblocks BattleScript_ButItFailedAtkStringPpReduce + accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE + cantarshotwork BS_TARGET, BattleScript_ButItFailedAtkStringPpReduce + attackstring + ppreduce + setstatchanger STAT_SPEED, 1, TRUE + attackanimation + waitanimation + statbuffchange STAT_BUFF_ALLOW_PTR, BattleScript_TryTarShot + setgraphicalstatchangevalues + playanimation BS_TARGET, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1 + printfromtable gStatDownStringIds + waitmessage B_WAIT_TIME_LONG +BattleScript_TryTarShot: + trytarshot BS_TARGET, BattleScript_MoveEnd + printstring STRINGID_PKMNBECAMEWEAKERTOFIRE + waitmessage B_WAIT_TIME_LONG + goto BattleScript_MoveEnd + +BattleScript_EffectNoRetreat: + attackcanceler + accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE + attackstring + ppreduce + trynoretreat BS_TARGET, BattleScript_ButItFailed + attackanimation + waitanimation + call BattleScript_AllStatsUp + jumpifstatus2 BS_TARGET, STATUS2_ESCAPE_PREVENTION, BattleScript_MoveEnd + setmoveeffect MOVE_EFFECT_PREVENT_ESCAPE + seteffectprimary + printstring STRINGID_CANTESCAPEDUETOUSEDMOVE + waitmessage B_WAIT_TIME_LONG + goto BattleScript_MoveEnd + +BattleScript_EffectJawLock: + setmoveeffect MOVE_EFFECT_TRAP_BOTH | MOVE_EFFECT_CERTAIN + goto BattleScript_EffectHit + +BattleScript_BothCanNoLongerEscape:: + printstring STRINGID_BOTHCANNOLONGERESCAPE + waitmessage B_WAIT_TIME_LONG + return BattleScript_EffectHyperspaceFury: - jumpifspecies BS_ATTACKER, SPECIES_TREECKO, BattleScript_EffectHyperspaceFuryUnbound - jumpifspecies BS_ATTACKER, SPECIES_MUDKIP, BattleScript_ButHoopaCantUseIt + jumpifspecies BS_ATTACKER, SPECIES_HOOPA_UNBOUND, BattleScript_EffectHyperspaceFuryUnbound + jumpifspecies BS_ATTACKER, SPECIES_HOOPA, BattleScript_ButHoopaCantUseIt printstring STRINGID_BUTPOKEMONCANTUSETHEMOVE waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd @@ -734,9 +888,30 @@ BattleScript_EffectAttackerDefenseDownHit: setmoveeffect MOVE_EFFECT_DEF_MINUS_1 | MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN goto BattleScript_EffectHit -BattleScript_EffectSleepHit: - setmoveeffect MOVE_EFFECT_SLEEP - goto BattleScript_EffectHit +BattleScript_EffectRelicSong: + setmoveeffect MOVE_EFFECT_RELIC_SONG | MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN + attackcanceler + accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE + attackstring + ppreduce + 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 + seteffectwithchance + argumentstatuseffect + tryfaintmon BS_TARGET, FALSE, NULL + goto BattleScript_MoveEnd BattleScript_EffectAllySwitch: attackcanceler @@ -1707,7 +1882,7 @@ BattleScript_EffectSoak: attackanimation waitanimation trysoak BattleScript_ButItFailed - printstring STRINGID_TRANSFORMEDINTOWATERTYPE + printstring STRINGID_TARGETCHANGEDTYPE waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd @@ -1908,6 +2083,23 @@ BattleScript_EffectPsychicTerrain: waitmessage B_WAIT_TIME_LONG playanimation BS_SCRIPTING, B_ANIM_RESTORE_BG, NULL call BattleScript_TerrainSeedLoop + jumpifabilitypresent ABILITY_MIMICRY, BattleScript_ApplyMimicry + goto BattleScript_MoveEnd + +BattleScript_ApplyMimicry:: + savetarget + setbyte gBattlerTarget, 0 +BattleScript_MimicryLoopIter: + copybyte sBATTLER, gBattlerTarget + trytoapplymimicry BS_TARGET, BattleScript_MimicryLoop_NextBattler + copybyte gBattlerAbility, sBATTLER + call BattleScript_AbilityPopUp + printstring STRINGID_BATTLERTYPECHANGEDTO + waitmessage B_WAIT_TIME_LONG +BattleScript_MimicryLoop_NextBattler: + addbyte gBattlerTarget, 0x1 + jumpifbytenotequal gBattlerTarget, gBattlersCount, BattleScript_MimicryLoopIter + restoretarget goto BattleScript_MoveEnd BattleScript_EffectTopsyTurvy: @@ -1995,6 +2187,7 @@ BattleScript_EffectSimpleBeam: trytoclearprimalweather printstring STRINGID_EMPTYSTRING3 waitmessage 1 + tryendneutralizinggas BS_TARGET goto BattleScript_MoveEnd BattleScript_EffectSuckerPunch: @@ -2217,6 +2410,7 @@ BattleScript_EffectGastroAcid: trytoclearprimalweather printstring STRINGID_EMPTYSTRING3 waitmessage 1 + tryendneutralizinggas BS_TARGET goto BattleScript_MoveEnd BattleScript_EffectToxicSpikes: @@ -6289,7 +6483,7 @@ BattleScript_AttackerItemStatRaise:: playanimation BS_ATTACKER, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1 waitanimation printstring STRINGID_USINGITEMSTATOFPKMNROSE - waitmessage 0x40 + waitmessage B_WAIT_TIME_LONG removeitem BS_ATTACKER BattleScript_AttackerItemStatRaiseRet: return @@ -6972,6 +7166,7 @@ BattleScript_AttackerFormChange:: call BattleScript_AbilityPopUp printstring STRINGID_EMPTYSTRING3 waitmessage 1 +BattleScript_AttackerFormChangeNoPopup:: handleformchange BS_ATTACKER, 0 handleformchange BS_ATTACKER, 1 playanimation BS_ATTACKER, B_ANIM_FORM_CHANGE, NULL @@ -6983,6 +7178,21 @@ BattleScript_AttackerFormChangeEnd3:: call BattleScript_AttackerFormChange end3 +BattleScript_AttackerFormChangeEnd3NoPopup:: + call BattleScript_AttackerFormChangeNoPopup + +BattleScript_AttackerFormChangeMoveEffect:: + waitmessage 1 + handleformchange BS_ATTACKER, 0 + handleformchange BS_ATTACKER, 1 + playanimation BS_ATTACKER, B_ANIM_FORM_CHANGE, NULL + waitanimation + copybyte sBATTLER, gBattlerAttacker + printstring STRINGID_PKMNTRANSFORMED + waitmessage B_WAIT_TIME_LONG + handleformchange BS_ATTACKER, 2 + end3 + BattleScript_BallFetch:: call BattleScript_AbilityPopUp printstring STRINGID_FETCHEDPOKEBALL @@ -8006,6 +8216,12 @@ BattleScript_ColorChangeActivates:: waitmessage B_WAIT_TIME_LONG return +BattleScript_MimicryActivatesEnd3:: + call BattleScript_AbilityPopUp + printstring STRINGID_BATTLERTYPECHANGEDTO + waitmessage B_WAIT_TIME_LONG + end3 + BattleScript_ProteanActivates:: call BattleScript_AbilityPopUp printstring STRINGID_PKMNCHANGEDTYPE @@ -8168,6 +8384,12 @@ BattleScript_SwitchInAbilityMsg:: waitmessage B_WAIT_TIME_LONG end3 +BattleScript_SwitchInAbilityMsgRet:: + call BattleScript_AbilityPopUp + printfromtable gSwitchInAbilityStringIds + waitmessage B_WAIT_TIME_LONG + return + BattleScript_ActivateAsOne:: call BattleScript_AbilityPopUp printfromtable gSwitchInAbilityStringIds @@ -8931,7 +9153,7 @@ BattleScript_StickyBarbTransfer:: BattleScript_RedCardActivates:: playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT, NULL printstring STRINGID_REDCARDACTIVATE - waitmessage 0x40 + waitmessage B_WAIT_TIME_LONG swapattackerwithtarget jumpifstatus3 BS_EFFECT_BATTLER, STATUS3_ROOTED, BattleScript_RedCardIngrain jumpifability BS_EFFECT_BATTLER, ABILITY_SUCTION_CUPS, BattleScript_RedCardSuctionCups @@ -8942,13 +9164,13 @@ BattleScript_RedCardEnd: return BattleScript_RedCardIngrain: printstring STRINGID_PKMNANCHOREDITSELF - waitmessage 0x40 + waitmessage B_WAIT_TIME_LONG removeitem BS_SCRIPTING swapattackerwithtarget return BattleScript_RedCardSuctionCups: printstring STRINGID_PKMNANCHORSITSELFWITH - waitmessage 0x40 + waitmessage B_WAIT_TIME_LONG removeitem BS_SCRIPTING swapattackerwithtarget return @@ -8957,7 +9179,7 @@ BattleScript_EjectButtonActivates:: makevisible BS_ATTACKER playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT, NULL printstring STRINGID_EJECTBUTTONACTIVATE - waitmessage 0x40 + waitmessage B_WAIT_TIME_LONG removeitem BS_SCRIPTING makeinvisible BS_SCRIPTING openpartyscreen BS_SCRIPTING, BattleScript_EjectButtonEnd @@ -9021,3 +9243,19 @@ BattleScript_PastelVeilLoopIncrement: goto BattleScript_PastelVeilEnd BattleScript_PastelVeilEnd: end3 + +sByteFour: +.byte MAX_BATTLERS_COUNT + +BattleScript_NeutralizingGasExits:: + savetarget + pause B_WAIT_TIME_SHORT + printstring STRINGID_NEUTRALIZINGGASOVER + waitmessage B_WAIT_TIME_LONG + setbyte gBattlerTarget, 0 +BattleScript_NeutralizingGasExitsLoop: + switchinabilities BS_TARGET + addbyte gBattlerTarget, 1 + jumpifbytenotequal gBattlerTarget, sByteFour, BattleScript_NeutralizingGasExitsLoop @ SOMEHOW, comparing to gBattlersCount is problematic. + restoretarget + return diff --git a/graphics/battle_anims/backgrounds/dark_void.bin b/graphics/battle_anims/backgrounds/dark_void.bin deleted file mode 100644 index 97b879f01b..0000000000 Binary files a/graphics/battle_anims/backgrounds/dark_void.bin and /dev/null differ diff --git a/graphics/battle_anims/backgrounds/dark_void.pal b/graphics/battle_anims/backgrounds/dark_void.pal deleted file mode 100644 index f4cf0f09d3..0000000000 --- a/graphics/battle_anims/backgrounds/dark_void.pal +++ /dev/null @@ -1,19 +0,0 @@ -JASC-PAL -0100 -16 -0 0 0 -131 131 131 -123 123 123 -115 115 115 -106 106 106 -98 98 98 -82 82 82 -65 65 65 -49 49 49 -0 0 0 -0 0 0 -0 0 0 -0 0 0 -0 0 0 -0 0 0 -0 0 0 diff --git a/graphics/battle_anims/backgrounds/dark_void.png b/graphics/battle_anims/backgrounds/dark_void.png deleted file mode 100644 index 2922f89d3f..0000000000 Binary files a/graphics/battle_anims/backgrounds/dark_void.png and /dev/null differ diff --git a/graphics/battle_anims/backgrounds/giga_impact.pal b/graphics/battle_anims/backgrounds/giga_impact.pal deleted file mode 100644 index 944174076e..0000000000 --- a/graphics/battle_anims/backgrounds/giga_impact.pal +++ /dev/null @@ -1,19 +0,0 @@ -JASC-PAL -0100 -16 -0 0 0 -255 214 0 -255 197 0 -255 173 0 -255 165 0 -148 90 222 -255 107 0 -255 132 0 -255 148 0 -255 156 41 -0 0 0 -0 90 0 -0 0 0 -0 0 0 -0 0 0 -0 0 0 diff --git a/graphics/battle_anims/backgrounds/new/dark_void.bin b/graphics/battle_anims/backgrounds/new/dark_void.bin index 97b879f01b..274b971db6 100644 Binary files a/graphics/battle_anims/backgrounds/new/dark_void.bin and b/graphics/battle_anims/backgrounds/new/dark_void.bin differ diff --git a/graphics/battle_anims/backgrounds/new/dark_void.pal b/graphics/battle_anims/backgrounds/new/dark_void.pal index f4cf0f09d3..6aa0b26a6d 100644 --- a/graphics/battle_anims/backgrounds/new/dark_void.pal +++ b/graphics/battle_anims/backgrounds/new/dark_void.pal @@ -2,14 +2,14 @@ JASC-PAL 0100 16 0 0 0 -131 131 131 -123 123 123 -115 115 115 -106 106 106 -98 98 98 -82 82 82 -65 65 65 -49 49 49 +48 48 48 +72 72 72 +88 88 88 +120 120 120 +0 0 0 +0 0 0 +0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/graphics/battle_anims/backgrounds/new/dark_void.png b/graphics/battle_anims/backgrounds/new/dark_void.png deleted file mode 100644 index 2922f89d3f..0000000000 Binary files a/graphics/battle_anims/backgrounds/new/dark_void.png and /dev/null differ diff --git a/graphics/battle_anims/backgrounds/new/focus_blast.bin b/graphics/battle_anims/backgrounds/new/focus_blast.bin index 98e3e8e16b..25c569a146 100644 Binary files a/graphics/battle_anims/backgrounds/new/focus_blast.bin and b/graphics/battle_anims/backgrounds/new/focus_blast.bin differ diff --git a/graphics/battle_anims/backgrounds/new/focus_blast.png b/graphics/battle_anims/backgrounds/new/focus_blast.png index 8720658a78..7c8755f59a 100644 Binary files a/graphics/battle_anims/backgrounds/new/focus_blast.png and b/graphics/battle_anims/backgrounds/new/focus_blast.png differ diff --git a/graphics/battle_anims/backgrounds/new/giga_impact.pal b/graphics/battle_anims/backgrounds/new/giga_impact.pal new file mode 100644 index 0000000000..06f02604a6 --- /dev/null +++ b/graphics/battle_anims/backgrounds/new/giga_impact.pal @@ -0,0 +1,19 @@ +JASC-PAL +0100 +16 +0 0 0 +240 136 184 +232 104 168 +136 8 40 +248 24 104 +216 32 96 +224 72 136 +160 0 48 +216 0 64 +200 40 88 +192 0 56 +176 32 128 +176 24 72 +152 16 56 +200 48 80 +216 56 160 diff --git a/graphics/battle_anims/backgrounds/new/giga_impact.png b/graphics/battle_anims/backgrounds/new/giga_impact.png new file mode 100644 index 0000000000..0d5d705fe3 Binary files /dev/null and b/graphics/battle_anims/backgrounds/new/giga_impact.png differ diff --git a/graphics/battle_anims/backgrounds/new/giga_impact_contest.bin b/graphics/battle_anims/backgrounds/new/giga_impact_contest.bin new file mode 100644 index 0000000000..03c709bb90 --- /dev/null +++ b/graphics/battle_anims/backgrounds/new/giga_impact_contest.bin @@ -0,0 +1,3 @@ +$$$$$$$$$ D!E!F!G!H!I!@!$$$$$$$$$ $$$$$$$$$ +! ! ! !!!!$$$$$$$$$ !!!!!!!$$$$$$$$$ *!+!,!-!.!/!"!$$$$$$$$$ :!;!!?!2!$$$$$$$$$ J!K!L!M!N!O!B!,,,,,,,,,((((((((((((((((J)K)L)M)N)O)B),,,,,,,,,((((((((((((((((:);)<)=)>)?)2),,,,,,,,,((((((((((((((((*)+),)-).)/)"),,,,,,,,,(((((((((((((((())))))),,,,,,,,,(((((((((((((((( +) ) ) )))),,,,,,,,,(((((((((((((((((((((((,,,,,,,,,((((((((((((((((D)E)F)G)H)I)@) \ No newline at end of file diff --git a/graphics/battle_anims/backgrounds/new/giga_impact_opponent.bin b/graphics/battle_anims/backgrounds/new/giga_impact_opponent.bin index a55ff2f56d..0cfa1f1ec6 100644 Binary files a/graphics/battle_anims/backgrounds/new/giga_impact_opponent.bin and b/graphics/battle_anims/backgrounds/new/giga_impact_opponent.bin differ diff --git a/graphics/battle_anims/backgrounds/new/giga_impact_opponent.pal b/graphics/battle_anims/backgrounds/new/giga_impact_opponent.pal deleted file mode 100644 index 2fdba24f6f..0000000000 --- a/graphics/battle_anims/backgrounds/new/giga_impact_opponent.pal +++ /dev/null @@ -1,19 +0,0 @@ -JASC-PAL -0100 -16 -41 49 49 -106 139 189 -246 131 180 -255 0 255 -255 16 98 -238 98 164 -230 65 131 -222 0 57 -222 24 90 -205 41 74 -205 32 82 -189 0 49 -172 16 65 -156 0 41 -148 16 49 -131 8 32 diff --git a/graphics/battle_anims/backgrounds/new/giga_impact_opponent.png b/graphics/battle_anims/backgrounds/new/giga_impact_opponent.png deleted file mode 100644 index cfa8c07c8d..0000000000 Binary files a/graphics/battle_anims/backgrounds/new/giga_impact_opponent.png and /dev/null differ diff --git a/graphics/battle_anims/backgrounds/new/giga_impact_player.bin b/graphics/battle_anims/backgrounds/new/giga_impact_player.bin index bfee2cb88b..3b89218e0e 100644 Binary files a/graphics/battle_anims/backgrounds/new/giga_impact_player.bin and b/graphics/battle_anims/backgrounds/new/giga_impact_player.bin differ diff --git a/graphics/battle_anims/backgrounds/new/giga_impact_player.pal b/graphics/battle_anims/backgrounds/new/giga_impact_player.pal deleted file mode 100644 index ea01813a95..0000000000 --- a/graphics/battle_anims/backgrounds/new/giga_impact_player.pal +++ /dev/null @@ -1,19 +0,0 @@ -JASC-PAL -0100 -16 -0 0 0 -255 255 255 -255 0 255 -255 16 98 -246 131 180 -238 98 164 -230 65 131 -222 0 57 -222 24 90 -205 32 82 -205 41 74 -189 0 49 -172 16 65 -156 0 41 -148 16 49 -131 8 32 diff --git a/graphics/battle_anims/backgrounds/new/giga_impact_player.png b/graphics/battle_anims/backgrounds/new/giga_impact_player.png deleted file mode 100644 index b258035e34..0000000000 Binary files a/graphics/battle_anims/backgrounds/new/giga_impact_player.png and /dev/null differ diff --git a/graphics/battle_anims/backgrounds/new/magic_room.pal b/graphics/battle_anims/backgrounds/new/magic_room.pal index 2613d5ee1a..ad110acec2 100644 --- a/graphics/battle_anims/backgrounds/new/magic_room.pal +++ b/graphics/battle_anims/backgrounds/new/magic_room.pal @@ -2,12 +2,12 @@ JASC-PAL 0100 16 0 0 0 -164 156 24 -156 148 24 -197 189 32 -172 164 32 -115 106 16 -0 0 0 +248 248 144 +224 224 120 +200 200 96 +176 176 72 +152 152 48 +120 120 16 0 0 0 0 0 0 0 0 0 diff --git a/graphics/battle_anims/backgrounds/new/spacial_rend_opponent.bin b/graphics/battle_anims/backgrounds/new/spacial_rend_opponent.bin deleted file mode 100644 index 0cfa1f1ec6..0000000000 --- a/graphics/battle_anims/backgrounds/new/spacial_rend_opponent.bin +++ /dev/null @@ -1,3 +0,0 @@ -@%I%H%G%F%E%D%$$$$$$$$$$$$$$$$ $$$$$$$$$$$$$$$$$$$$$$$ %%% % % % -%$$$$$$$$$$$$$$$$ %%%%%%%$$$$$$$$$$$$$$$$ "%/%.%-%,%+%*%$$$$$$$$$$$$$$$$ 2%?%>%=%<%;%:%$$$$$$$$$$$$$$$$ B%O%N%M%L%K%J%$$$$$$$$$$$$$$$$ B-O-N-M-L-K-J-,,,,,,,,,,,,,,,,(((((((((2-?->-=-<-;-:-,,,,,,,,,,,,,,,,((((((((("-/-.---,-+-*-,,,,,,,,,,,,,,,,(((((((((-------,,,,,,,,,,,,,,,,(((((((((--- - - - --,,,,,,,,,,,,,,,,(((((((((,,,,,,,,,,,,,,,,,,,,,,,(((((((((@-I-H-G-F-E-D-,,,,,,,,,,,,,,,,((((((((( \ No newline at end of file diff --git a/graphics/battle_anims/backgrounds/new/spacial_rend_player.bin b/graphics/battle_anims/backgrounds/new/spacial_rend_player.bin deleted file mode 100644 index 3b89218e0e..0000000000 Binary files a/graphics/battle_anims/backgrounds/new/spacial_rend_player.bin and /dev/null differ diff --git a/graphics/battle_anims/backgrounds/new/trick_room.bin b/graphics/battle_anims/backgrounds/new/trick_room.bin index 46060d1687..c58eed62a4 100644 Binary files a/graphics/battle_anims/backgrounds/new/trick_room.bin and b/graphics/battle_anims/backgrounds/new/trick_room.bin differ diff --git a/graphics/battle_anims/backgrounds/new/trick_room.pal b/graphics/battle_anims/backgrounds/new/trick_room.pal index 5e0aae212c..1861ef92a5 100644 --- a/graphics/battle_anims/backgrounds/new/trick_room.pal +++ b/graphics/battle_anims/backgrounds/new/trick_room.pal @@ -2,12 +2,12 @@ JASC-PAL 0100 16 0 0 0 -106 123 139 -90 106 139 -123 139 164 -123 139 197 -65 74 115 -0 0 0 +152 184 248 +128 160 240 +104 136 216 +80 112 192 +56 88 168 +24 56 136 0 0 0 0 0 0 0 0 0 diff --git a/graphics/battle_anims/backgrounds/new/trick_room.png b/graphics/battle_anims/backgrounds/new/trick_room.png index aac1ddc88a..8605eb0637 100644 Binary files a/graphics/battle_anims/backgrounds/new/trick_room.png and b/graphics/battle_anims/backgrounds/new/trick_room.png differ diff --git a/graphics/battle_anims/backgrounds/new/waterfall.bin b/graphics/battle_anims/backgrounds/new/waterfall.bin index 076beeff2f..eb2085cb29 100644 Binary files a/graphics/battle_anims/backgrounds/new/waterfall.bin and b/graphics/battle_anims/backgrounds/new/waterfall.bin differ diff --git a/graphics/battle_anims/backgrounds/new/waterfall.pal b/graphics/battle_anims/backgrounds/new/waterfall.pal index 1ae2f0ef99..69a25c589c 100644 --- a/graphics/battle_anims/backgrounds/new/waterfall.pal +++ b/graphics/battle_anims/backgrounds/new/waterfall.pal @@ -2,10 +2,10 @@ JASC-PAL 0100 16 0 0 0 -131 205 230 -123 180 213 -115 156 205 -115 139 164 +128 200 232 +120 176 216 +112 152 200 +112 136 160 0 0 0 0 0 0 0 0 0 diff --git a/graphics/battle_anims/backgrounds/new/waterfall.png b/graphics/battle_anims/backgrounds/new/waterfall.png index 2fa27759f3..3ddb1a0a26 100644 Binary files a/graphics/battle_anims/backgrounds/new/waterfall.png and b/graphics/battle_anims/backgrounds/new/waterfall.png differ diff --git a/graphics/battle_anims/backgrounds/new/wonder_room.pal b/graphics/battle_anims/backgrounds/new/wonder_room.pal index a1792d0173..89addaae0a 100644 --- a/graphics/battle_anims/backgrounds/new/wonder_room.pal +++ b/graphics/battle_anims/backgrounds/new/wonder_room.pal @@ -2,12 +2,12 @@ JASC-PAL 0100 16 0 0 0 -214 55 93 -199 40 78 -222 91 123 -223 96 127 -158 31 62 -0 0 0 +248 144 248 +224 120 224 +200 96 200 +176 72 176 +152 48 152 +120 16 120 0 0 0 0 0 0 0 0 0 diff --git a/graphics/battle_anims/backgrounds/trick_room.png b/graphics/battle_anims/backgrounds/trick_room.png deleted file mode 100644 index 99eda69bff..0000000000 Binary files a/graphics/battle_anims/backgrounds/trick_room.png and /dev/null differ diff --git a/graphics/battle_anims/backgrounds/trick_room_map.bin b/graphics/battle_anims/backgrounds/trick_room_map.bin deleted file mode 100644 index 3d0041baaa..0000000000 Binary files a/graphics/battle_anims/backgrounds/trick_room_map.bin and /dev/null differ diff --git a/include/battle.h b/include/battle.h index cb99cc44fa..5658f603cf 100644 --- a/include/battle.h +++ b/include/battle.h @@ -62,12 +62,13 @@ struct ResourceFlags u32 flags[4]; }; -#define RESOURCE_FLAG_FLASH_FIRE 0x1 -#define RESOURCE_FLAG_ROOST 0x2 -#define RESOURCE_FLAG_UNBURDEN 0x4 -#define RESOURCE_FLAG_INTIMIDATED 0x8 -#define RESOURCE_FLAG_TRACED 0x10 -#define RESOURCE_FLAG_EMERGENCY_EXIT 0x20 +#define RESOURCE_FLAG_FLASH_FIRE 0x1 +#define RESOURCE_FLAG_ROOST 0x2 +#define RESOURCE_FLAG_UNBURDEN 0x4 +#define RESOURCE_FLAG_INTIMIDATED 0x8 +#define RESOURCE_FLAG_TRACED 0x10 +#define RESOURCE_FLAG_EMERGENCY_EXIT 0x20 +#define RESOURCE_FLAG_NEUTRALIZING_GAS 0x40 struct DisableStruct { @@ -112,6 +113,9 @@ struct DisableStruct u8 throatChopTimer; u8 usedMoves:4; u8 wrapTurns; + u8 noRetreat:1; + u8 tarShot:1; + u8 octolock:1; }; struct ProtectStruct @@ -181,6 +185,8 @@ struct SpecialStatus u8 damagedMons:4; // Mons that have been damaged directly by using a move, includes substitute. u8 dancerUsedMove:1; u8 dancerOriginalTarget:3; + u8 announceNeutralizingGas:1; // See Cmd_switchineffects + u8 neutralizingGasRemoved:1; // See VARIOUS_TRY_END_NEUTRALIZING_GAS s32 dmg; s32 physicalDmg; s32 specialDmg; @@ -222,10 +228,7 @@ struct FieldTimer u8 wonderRoomTimer; u8 magicRoomTimer; u8 trickRoomTimer; - u8 grassyTerrainTimer; - u8 mistyTerrainTimer; - u8 electricTerrainTimer; - u8 psychicTerrainTimer; + u8 terrainTimer; u8 gravityTimer; u8 fairyLockTimer; }; @@ -236,7 +239,7 @@ struct WishFutureKnock u8 futureSightAttacker[MAX_BATTLERS_COUNT]; u16 futureSightMove[MAX_BATTLERS_COUNT]; u8 wishCounter[MAX_BATTLERS_COUNT]; - u8 wishMonId[MAX_BATTLERS_COUNT]; + u8 wishPartyId[MAX_BATTLERS_COUNT]; u8 weatherDuration; u8 knockedOffMons[2]; // Each battler is represented by a bit. The array entry is dependent on the battler's side. }; @@ -929,5 +932,6 @@ extern u8 gBattleControllerData[MAX_BATTLERS_COUNT]; extern bool8 gHasFetchedBall; extern u8 gLastUsedBall; extern u16 gLastThrownBall; +extern bool8 gSwapDamageCategory; // Photon Geyser, Shell Side Arm, Light That Burns the Sky #endif // GUARD_BATTLE_H diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index b8cd53c072..5ccf68c58e 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -1,9 +1,9 @@ #ifndef GUARD_BATTLE_AI_UTIL_H #define GUARD_BATTLE_AI_UTIL_H -// for IsAiFaster -#define AI_CHECK_FASTER 0 // if_user_faster -#define AI_CHECK_SLOWER 1 // if_target_faster +// for AI_WhoStrikesFirst +#define AI_IS_FASTER 0 +#define AI_IS_SLOWER 1 #define FOE(battler) ((battler ^ BIT_SIDE) & BIT_SIDE) @@ -21,12 +21,13 @@ void SaveBattlerData(u8 battlerId); void SetBattlerData(u8 battlerId); void RestoreBattlerData(u8 battlerId); +bool32 WillAIStrikeFirst(void); u32 GetTotalBaseStat(u32 species); bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler); bool32 AtMaxHp(u8 battler); u32 GetHealthPercentage(u8 battler); bool32 IsBattlerTrapped(u8 battler, bool8 switching); -bool32 IsAiFaster(u8 battler); +u8 AI_WhoStrikesFirst(u8 battlerAI, u8 battler2); bool32 CanTargetFaintAi(u8 battlerDef, u8 battlerAtk); bool32 CanMoveFaintBattler(u16 move, u8 battlerDef, u8 battlerAtk, u8 nHits); bool32 CanTargetFaintAiWithMod(u8 battlerDef, u8 battlerAtk, s32 hpMod, s32 dmgMod); @@ -35,7 +36,8 @@ u16 AI_GetHoldEffect(u32 battlerId); u32 AI_GetMoveAccuracy(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u8 atkHoldEffect, u8 defHoldEffect, u16 move); bool32 DoesBattlerIgnoreAbilityChecks(u16 atkAbility, u16 move); bool32 AI_WeatherHasEffect(void); -bool32 CanAttackerFaintTarget(u8 battlerAtk, u8 battlerDef, u8 index, u8 numHits); +bool32 CanAIFaintTarget(u8 battlerAtk, u8 battlerDef, u8 numHits); +bool32 CanIndexMoveFaintTarget(u8 battlerAtk, u8 battlerDef, u8 index, u8 numHits); bool32 AI_IsTerrainAffected(u8 battlerId, u32 flags); bool32 AI_IsBattlerGrounded(u8 battlerId); bool32 HasDamagingMove(u8 battlerId); @@ -51,9 +53,13 @@ bool32 ShouldRecover(u8 battlerAtk, u8 battlerDef, u16 move, u8 healPercent); bool32 ShouldSetScreen(u8 battlerAtk, u8 battlerDef, u16 moveEffect); bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 moveIndex); bool32 IsRecycleEncouragedItem(u16 item); +bool32 ShouldRestoreHpBerry(u8 battlerAtk, u16 item); +bool32 IsStatBoostingBerry(u16 item); bool32 CanKnockOffItem(u8 battler, u16 item); bool32 IsAbilityOfRating(u16 ability, s8 rating); s8 GetAbilityRating(u16 ability); +bool32 AI_IsAbilityOnSide(u32 battlerId, u32 ability); +bool32 AI_MoveMakesContact(u32 ability, u32 holdEffect, u16 move); // stat stage checks bool32 AnyStatIsRaised(u8 battlerId); @@ -120,7 +126,6 @@ bool32 IsSemiInvulnerable(u8 battlerDef, u16 move); // status checks bool32 AI_CanBeBurned(u8 battler, u16 ability); -bool32 AI_CanBePoisoned(u8 battler, u16 ability); bool32 AI_CanBeConfused(u8 battler, u16 ability); bool32 AI_CanSleep(u8 battler, u16 ability); bool32 IsBattlerIncapacitated(u8 battler, u16 ability); diff --git a/include/battle_message.h b/include/battle_message.h index e8b362c9ee..5c10f9e04a 100644 --- a/include/battle_message.h +++ b/include/battle_message.h @@ -310,6 +310,5 @@ extern const u8 gText_BattleTourney[]; extern const u16 gMissStringIds[]; extern const u16 gStatUpStringIds[]; -extern const u16 gTrappingMoves[]; #endif // GUARD_BATTLE_MESSAGE_H diff --git a/include/battle_script_commands.h b/include/battle_script_commands.h index b55ac1391d..5b263410c4 100644 --- a/include/battle_script_commands.h +++ b/include/battle_script_commands.h @@ -36,6 +36,7 @@ u32 IsAbilityStatusProtected(u32 battler); bool32 TryResetBattlerStatChanges(u8 battler); bool32 CanCamouflage(u8 battlerId); u16 GetNaturePowerMove(void); +u16 GetSecretPowerMoveEffect(void); void StealTargetItem(u8 battlerStealer, u8 battlerItem); u8 GetCatchingBattler(void); diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 12212ff94a..415eaa6bb4 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -261,6 +261,7 @@ extern const u8 BattleScript_AttackerAbilityStatRaiseEnd3[]; extern const u8 BattleScript_PoisonHealActivates[]; extern const u8 BattleScript_BadDreamsActivates[]; extern const u8 BattleScript_SwitchInAbilityMsg[]; +extern const u8 BattleScript_SwitchInAbilityMsgRet[]; extern const u8 BattleScript_ToxicSpikesPoisoned[]; extern const u8 BattleScript_ToxicSpikesAbsorbed[]; extern const u8 BattleScript_StickyWebOnSwitchIn[]; @@ -407,5 +408,12 @@ extern const u8 BattleScript_WanderingSpiritActivates[]; extern const u8 BattleScript_MirrorArmorReflect[]; extern const u8 BattleScript_GooeyActivates[]; extern const u8 BattleScript_PastelVeilActivates[]; +extern const u8 BattleScript_MimicryActivatesEnd3[]; +extern const u8 BattleScript_ApplyMimicry[]; +extern const u8 BattleScript_AttackerFormChangeEnd3NoPopup[]; +extern const u8 BattleScript_AttackerFormChangeMoveEffect[]; +extern const u8 BattleScript_BothCanNoLongerEscape[]; +extern const u8 BattleScript_OctolockEndTurn[]; +extern const u8 BattleScript_NeutralizingGasExits[]; #endif // GUARD_BATTLE_SCRIPTS_H diff --git a/include/battle_util.h b/include/battle_util.h index d0a9d8f87f..b1a2a15347 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -8,21 +8,23 @@ #define MOVE_LIMITATION_TAUNT (1 << 4) #define MOVE_LIMITATION_IMPRISON (1 << 5) -#define ABILITYEFFECT_ON_SWITCHIN 0x0 -#define ABILITYEFFECT_ENDTURN 0x1 -#define ABILITYEFFECT_MOVES_BLOCK 0x2 -#define ABILITYEFFECT_ABSORBING 0x3 -#define ABILITYEFFECT_MOVE_END_ATTACKER 0x4 -#define ABILITYEFFECT_MOVE_END 0x5 -#define ABILITYEFFECT_IMMUNITY 0x6 -#define ABILITYEFFECT_FORECAST 0x7 -#define ABILITYEFFECT_SYNCHRONIZE 0x8 -#define ABILITYEFFECT_ATK_SYNCHRONIZE 0x9 -#define ABILITYEFFECT_INTIMIDATE1 0xA -#define ABILITYEFFECT_INTIMIDATE2 0xB -#define ABILITYEFFECT_TRACE1 0xC -#define ABILITYEFFECT_TRACE2 0xD -#define ABILITYEFFECT_MOVE_END_OTHER 0xE +#define ABILITYEFFECT_ON_SWITCHIN 0 +#define ABILITYEFFECT_ENDTURN 1 +#define ABILITYEFFECT_MOVES_BLOCK 2 +#define ABILITYEFFECT_ABSORBING 3 +#define ABILITYEFFECT_MOVE_END_ATTACKER 4 +#define ABILITYEFFECT_MOVE_END 5 +#define ABILITYEFFECT_IMMUNITY 6 +#define ABILITYEFFECT_FORECAST 7 +#define ABILITYEFFECT_SYNCHRONIZE 8 +#define ABILITYEFFECT_ATK_SYNCHRONIZE 9 +#define ABILITYEFFECT_INTIMIDATE1 10 +#define ABILITYEFFECT_INTIMIDATE2 11 +#define ABILITYEFFECT_TRACE1 12 +#define ABILITYEFFECT_TRACE2 13 +#define ABILITYEFFECT_MOVE_END_OTHER 14 +#define ABILITYEFFECT_NEUTRALIZINGGAS 15 +// Special cases #define ABILITYEFFECT_SWITCH_IN_TERRAIN 0xFE #define ABILITYEFFECT_SWITCH_IN_WEATHER 0xFF @@ -102,6 +104,7 @@ u32 IsAbilityOnOpposingSide(u32 battlerId, u32 ability); u32 IsAbilityOnField(u32 ability); u32 IsAbilityOnFieldExcept(u32 battlerId, u32 ability); u32 IsAbilityPreventingEscape(u32 battlerId); +bool32 IsBattlerProtected(u8 battlerId, u16 move); bool32 CanBattlerEscape(u32 battlerId); // no ability check void BattleScriptExecute(const u8* BS_ptr); void BattleScriptPushCursorAndCallback(const u8* BS_ptr); @@ -157,8 +160,11 @@ void DoBurmyFormChange(u32 monId); bool32 BlocksPrankster(u16 move, u8 battlerPrankster, u8 battlerDef, bool32 checkTarget); u16 GetUsedHeldItem(u8 battler); bool32 IsBattlerWeatherAffected(u8 battlerId, u32 weatherFlags); +void TryToApplyMimicry(u8 battlerId, bool8 various); +void TryToRevertMimicry(void); +void RestoreBattlerOriginalTypes(u8 battlerId); -// ability checks +// Ability checks bool32 IsRolePlayBannedAbilityAtk(u16 ability); bool32 IsRolePlayBannedAbility(u16 ability); bool32 IsSkillSwapBannedAbility(u16 ability); diff --git a/include/constants/battle.h b/include/constants/battle.h index 8841a3c128..805b0ccac2 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -358,22 +358,39 @@ #define MOVE_EFFECT_INCINERATE 0x44 #define MOVE_EFFECT_BUG_BITE 0x45 #define MOVE_EFFECT_RECOIL_HP_25 0x46 -#define NUM_MOVE_EFFECTS 0x47 +#define MOVE_EFFECT_RELIC_SONG 0x47 +#define MOVE_EFFECT_TRAP_BOTH 0x48 +#define NUM_MOVE_EFFECTS 0x49 #define MOVE_EFFECT_AFFECTS_USER 0x4000 #define MOVE_EFFECT_CERTAIN 0x8000 // Battle terrain defines for gBattleTerrain. -#define BATTLE_TERRAIN_GRASS 0 -#define BATTLE_TERRAIN_LONG_GRASS 1 -#define BATTLE_TERRAIN_SAND 2 -#define BATTLE_TERRAIN_UNDERWATER 3 -#define BATTLE_TERRAIN_WATER 4 -#define BATTLE_TERRAIN_POND 5 -#define BATTLE_TERRAIN_MOUNTAIN 6 -#define BATTLE_TERRAIN_CAVE 7 -#define BATTLE_TERRAIN_BUILDING 8 -#define BATTLE_TERRAIN_PLAIN 9 +#define BATTLE_TERRAIN_GRASS 0 +#define BATTLE_TERRAIN_LONG_GRASS 1 +#define BATTLE_TERRAIN_SAND 2 +#define BATTLE_TERRAIN_UNDERWATER 3 +#define BATTLE_TERRAIN_WATER 4 +#define BATTLE_TERRAIN_POND 5 +#define BATTLE_TERRAIN_MOUNTAIN 6 +#define BATTLE_TERRAIN_CAVE 7 +#define BATTLE_TERRAIN_BUILDING 8 +#define BATTLE_TERRAIN_PLAIN 9 +// New battle terrains are used for Secret Power but not fully implemented. +#define BATTLE_TERRAIN_SOARING 10 +#define BATTLE_TERRAIN_SKY_PILLAR 11 +#define BATTLE_TERRAIN_BURIAL_GROUND 12 +#define BATTLE_TERRAIN_PUDDLE 13 +#define BATTLE_TERRAIN_MARSH 14 +#define BATTLE_TERRAIN_SWAMP 15 +#define BATTLE_TERRAIN_SNOW 16 +#define BATTLE_TERRAIN_ICE 17 +#define BATTLE_TERRAIN_VOLCANO 18 +#define BATTLE_TERRAIN_DISTORTION_WORLD 19 +#define BATTLE_TERRAIN_SPACE 20 +#define BATTLE_TERRAIN_ULTRA_SPACE 21 + +#define BATTLE_TERRAIN_COUNT 22 #define B_WAIT_TIME_LONG 64 #define B_WAIT_TIME_MED 48 diff --git a/include/constants/battle_anim.h b/include/constants/battle_anim.h index c7871bd154..7df75794e2 100644 --- a/include/constants/battle_anim.h +++ b/include/constants/battle_anim.h @@ -565,7 +565,8 @@ #define TRAP_ANIM_WHIRLPOOL 2 #define TRAP_ANIM_CLAMP 3 #define TRAP_ANIM_SAND_TOMB 4 -#define TRAP_ANIM_INFESTATION 5 +#define TRAP_ANIM_MAGMA_STORM 5 +#define TRAP_ANIM_INFESTATION 6 // Weather defines for battle animation scripts. #define ANIM_WEATHER_NONE 0 diff --git a/include/constants/battle_config.h b/include/constants/battle_config.h index 41fee089de..29b7b57503 100644 --- a/include/constants/battle_config.h +++ b/include/constants/battle_config.h @@ -47,6 +47,11 @@ #define SPECIES_GRENINJA_ASH 10017 #define SPECIES_HOOPA 0 #define SPECIES_HOOPA_UNBOUND 10018 + #define SPECIES_MELOETTA 0 + #define SPECIES_MELOETTA_PIROUETTE 10019 + #define SPECIES_MORPEKO 0 + #define SPECIES_MORPEKO_HANGRY 10020 + #define SPECIES_SIRFETCHD 10021 #endif // Items with peculiar battle effects. @@ -87,11 +92,13 @@ #define GEN_8 5 #endif +// Mega Evolution settings +#define B_MEGA_EVO_TURN_ORDER GEN_7 // In Gen7, a Pokémon's Speed after Mega Evolution is used to determine turn order, not its Speed before. + // Calculation settings #define B_CRIT_CHANCE GEN_7 // Chances of a critical hit landing. See CalcCritChanceStage. #define B_CRIT_MULTIPLIER GEN_7 // In Gen6+, critical hits multiply damage by 1.5 instead of 2. #define B_PARALYSIS_SPEED GEN_7 // In Gen7+, Speed is decreased by 50% instead of 75%. -#define B_TERRAIN_TYPE_BOOST GEN_8 // In Gen8, damage is boosted by 30% instead of 50%. #define B_CONFUSION_SELF_DMG_CHANCE GEN_7 // In Gen7+, confusion has a 33.3% of self-damage, instead of 50%. #define B_MULTI_HIT_CHANCE GEN_7 // In Gen5+, multi-hit moves have different %. See Cmd_setmultihitcounter for values. @@ -111,6 +118,7 @@ #define B_PAYBACK_SWITCH_BOOST GEN_7 // In Gen5+, if the opponent switches out, Payback's damage will no longer be doubled. #define B_HIDDEN_POWER_DMG GEN_7 // In Gen6+, Hidden Power's base power was set to always be 60. Before, it was determined by the mon's IVs. #define B_ROUGH_SKIN_DMG GEN_7 // In Gen4+, Rough Skin contact damage is 1/8th of max HP instead of 1/16th. This will also affect Iron Barbs. +#define B_KNOCK_OFF_DMG GEN_8 // In Gen6+, Knock Off deals 50% more damage when knocking off an item // Type settings #define B_GHOSTS_ESCAPE GEN_7 // In Gen6+, abilities like Shadow Tag or moves like Mean Look fail on Ghost-type Pokémon. They can also escape any Wild Battle. @@ -149,6 +157,9 @@ #define B_MEMENTO_FAIL GEN_7 // In Gen4+, Memento fails if there is no target or if the target is protected or behind substitute. But not if Atk/Sp. Atk are at -6. #define B_GLARE_GHOST GEN_7 // In Gen4+, Glare can hit Ghost-type Pokémon normally. #define B_SKILL_SWAP GEN_7 // In Gen4+, Skill Swap triggers switch-in abilities after use. +#define B_BRICK_BREAK GEN_7 // In Gen4+, you can destroy your own side's screens. In Gen 5+, screens are not removed if the target is immune. +#define B_WISH_HP_SOURCE GEN_7 // In Gen5+, Wish heals half of the user's max HP instead of the target's. +#define B_RAMPAGE_CANCELLING GEN_7 // In Gen5+, a failed Thrash, etc, will cancel except on its last turn. // Ability settings #define B_ABILITY_WEATHER GEN_7 // In Gen6+, ability-induced weather lasts 5 turns. Before, it lasted until the battle ended or until it was changed by a move or a different weather-affecting ability. @@ -157,7 +168,8 @@ #define B_SHADOW_TAG_ESCAPE GEN_7 // In Gen4+, if both sides have a Pokémon with Shadow Tag, all battlers can escape. Before, neither side could escape this situation. #define B_MOODY_ACC_EVASION GEN_8 // In Gen8, Moody CANNOT raise Accuracy and Evasion anymore. #define B_FLASH_FIRE_FROZEN GEN_7 // In Gen5+, Flash Fire can trigger even when frozen, when it couldn't before. -#define B_SYNCHRONIZE_NATURE GEN_8 // In Gen8, if the Pokémon with Synchronize is leading the party, it's 100% guaranteed that wild Pokémon will have the same ability, as opposed to 50% previously. +#define B_SYNCHRONIZE_NATURE GEN_8 // In Gen8, if a Pokémon with Synchronize is leading the party, it's 100% guaranteed that wild Pokémon will have the same ability, as opposed to 50% previously. +#define B_SYNCHRONIZE_TOXIC GEN_8 // In Gen5+, if a Pokémon with Synchronize is badly poisoned, the opponent will also become badly poisoned. Previously, the opponent would become regular poisoned. #define B_UPDATED_INTIMIDATE GEN_8 // In Gen8, Intimidate doesn't work on opponents with the Inner Focus, Scrappy, Own Tempo or Oblivious abilities. // Item settings @@ -166,6 +178,19 @@ #define B_X_ITEMS_BUFF GEN_7 // In Gen7+, the X Items raise a stat by 2 stages instead of 1. #define B_MENTAL_HERB GEN_5 // In Gen5+, the Mental Herb cures Infatuation, Taunt, Encore, Torment, Heal Block, and Disable #define B_TRAINERS_KNOCK_OFF_ITEMS TRUE // If TRUE, trainers can steal/swap your items (non-berries are restored after battle). In vanilla games trainers cannot steal items. +#define B_SOUL_DEW_BOOST GEN_7 // In Gens3-6, Soul Dew boosts Lati@s' Sp. Atk and Sp. Def. In Gen7+ it boosts the power of their Psychic and Dragon type moves instead. +#define B_NET_BALL_MODIFIER GEN_7 // In Gen7+, Net Ball's catch multiplier is x5 instead of x3. +#define B_DIVE_BALL_MODIFIER GEN_7 // In Gen4+, Dive Ball's effectiveness increases by when Surfing or Fishing. +#define B_NEST_BALL_MODIFIER GEN_7 // Nest Ball's formula varies depending on the Gen. See Cmd_handleballthrow. +#define B_REPEAT_BALL_MODIFIER GEN_7 // In Gen7+, Repeat Ball's catch multiplier is x3.5 instead of x3. +#define B_TIMER_BALL_MODIFIER GEN_7 // In Gen5+, Timer Ball's effectiveness increases by x0.3 per turn instead of x0.1 +#define B_DUSK_BALL_MODIFIER GEN_7 // In Gen7+, Dusk Ball's catch multiplier is x3 instead of x3.5. +#define B_QUICK_BALL_MODIFIER GEN_7 // In Gen5+, Quick Ball's catch multiplier is x5 instead of x4. +#define B_LURE_BALL_MODIFIER GEN_7 // In Gen7+, Lure Ball's catch multiplier is x5 instead of x3. +#define B_HEAVY_BALL_MODIFIER GEN_7 // In Gen7+, Heavy Ball's ranges change. See Cmd_handleballthrow. +#define B_DREAM_BALL_MODIFIER GEN_8 // In Gen8, Dream Ball's catch multiplier is x4 when the target is asleep or has the ability Comatose. +#define B_SERENE_GRACE_BOOST GEN_7 // In Gen5+, Serene Grace boosts the added flinch chance of King's Rock and Razor Fang. +#define B_LEEK_ALWAYS_CRIT GEN_7 // In Gen6+, if a Farfetch'd or Sirfetch'd holding a Leek use a move with increased Critical Hit ratio, it will always result in a Critical Hit. // Flag settings // To use the following features in scripting, replace the 0s with the flag ID you're assigning it to. @@ -178,26 +203,31 @@ // Eg: Replace with VAR_UNUSED_0x40F7 so you can use VAR_TERRAIN for that feature. #define VAR_TERRAIN 0 // If this var has a value, assigning a STATUS_FIELD_xx_TERRAIN to it before battle causes the battle to start with that terrain active +// Terrain settings +#define B_TERRAIN_BG_CHANGE TRUE // If set to TRUE, terrain moves permanently change the default battle background until the effect fades. +#define B_THUNDERSTORM_TERRAIN TRUE // If TRUE, overworld Thunderstorm generates Rain and Electric Terrain as in Gen 8. +#define B_TERRAIN_TYPE_BOOST GEN_8 // In Gen8, damage is boosted by 30% instead of 50%. +#define B_SECRET_POWER_EFFECT GEN_7 // Secret Power's effects change depending on terrain and generation. See GetSecretPowerMoveEffect. +#define B_SECRET_POWER_ANIMATION GEN_7 // Secret Power's animations change depending on terrain and generation. +#define B_NATURE_POWER_MOVES GEN_8 // Nature Power calls different moves depending on terrain and generation. See sNaturePowerMoves. +#define B_CAMOUFLAGE_TYPES GEN_7 // Camouflage changes the user to different types depending on terrain and generation. See sTerrainToType. + // Interface settings #define B_ABILITY_POP_UP TRUE // In Gen5+, the Pokémon abilities are displayed in a pop-up, when they activate in battle. #define B_FAST_INTRO TRUE // If set to TRUE, battle intro texts print at the same time as animation of a Pokémon, as opposing to waiting for the animation to end. #define B_SHOW_TARGETS TRUE // If set to TRUE, all available targets, for moves hitting 2 or 3 Pokémon, will be shown before selecting a move. #define B_SHOW_SPLIT_ICON TRUE // If set to TRUE, it will show an icon in the summary showing the move's category split. #define B_HIDE_HEALTHBOX_IN_ANIMS TRUE // If set to TRUE, hides healthboxes during move animations. -#define B_TERRAIN_BG_CHANGE TRUE // If set to TRUE, terrain moves permanently change the default battle background until the effect fades. -// Critical Capture -#define B_CRITICAL_CAPTURE TRUE // If set to TRUE, Critical Capture will be enabled. -#define B_CATCHING_CHARM_BOOST 20 // % boost in Critical Capture odds if player has the Catching Charm. - -// Last Used Ball -#define B_LAST_USED_BALL TRUE // If TRUE, the "last used ball" feature from Gen 7 will be implemented -#define B_LAST_USED_BALL_BUTTON R_BUTTON // If last used ball is implemented, this button (or button combo) will trigger throwing the last used ball. +// Catching settings +#define B_SEMI_INVULNERABLE_CATCH GEN_7 // In Gen4+, you cannot throw a ball against a Pokemon that is in a semi-invulnerable state (dig/fly/etc) +#define B_CATCHING_CHARM_BOOST 20 // % boost in Critical Capture odds if player has the Catching Charm. +#define B_CRITICAL_CAPTURE TRUE // If set to TRUE, Critical Capture will be enabled. +#define B_LAST_USED_BALL TRUE // If TRUE, the "last used ball" feature from Gen 7 will be implemented +#define B_LAST_USED_BALL_BUTTON R_BUTTON // If last used ball is implemented, this button (or button combo) will trigger throwing the last used ball. // Other #define B_DOUBLE_WILD_CHANCE 0 // % chance of encountering two Pokémon in a Wild Encounter. -#define B_THUNDERSTORM_TERRAIN TRUE // If TRUE, overworld Thunderstorm generates Rain and Electric Terrain as in Gen 8. -#define B_SEMI_INVULNERABLE_CATCH GEN_7 // In Gen4+, you cannot throw a ball against a Pokemon that is in a semi-invulnerable state (dig/fly/etc) // Animation Settings #define B_NEW_SWORD_PARTICLE FALSE // If set to TRUE, it updates Swords Dance's particle. diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index 62b49a1910..3f24caf5e5 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -350,7 +350,7 @@ #define EFFECT_GEOMANCY 344 #define EFFECT_FAIRY_LOCK 345 #define EFFECT_ALLY_SWITCH 346 -#define EFFECT_SLEEP_HIT 347 +#define EFFECT_RELIC_SONG 347 #define EFFECT_ATTACKER_DEFENSE_DOWN_HIT 348 #define EFFECT_BODY_PRESS 349 #define EFFECT_EERIE_SPELL 350 @@ -375,7 +375,18 @@ #define EFFECT_SPARKLY_SWIRL 369 #define EFFECT_PLASMA_FISTS 370 #define EFFECT_HYPERSPACE_FURY 371 +#define EFFECT_AURA_WHEEL 372 +#define EFFECT_PHOTON_GEYSER 373 +#define EFFECT_SHELL_SIDE_ARM 374 +#define EFFECT_TERRAIN_PULSE 375 +#define EFFECT_JAW_LOCK 376 +#define EFFECT_NO_RETREAT 377 +#define EFFECT_TAR_SHOT 378 +#define EFFECT_POLTERGEIST 379 +#define EFFECT_OCTOLOCK 380 +#define EFFECT_CLANGOROUS_SOUL 381 +#define EFFECT_BOLT_BEAK 382 -#define NUM_BATTLE_MOVE_EFFECTS 372 +#define NUM_BATTLE_MOVE_EFFECTS 383 #endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 3b4495208f..bd16f741be 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -198,6 +198,16 @@ #define VARIOUS_JUMP_IF_WEATHER_AFFECTED 125 #define VARIOUS_JUMP_IF_LEAF_GUARD_PROTECTED 126 #define VARIOUS_SET_ATTACKER_STICKY_WEB_USER 127 +#define VARIOUS_TRY_TO_APPLY_MIMICRY 128 +#define VARIOUS_PHOTON_GEYSER_CHECK 129 +#define VARIOUS_SHELL_SIDE_ARM_CHECK 130 +#define VARIOUS_TRY_NO_RETREAT 131 +#define VARIOUS_TRY_TAR_SHOT 132 +#define VARIOUS_CAN_TAR_SHOT_WORK 133 +#define VARIOUS_CHECK_POLTERGEIST 134 +#define VARIOUS_SET_OCTOLOCK 135 +#define VARIOUS_CUT_1_3_HP_RAISE_STATS 136 +#define VARIOUS_TRY_END_NEUTRALIZING_GAS 137 // Cmd_manipulatedamage #define DMG_CHANGE_SIGN 0 @@ -216,6 +226,7 @@ // Cmd_statbuffchange #define STAT_BUFF_ALLOW_PTR (1 << 0) // If set, allow use of jumpptr. Set in every use of statbuffchange #define STAT_BUFF_NOT_PROTECT_AFFECTED (1 << 5) +#define STAT_BUFF_UPDATE_MOVE_EFFECT (1 << 6) // stat change flags for Cmd_playstatchangeanimation #define STAT_CHANGE_NEGATIVE (1 << 0) diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index 3eb5dc9a44..7846fa5218 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -410,7 +410,7 @@ #define STRINGID_PKMNTWISTEDDIMENSIONS 406 #define STRINGID_POINTEDSTONESFLOAT 407 #define STRINGID_CLOAKEDINMYSTICALMOONLIGHT 408 -#define STRINGID_TRAPPERBYSWIRLINGMAGMA 409 +#define STRINGID_TRAPPEDBYSWIRLINGMAGMA 409 #define STRINGID_VANISHEDINSTANTLY 410 #define STRINGID_PROTECTEDTEAM 411 #define STRINGID_SHAREDITSGUARD 412 @@ -420,7 +420,7 @@ #define STRINGID_HURLEDINTOTHEAIR 416 #define STRINGID_HELDITEMSLOSEEFFECTS 417 #define STRINGID_FELLSTRAIGHTDOWN 418 -#define STRINGID_TRANSFORMEDINTOWATERTYPE 419 +#define STRINGID_TARGETCHANGEDTYPE 419 #define STRINGID_PKMNACQUIREDSIMPLE 420 #define STRINGID_EMPTYSTRING5 421 #define STRINGID_KINDOFFER 422 @@ -601,8 +601,16 @@ #define STRINGID_SWAPPEDABILITIES 598 #define STRINGID_PASTELVEILPROTECTED 599 #define STRINGID_PASTELVEILENTERS 600 +#define STRINGID_BATTLERTYPECHANGEDTO 601 +#define STRINGID_BOTHCANNOLONGERESCAPE 602 +#define STRINGID_CANTESCAPEDUETOUSEDMOVE 603 +#define STRINGID_PKMNBECAMEWEAKERTOFIRE 604 +#define STRINGID_ABOUTTOUSEPOLTERGEIST 605 +#define STRINGID_CANTESCAPEBECAUSEOFCURRENTMOVE 606 +#define STRINGID_NEUTRALIZINGGASENTERS 607 +#define STRINGID_NEUTRALIZINGGASOVER 608 -#define BATTLESTRINGS_COUNT 601 +#define BATTLESTRINGS_COUNT 609 // The below IDs are all indexes into battle message tables, // used to determine which of a set of messages to print. @@ -838,6 +846,7 @@ #define B_MSG_SWITCHIN_ASONE 13 #define B_MSG_SWITCHIN_CURIOUS_MEDICINE 14 #define B_MSG_SWITCHIN_PASTEL_VEIL 15 +#define B_MSG_SWITCHIN_NEUTRALIZING_GAS 16 // gMentalHerbCureStringIds #define B_MSG_MENTALHERBCURE_INFATUATION 0 diff --git a/include/constants/hold_effects.h b/include/constants/hold_effects.h index d7d74d3e1b..cba2321ce2 100644 --- a/include/constants/hold_effects.h +++ b/include/constants/hold_effects.h @@ -62,12 +62,12 @@ #define HOLD_EFFECT_FIRE_POWER 58 #define HOLD_EFFECT_DRAGON_POWER 59 #define HOLD_EFFECT_NORMAL_POWER 60 -#define HOLD_EFFECT_UP_GRADE 61 +#define HOLD_EFFECT_UPGRADE 61 #define HOLD_EFFECT_SHELL_BELL 62 #define HOLD_EFFECT_LUCKY_PUNCH 63 #define HOLD_EFFECT_METAL_POWDER 64 #define HOLD_EFFECT_THICK_CLUB 65 -#define HOLD_EFFECT_STICK 66 +#define HOLD_EFFECT_LEEK 66 // Gen4 hold effects. #define HOLD_EFFECT_CHOICE_SCARF 67 diff --git a/include/constants/pokemon.h b/include/constants/pokemon.h index 4e776e592b..959148e6c8 100644 --- a/include/constants/pokemon.h +++ b/include/constants/pokemon.h @@ -308,6 +308,7 @@ #define FLAG_DMG_UNGROUNDED_IGNORE_TYPE_IF_FLYING (1 << 24) // Makes a Ground type move do 1x damage to flying and levitating targets #define FLAG_THAW_USER (1 << 25) #define FLAG_HIT_IN_SUBSTITUTE (1 << 26) // Hyperspace Fury +#define FLAG_TWO_STRIKES (1 << 27) // A move with this flag will strike twice, and may apply its effect on each hit // Split defines. #define SPLIT_PHYSICAL 0x0 diff --git a/include/graphics.h b/include/graphics.h index 78d9f2c420..efb57bfdef 100644 --- a/include/graphics.h +++ b/include/graphics.h @@ -4937,11 +4937,13 @@ extern const u32 gBattleAnimBgImage_Hurricane[]; extern const u32 gBattleAnimBgPalette_Hurricane[]; extern const u32 gBattleAnimBgTilemap_Hurricane[]; extern const u32 gBattleAnimBgPalette_RockWrecker[]; +extern const u32 gBattleAnimBgTilemap_GigaImpactPlayer[]; +extern const u32 gBattleAnimBgTilemap_GigaImpactOpponent[]; +extern const u32 gBattleAnimBgTilemap_GigaImpactContest[]; +extern const u32 gBattleAnimBgImage_GigaImpact[]; +extern const u32 gBattleAnimBgPalette_GigaImpact[]; extern const u32 gBattleAnimBgImage_SpacialRend[]; extern const u32 gBattleAnimBgPalette_SpacialRend[]; -extern const u32 gBattleAnimBgTilemap_SpacialRendOpponent[]; -extern const u32 gBattleAnimBgTilemap_SpacialRendPlayer[]; -extern const u32 gBattleAnimBgImage_DarkVoid[]; extern const u32 gBattleAnimBgPalette_DarkVoid[]; extern const u32 gBattleAnimBgTilemap_DarkVoid[]; extern const u32 gBattleAnimBgPalette_Dark[]; @@ -4961,7 +4963,6 @@ extern const u32 gBattleAnimBgPalette_Fissure[]; extern const u32 gBattleAnimBgPalette_Bug[]; extern const u32 gBattleAnimBgPalette_Solarbeam[]; extern const u32 gBattleAnimBgPalette_MagmaStorm[]; -extern const u32 gBattleAnimBgPalette_GigaImpact[]; extern const u32 gBattleAnimBgPalette_TrickRoom[]; extern const u32 gBattleAnimBgTilemap_Dark[]; extern const u32 gBattleAnimBgTilemap_Ghost[]; diff --git a/include/wild_encounter.h b/include/wild_encounter.h index 2002431707..5f4fcf5362 100644 --- a/include/wild_encounter.h +++ b/include/wild_encounter.h @@ -30,6 +30,8 @@ struct WildPokemonHeader }; extern const struct WildPokemonHeader gWildMonHeaders[]; +extern bool8 gIsFishingEncounter; +extern bool8 gIsSurfingEncounter; void DisableWildEncounters(bool8 disabled); bool8 StandardWildEncounter(u16 currMetaTileBehavior, u16 previousMetaTileBehavior); diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 84fa7b6349..25250c480e 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -278,6 +278,7 @@ static u8 ChooseMoveOrAction_Singles(void) return AI_CHOICE_WATCH; gActiveBattler = sBattler_AI; + // If can switch. if (CountUsablePartyMons(sBattler_AI) > 0 && !IsAbilityPreventingEscape(sBattler_AI) @@ -318,7 +319,7 @@ static u8 ChooseMoveOrAction_Singles(void) } } } - + numOfBestMoves = 1; currentMoveArray[0] = AI_THINKING_STRUCT->score[0]; consideredMoveArray[0] = 0; @@ -559,7 +560,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } // check off screen - if (IsSemiInvulnerable(battlerDef, move) && moveEffect != EFFECT_SEMI_INVULNERABLE && GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) != 1) + if (IsSemiInvulnerable(battlerDef, move) && moveEffect != EFFECT_SEMI_INVULNERABLE && AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) RETURN_SCORE_MINUS(20); // if target off screen and we go first, don't use move // check if negates type @@ -578,6 +579,21 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { switch (AI_DATA->defAbility) { + case ABILITY_MAGIC_GUARD: + switch (moveEffect) + { + case EFFECT_POISON: + case EFFECT_WILL_O_WISP: + case EFFECT_TOXIC: + case EFFECT_LEECH_SEED: + score -= 5; + break; + case EFFECT_CURSE: + if (IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GHOST)) // Don't use Curse if you're a ghost type vs a Magic Guard user, they'll take no damage. + score -= 5; + break; + } + break; case ABILITY_VOLT_ABSORB: case ABILITY_MOTOR_DRIVE: case ABILITY_LIGHTNING_ROD: @@ -1243,7 +1259,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) && (B_MENTAL_HERB >= GEN_5 && AI_DATA->defHoldEffect != HOLD_EFFECT_MENTAL_HERB) && !PartnerHasSameMoveEffectWithoutTarget(AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) { - if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // attacker should go first + if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) // Attacker should go first { if (gLastMoves[battlerDef] == MOVE_NONE || gLastMoves[battlerDef] == 0xFFFF) score -= 10; // no anticipated move to disable @@ -1263,7 +1279,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) && (B_MENTAL_HERB >= GEN_5 && AI_DATA->defHoldEffect != HOLD_EFFECT_MENTAL_HERB) && !DoesPartnerHaveSameMoveEffect(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) { - if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // attacker should go first + if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) // Attacker should go first { if (gLastMoves[battlerDef] == MOVE_NONE || gLastMoves[battlerDef] == 0xFFFF) score -= 10; // no anticipated move to encore @@ -1377,22 +1393,22 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_SANDSTORM: - if (gBattleWeather & WEATHER_SANDSTORM_ANY //TODO | WEATHER_PRIMAL_ANY) + if (gBattleWeather & (WEATHER_SANDSTORM_ANY | WEATHER_PRIMAL_ANY) || PartnerMoveEffectIsWeather(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove)) score -= 8; break; case EFFECT_SUNNY_DAY: - if (gBattleWeather & WEATHER_SUN_ANY //TODO | WEATHER_PRIMAL_ANY) + if (gBattleWeather & (WEATHER_SUN_ANY | WEATHER_PRIMAL_ANY) || PartnerMoveEffectIsWeather(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove)) score -= 8; break; case EFFECT_RAIN_DANCE: - if (gBattleWeather & WEATHER_RAIN_ANY //TODO | WEATHER_PRIMAL_ANY) + if (gBattleWeather & (WEATHER_RAIN_ANY | WEATHER_PRIMAL_ANY) || PartnerMoveEffectIsWeather(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove)) score -= 8; break; case EFFECT_HAIL: - if (gBattleWeather & WEATHER_HAIL_ANY //TODO | WEATHER_PRIMAL_ANY) + if (gBattleWeather & (WEATHER_HAIL_ANY | WEATHER_PRIMAL_ANY) || PartnerMoveEffectIsWeather(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove)) score -= 8; break; @@ -1458,7 +1474,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) else if (move == MOVE_FAKE_OUT) // filter out first impression { if ((AI_DATA->atkHoldEffect == HOLD_EFFECT_CHOICE_BAND || AI_DATA->atkAbility == ABILITY_GORILLA_TACTICS) - && (CountUsablePartyMons(battlerDef) > 0 || !CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0))) + && (CountUsablePartyMons(battlerDef) > 0 || !CanIndexMoveFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0))) { if (CountUsablePartyMons(battlerAtk) == 0) score -= 10; // Don't lock the attacker into Fake Out if they can't switch out afterwards. @@ -1699,12 +1715,12 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (AI_DATA->defAbility == ABILITY_WONDER_GUARD && effectiveness < AI_EFFECTIVENESS_x2) score -= 10; else if (AI_DATA->atkAbility != ABILITY_TRUANT - && !CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) + && !CanIndexMoveFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) score -= 2; break; case EFFECT_SPITE: case EFFECT_MIMIC: - if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // attacker should go first + if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) // Attacker should go first { if (gLastMoves[battlerDef] == MOVE_NONE || gLastMoves[battlerDef] == 0xFFFF) @@ -1861,7 +1877,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (isDoubleBattle) { if (IsHazardMoveEffect(gBattleMoves[AI_DATA->partnerMove].effect) // partner is going to set up hazards - && GetWhoStrikesFirst(AI_DATA->battlerAtkPartner, battlerAtk, FALSE)) // partner is going to set up before the potential Defog + && AI_WhoStrikesFirst(AI_DATA->battlerAtkPartner, battlerAtk) == AI_IS_FASTER) // partner is going to set up before the potential Defog { score -= 10; break; // Don't use Defog if partner is going to set up hazards @@ -1899,7 +1915,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_SEMI_INVULNERABLE: if (predictedMove != MOVE_NONE - && GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1 + && AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER && gBattleMoves[predictedMove].effect == EFFECT_SEMI_INVULNERABLE) score -= 10; // Don't Fly/dig/etc if opponent is going to fly/dig/etc after you @@ -2080,7 +2096,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_ME_FIRST: if (predictedMove != MOVE_NONE) { - if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1) + if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER) score -= 10; // Target is predicted to go first, Me First will fail else return AI_CheckBadMove(battlerAtk, battlerDef, predictedMove, score); @@ -2267,7 +2283,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_ELECTRIFY: - if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0 + if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER //|| GetMoveTypeSpecial(battlerDef, predictedMove) == TYPE_ELECTRIC // Move will already be electric type || PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; @@ -2296,7 +2312,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_INSTRUCT: { u16 instructedMove; - if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1) + if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER) instructedMove = predictedMove; else instructedMove = gLastMoves[battlerDef]; @@ -2305,7 +2321,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) || IsInstructBannedMove(instructedMove) || MoveRequiresRecharging(instructedMove) || MoveCallsOtherMove(instructedMove) - #ifdef ITEM_Z_RING + #ifdef ITEM_Z_POWER_RING //|| (IsZMove(instructedMove)) #endif || (gLockedMoves[battlerDef] != 0 && gLockedMoves[battlerDef] != 0xFFFF) @@ -2336,21 +2352,21 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_QUASH: if (!isDoubleBattle - || GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1 + || AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER || PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_AFTER_YOU: if (!IsTargetingPartner(battlerAtk, battlerDef) || !isDoubleBattle - || GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1 + || AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER || PartnerMoveIsSameAsAttacker(AI_DATA->battlerAtkPartner, battlerDef, move, AI_DATA->partnerMove)) score -= 10; break; case EFFECT_SUCKER_PUNCH: if (predictedMove != MOVE_NONE) { - if (IS_MOVE_STATUS(predictedMove) || GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1) // opponent going first + if (IS_MOVE_STATUS(predictedMove) || AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER) // Opponent going first score -= 10; } break; @@ -2398,11 +2414,11 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score--; break; case EFFECT_VITAL_THROW: - if (IsAiFaster(AI_CHECK_FASTER) && GetHealthPercentage(battlerAtk) < 40) + if (WillAIStrikeFirst() && GetHealthPercentage(battlerAtk) < 40) score--; // don't want to move last break; case EFFECT_FLAIL: - if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1 // opponent should go first + if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER // Opponent should go first || GetHealthPercentage(battlerAtk) > 50) score -= 4; break; @@ -2450,10 +2466,10 @@ static s16 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (gBattleMoves[move].power == 0) return score; // can't make anything faint with no power - if (CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0) && gBattleMoves[move].effect != EFFECT_EXPLOSION) + if (CanIndexMoveFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0) && gBattleMoves[move].effect != EFFECT_EXPLOSION) { // this move can faint the target - if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0 || GetMovePriority(battlerAtk, move) > 0) + if (!WillAIStrikeFirst() || GetMovePriority(battlerAtk, move) > 0) score += 4; // we go first or we're using priority move else score += 2; @@ -2501,7 +2517,7 @@ static s16 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } //AI_TryToFaint_CheckIfDanger - if (!IsAiFaster(AI_CHECK_FASTER) && CanTargetFaintAi(battlerDef, battlerAtk)) + if (!WillAIStrikeFirst() && CanTargetFaintAi(battlerDef, battlerAtk)) { // AI_TryToFaint_Danger if (GetMoveDamageResult(move) != MOVE_POWER_BEST) score--; @@ -2551,7 +2567,7 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // Ally decided to use Frost Breath on us. we must have Anger Point as our ability if (AI_DATA->atkAbility == ABILITY_ANGER_POINT) { - if (GetWhoStrikesFirst(battlerAtk, battlerAtkPartner, TRUE) == 1) // partner moving first + if (AI_WhoStrikesFirst(battlerAtk, battlerAtkPartner) == AI_IS_SLOWER) // Partner moving first { // discourage raising our attack since it's about to be maxed out if (IsAttackBoostMoveEffect(effect)) @@ -2692,7 +2708,7 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) && !IS_MOVE_STATUS(move) && HasMoveWithSplit(battlerAtkPartner, SPLIT_PHYSICAL) && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK) - && !CanAttackerFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 1)) + && !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 1)) { RETURN_SCORE_PLUS(1); } @@ -2701,7 +2717,7 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (!IS_MOVE_STATUS(move) && (moveType == TYPE_DARK || moveType == TYPE_GHOST || moveType == TYPE_BUG) && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPEED) - && !CanAttackerFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 1)) + && !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 1)) { RETURN_SCORE_PLUS(1); } @@ -2767,7 +2783,7 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) && !IS_MOVE_STATUS(move) && HasMoveWithSplit(battlerAtkPartner, SPLIT_PHYSICAL) && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK) - && !CanAttackerFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 0)) + && !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 0)) { RETURN_SCORE_PLUS(1); } @@ -2818,22 +2834,22 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_INSTRUCT: { u16 instructedMove; - if (GetWhoStrikesFirst(battlerAtk, battlerAtkPartner, TRUE) == 0) + if (AI_WhoStrikesFirst(battlerAtk, battlerAtkPartner) == AI_IS_FASTER) instructedMove = AI_DATA->partnerMove; else instructedMove = gLastMoves[battlerAtkPartner]; if (instructedMove != MOVE_NONE && !IS_MOVE_STATUS(instructedMove) - && gBattleMoves[instructedMove].target & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY)) //Use instruct on multi-target moves + && gBattleMoves[instructedMove].target & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY)) // Use instruct on multi-target moves { RETURN_SCORE_PLUS(1); } } break; case EFFECT_AFTER_YOU: - if (GetWhoStrikesFirst(battlerAtkPartner, FOE(battlerAtkPartner), TRUE) == 1 // opponent mon 1 goes before partner - || GetWhoStrikesFirst(battlerAtkPartner, BATTLE_PARTNER(FOE(battlerAtkPartner)), TRUE) == 1) // opponent mon 2 goes before partner + if (AI_WhoStrikesFirst(battlerAtkPartner, FOE(battlerAtkPartner) == AI_IS_SLOWER) // Opponent mon 1 goes before partner + || AI_WhoStrikesFirst(battlerAtkPartner, BATTLE_PARTNER(FOE(battlerAtkPartner)) == AI_IS_SLOWER)) // Opponent mon 2 goes before partner { if (gBattleMoves[AI_DATA->partnerMove].effect == EFFECT_COUNTER || gBattleMoves[AI_DATA->partnerMove].effect == EFFECT_MIRROR_COAT) break; // These moves need to go last @@ -2859,7 +2875,9 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_EARTHQUAKE: case EFFECT_MAGNITUDE: if (!IsBattlerGrounded(battlerAtkPartner) - || (GetWhoStrikesFirst(battlerAtk, battlerAtkPartner, TRUE) == 1 && IsUngroundingEffect(gBattleMoves[AI_DATA->partnerMove].effect))) + || (IsBattlerGrounded(battlerAtkPartner) + && AI_WhoStrikesFirst(battlerAtk, battlerAtkPartner) == AI_IS_SLOWER + && IsUngroundingEffect(gBattleMoves[AI_DATA->partnerMove].effect))) score += 2; else if (IS_BATTLER_OF_TYPE(battlerAtkPartner, TYPE_FIRE) || IS_BATTLER_OF_TYPE(battlerAtkPartner, TYPE_ELECTRIC) @@ -2910,9 +2928,9 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) // check already dead if (!IsBattlerIncapacitated(battlerDef, AI_DATA->defAbility) && CanTargetFaintAi(battlerAtk, battlerDef) - && GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1) // opponent should go first + && AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER) // Opponent should go first { - if (atkPriority > 0) + if (atkPriority > 0) score++; else score--; @@ -2949,38 +2967,26 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } } - // ability checks + // attacker ability checks switch (AI_DATA->atkAbility) { case ABILITY_MOXIE: case ABILITY_BEAST_BOOST: - if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // attacker should go first + case ABILITY_CHILLING_NEIGH: + case ABILITY_GRIM_NEIGH: + case ABILITY_AS_ONE_ICE_RIDER: + case ABILITY_AS_ONE_SHADOW_RIDER: + if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) // Attacker should go first { - if (CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) + if (CanIndexMoveFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) score += 8; // prioritize killing target for stat boost } break; - case ABILITY_MAGIC_GUARD: - switch (moveEffect) - { - case EFFECT_POISON: - case EFFECT_WILL_O_WISP: - case EFFECT_TOXIC: - case EFFECT_LEECH_SEED: - score -= 5; - break; - case EFFECT_CURSE: - if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GHOST)) - score -= 5; - break; - } - break; } // ability checks // move effect checks switch (moveEffect) { - case EFFECT_HIT: break; case EFFECT_SLEEP: @@ -3042,7 +3048,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_SPEED_UP: case EFFECT_SPEED_UP_2: - if (IsAiFaster(AI_CHECK_SLOWER)) + if (!WillAIStrikeFirst()) { if (!AI_RandLessThan(70)) score += 3; @@ -3140,7 +3146,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_SPEED_DOWN: case EFFECT_SPEED_DOWN_2: - if (IsAiFaster(AI_CHECK_FASTER)) + if (WillAIStrikeFirst()) score -= 3; else if (!AI_RandLessThan(70)) score += 2; @@ -3243,6 +3249,10 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_MULTI_HIT: case EFFECT_DOUBLE_HIT: case EFFECT_TRIPLE_KICK: + if (AI_MoveMakesContact(AI_DATA->atkAbility, AI_DATA->atkHoldEffect, move) + && AI_DATA->atkAbility != ABILITY_MAGIC_GUARD + && AI_DATA->defHoldEffect == HOLD_EFFECT_ROCKY_HELMET) + score -= 2; break; case EFFECT_CONVERSION: if (!IS_BATTLER_OF_TYPE(battlerAtk, gBattleMoves[gBattleMons[battlerAtk].moves[0]].type)) @@ -3381,7 +3391,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score += 2; break; case EFFECT_SPEED_DOWN_HIT: - if (IsAiFaster(AI_CHECK_FASTER)) + if (WillAIStrikeFirst()) score -= 2; else if (!AI_RandLessThan(70)) score++; @@ -3413,7 +3423,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score++; break; case EFFECT_MIMIC: - if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) + if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) { if (gLastMoves[battlerDef] != MOVE_NONE && gLastMoves[battlerDef] != 0xFFFF) return AI_CheckViability(battlerAtk, battlerDef, gLastMoves[battlerDef], score); @@ -3472,7 +3482,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (gDisableStructs[battlerDef].disableTimer == 0 && (B_MENTAL_HERB >= GEN_5 && AI_DATA->defHoldEffect != HOLD_EFFECT_MENTAL_HERB)) // mental herb { - if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // AI goes first + if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) // AI goes first { if (gLastMoves[battlerDef] != MOVE_NONE && gLastMoves[battlerDef] != 0xFFFF) @@ -3522,11 +3532,11 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score++; break; case EFFECT_SPEED_UP_HIT: - if (AI_DATA->atkAbility == ABILITY_SERENE_GRACE && AI_DATA->defAbility != ABILITY_CONTRARY && IsAiFaster(AI_CHECK_SLOWER)) + if (AI_DATA->atkAbility == ABILITY_SERENE_GRACE && AI_DATA->defAbility != ABILITY_CONTRARY && !WillAIStrikeFirst()) score += 3; break; case EFFECT_DESTINY_BOND: - if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0 && CanTargetFaintAi(battlerDef, battlerAtk)) + if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER && CanTargetFaintAi(battlerDef, battlerAtk)) score += 3; break; case EFFECT_SPITE: @@ -3772,9 +3782,9 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_FELL_STINGER: if (gBattleMons[battlerAtk].statStages[STAT_ATK] < MAX_STAT_STAGE && AI_DATA->atkAbility != ABILITY_CONTRARY - && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) + && CanIndexMoveFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) { - if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // Attacker goes first + if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) // Attacker goes first score += 9; else score += 3; @@ -3819,7 +3829,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score++; if (predictedMove != MOVE_NONE && !isDoubleBattle) { - if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // Attacker goes first + if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) // Attacker goes first { if (gBattleMoves[predictedMove].effect == EFFECT_EXPLOSION || gBattleMoves[predictedMove].effect == EFFECT_PROTECT) @@ -3886,7 +3896,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_ATTRACT: if (!isDoubleBattle && BattlerWillFaintFromSecondaryDamage(battlerDef, AI_DATA->defAbility) - && GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1) // Target goes first + && AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER) // Target goes first break; // Don't use if the attract won't have a change to activate if (gBattleMons[battlerDef].status1 & STATUS1_ANY @@ -3931,7 +3941,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (isDoubleBattle) { if (IsHazardMoveEffect(gBattleMoves[AI_DATA->partnerMove].effect) // Partner is going to set up hazards - && GetWhoStrikesFirst(battlerAtk, AI_DATA->battlerAtkPartner, TRUE) == 1) // Partner going first + && AI_WhoStrikesFirst(battlerAtk, AI_DATA->battlerAtkPartner) == AI_IS_SLOWER) // Partner going first break; // Don't use Defog if partner is going to set up hazards } @@ -3999,7 +4009,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score += 2; break; case HOLD_EFFECT_TOXIC_ORB: - if (!ShouldPoisonSelf(battlerAtk, AI_DATA->atkAbility) && AI_CanBePoisoned(battlerDef, AI_DATA->defAbility)) + if (!ShouldPoisonSelf(battlerAtk, AI_DATA->atkAbility)) score += 2; break; case HOLD_EFFECT_FLAME_ORB: @@ -4101,6 +4111,18 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score++; if (IsRecycleEncouragedItem(GetUsedHeldItem(battlerAtk))) score++; + if (AI_DATA->atkAbility == ABILITY_RIPEN) + { + u16 item = GetUsedHeldItem(battlerAtk); + u16 toHeal = (ItemId_GetHoldEffectParam(item) == 10) ? 10 : gBattleMons[battlerAtk].maxHP / ItemId_GetHoldEffectParam(item); + + if (IsStatBoostingBerry(item) && atkHpPercent > 60) + score++; + else if (ShouldRestoreHpBerry(battlerAtk, item) && !CanAIFaintTarget(battlerAtk, battlerDef, 0) + && ((GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0 && CanTargetFaintAiWithMod(battlerDef, battlerAtk, 0, 0)) + || !CanTargetFaintAiWithMod(battlerDef, battlerAtk, toHeal, 0))) + score++; // Recycle healing berry if we can't otherwise faint the target and the target wont kill us after we activate the berry + } break; case EFFECT_BRICK_BREAK: if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_REFLECT) @@ -4305,7 +4327,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (!IsBattlerGrounded(battlerDef)) score += 3; break; - case EFFECT_SLEEP_HIT: // Relic Song + case EFFECT_RELIC_SONG: #if (defined SPECIES_MELOETTA && defined SPECIES_MELOETTA_PIROUETTE) if (AI_DATA->atkSpecies == SPECIES_MELOETTA && gBattleMons[battlerDef].defense < gBattleMons[battlerDef].spDefense) score += 3; // Change to pirouette if can do more damage @@ -4408,13 +4430,13 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score++; break; case EFFECT_THROAT_CHOP: - if (predictedMove != MOVE_NONE && TestMoveFlags(predictedMove, FLAG_SOUND) && GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) + if (predictedMove != MOVE_NONE && TestMoveFlags(predictedMove, FLAG_SOUND) && AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) score += 3; // Ai goes first and predicts the target will use a sound move else if (TestMoveFlagsInMoveset(battlerDef, FLAG_SOUND)) score += 3; break; case EFFECT_HEAL_BLOCK: - if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0 && predictedMove != MOVE_NONE && IsHealingMoveEffect(gBattleMoves[predictedMove].effect)) + if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER && predictedMove != MOVE_NONE && IsHealingMoveEffect(gBattleMoves[predictedMove].effect)) score += 3; // Try to cancel healing move else if (HasHealingEffect(battlerDef) || AI_DATA->defHoldEffect == HOLD_EFFECT_LEFTOVERS || (AI_DATA->defHoldEffect == HOLD_EFFECT_BLACK_SLUDGE && IS_BATTLER_OF_TYPE(battlerDef, TYPE_POISON))) @@ -4450,7 +4472,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_QUASH: if (isDoubleBattle - && GetWhoStrikesFirst(AI_DATA->battlerAtkPartner, battlerDef, TRUE) == 1) // Attacker partner wouldn't go before target + && AI_WhoStrikesFirst(AI_DATA->battlerAtkPartner, battlerDef) == AI_IS_SLOWER) // Attacker partner wouldn't go before target score++; break; case EFFECT_TAILWIND: @@ -4472,8 +4494,8 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) if (IsBattlerGrounded(battlerAtk) && HasDamagingMoveOfType(battlerDef, TYPE_ELECTRIC) && !(AI_GetTypeEffectiveness(MOVE_EARTHQUAKE, battlerDef, battlerAtk) == AI_EFFECTIVENESS_x0)) // Doesn't resist ground move { - if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // Attacker goes first - { + if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) // Attacker goes first + { if (gBattleMoves[predictedMove].type == TYPE_GROUND) score += 3; // Cause the enemy's move to fail break; @@ -4487,7 +4509,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_CAMOUFLAGE: - if (predictedMove != MOVE_NONE && GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0 // Attacker goes first + if (predictedMove != MOVE_NONE && AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER // Attacker goes first && !IS_MOVE_STATUS(move) && AI_GetTypeEffectiveness(predictedMove, battlerDef, battlerAtk) != AI_EFFECTIVENESS_x0) score++; break; @@ -4530,7 +4552,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } break; case EFFECT_FLAIL: - if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // Ai goes first + if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) // Ai goes first { if (GetHealthPercentage(battlerAtk) < 20) score++; @@ -4572,7 +4594,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) score += 2; break; case EFFECT_ENDEAVOR: - if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1) // Opponent faster + if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER) // Opponent faster { if (GetHealthPercentage(battlerAtk) < 40) score++; @@ -4603,7 +4625,7 @@ static s16 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) return score; if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_SMART_SWITCHING - && GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1 + && AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER && CanTargetFaintAi(battlerDef, battlerAtk) && GetMovePriority(battlerAtk, move) == 0) { @@ -4923,7 +4945,7 @@ static s16 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } // consider target HP - if (CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) + if (CanIndexMoveFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) { score += 2; } diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index e8e3999357..a3a1af8da0 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -12,12 +12,14 @@ #include "constants/item_effects.h" #include "constants/items.h" #include "constants/moves.h" +#include "constants/battle_ai.h" // this file's functions static bool8 HasSuperEffectiveMoveAgainstOpponents(bool8 noRng); static bool8 FindMonWithFlagsAndSuperEffective(u16 flags, u8 moduloPercent); static bool8 ShouldUseItem(void); +// Functions void GetAIPartyIndexes(u32 battlerId, s32 *firstId, s32 *lastId) { if (BATTLE_TWO_VS_ONE_OPPONENT && (battlerId & BIT_SIDE) == B_SIDE_OPPONENT) @@ -82,7 +84,7 @@ static bool8 ShouldSwitchIfWonderGuard(void) opposingPosition = BATTLE_OPPOSITE(GetBattlerPosition(gActiveBattler)); - if (gBattleMons[GetBattlerAtPosition(opposingPosition)].ability != ABILITY_WONDER_GUARD) + if (GetBattlerAbility(GetBattlerAtPosition(opposingPosition)) != ABILITY_WONDER_GUARD) return FALSE; // Check if Pokemon has a super effective move. @@ -176,7 +178,7 @@ static bool8 FindMonThatAbsorbsOpponentsMove(void) else return FALSE; - if (gBattleMons[gActiveBattler].ability == absorbingTypeAbility) + if (AI_GetAbility(gActiveBattler) == absorbingTypeAbility) return FALSE; GetAIPartyIndexes(gActiveBattler, &firstId, &lastId); @@ -228,7 +230,7 @@ static bool8 ShouldSwitchIfNaturalCure(void) { if (!(gBattleMons[gActiveBattler].status1 & STATUS1_SLEEP)) return FALSE; - if (gBattleMons[gActiveBattler].ability != ABILITY_NATURAL_CURE) + if (AI_GetAbility(gActiveBattler) != ABILITY_NATURAL_CURE) return FALSE; if (gBattleMons[gActiveBattler].hp < gBattleMons[gActiveBattler].maxHP / 2) return FALSE; @@ -407,7 +409,6 @@ static bool8 FindMonWithFlagsAndSuperEffective(u16 flags, u8 moduloPercent) if (AI_GetTypeEffectiveness(move, gActiveBattler, battlerIn1) >= UQ_4_12(2.0) && Random() % moduloPercent == 0) { *(gBattleStruct->AI_monToSwitchIntoId + gActiveBattler) = i; - BtlController_EmitTwoReturnValues(1, B_ACTION_SWITCH, 0); return TRUE; } } @@ -436,6 +437,7 @@ bool32 ShouldSwitch(void) return FALSE; availableToSwitch = 0; + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) { battlerIn1 = gActiveBattler; @@ -564,6 +566,7 @@ void AI_TrySwitchOrUseItem(void) } } + // AI has decided it shouldn't switch or use an item, so it will now choose a move to use BtlController_EmitTwoReturnValues(1, B_ACTION_USE_MOVE, (gActiveBattler ^ BIT_SIDE) << 8); } @@ -851,7 +854,8 @@ static bool8 ShouldUseItem(void) break; if (gBattleMons[gActiveBattler].hp == 0) break; - if (gBattleMons[gActiveBattler].hp < gBattleMons[gActiveBattler].maxHP / 4 || gBattleMons[gActiveBattler].maxHP - gBattleMons[gActiveBattler].hp > itemEffects[paramOffset]) + if (gBattleMons[gActiveBattler].hp < gBattleMons[gActiveBattler].maxHP / 4 + || gBattleMons[gActiveBattler].maxHP - gBattleMons[gActiveBattler].hp > itemEffects[paramOffset]) shouldUse = TRUE; break; case AI_ITEM_CURE_CONDITION: diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 9640df2b40..f94ba72ffd 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -439,6 +439,11 @@ static const u16 sOtherMoveCallingMoves[] = }; // Functions +bool32 WillAIStrikeFirst(void) +{ + return (AI_WhoStrikesFirst(sBattler_AI, gBattlerTarget) == AI_IS_FASTER); +} + bool32 AI_RandLessThan(u8 val) { if ((Random() % 0xFF) < val) @@ -632,7 +637,7 @@ bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler) u32 move = gBattleResources->battleHistory->usedMoves[opposingBattler][i]; if (gBattleMoves[move].effect == EFFECT_PROTECT && move != MOVE_ENDURE) return TRUE; - if (gBattleMoves[move].effect == EFFECT_SEMI_INVULNERABLE && GetWhoStrikesFirst(battlerAI, opposingBattler, TRUE) == 1) + if (gBattleMoves[move].effect == EFFECT_SEMI_INVULNERABLE && AI_WhoStrikesFirst(battlerAI, opposingBattler) == AI_IS_SLOWER) return TRUE; } return FALSE; @@ -660,9 +665,9 @@ bool32 MovesWithSplitUnusable(u32 attacker, u32 target, u32 split) for (i = 0; i < MAX_MON_MOVES; i++) { if (moves[i] != MOVE_NONE - && moves[i] != 0xFFFF - && GetBattleMoveSplit(moves[i]) == split - && !(unusable & gBitTable[i])) + && moves[i] != 0xFFFF + && GetBattleMoveSplit(moves[i]) == split + && !(unusable & gBitTable[i])) { SetTypeBeforeUsingMove(moves[i], attacker); GET_MOVE_TYPE(moves[i], moveType); @@ -733,28 +738,45 @@ s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef) else dmg = (critDmg + normalDmg * (critChance - 1)) / critChance; - // handle dynamic move damage + // Handle dynamic move damage switch (gBattleMoves[move].effect) { case EFFECT_LEVEL_DAMAGE: case EFFECT_PSYWAVE: - //psywave's expected damage is equal to the user's level - dmg = gBattleMons[battlerAtk].level; + dmg = gBattleMons[battlerAtk].level * (AI_DATA->atkAbility == ABILITY_PARENTAL_BOND ? 2 : 1); break; case EFFECT_DRAGON_RAGE: - dmg = 40; + dmg = 40 * (AI_DATA->atkAbility == ABILITY_PARENTAL_BOND ? 2 : 1); break; case EFFECT_SONICBOOM: - dmg = 20; + dmg = 20 * (AI_DATA->atkAbility == ABILITY_PARENTAL_BOND ? 2 : 1); break; - //case EFFECT_METAL_BURST: - //case EFFECT_COUNTER: - default: - //do not add the random factor, it's an average case analysis - //dmg *= (100 - (Random() % 10)) / 100; // add random factor + case EFFECT_MULTI_HIT: + dmg *= (AI_DATA->atkAbility == ABILITY_SKILL_LINK ? 5 : 3); + break; + case EFFECT_TRIPLE_KICK: + dmg *= (AI_DATA->atkAbility == ABILITY_SKILL_LINK ? 6 : 5); + break; + case EFFECT_ENDEAVOR: + // If target has less HP than user, Endeavor does no damage + dmg = max(0, gBattleMons[battlerDef].hp - gBattleMons[battlerAtk].hp); + break; + case EFFECT_SUPER_FANG: + dmg = (AI_DATA->atkAbility == ABILITY_PARENTAL_BOND + ? max(2, gBattleMons[battlerDef].hp * 3 / 4) + : max(1, gBattleMons[battlerDef].hp / 2)); + break; + case EFFECT_FINAL_GAMBIT: + dmg = gBattleMons[battlerAtk].hp; break; } + // Handle other multi-strike moves + if (gBattleMoves[move].flags & FLAG_TWO_STRIKES) + dmg *= 2; + else if (move == MOVE_SURGING_STRIKES || (move == MOVE_WATER_SHURIKEN && gBattleMons[battlerAtk].species == SPECIES_GRENINJA_ASH)) + dmg *= 3; + RestoreBattlerData(battlerAtk); RestoreBattlerData(battlerDef); @@ -964,48 +986,43 @@ u8 AI_GetMoveEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef) return damageVar; } -// AI_CHECK_FASTER: is user(ai) faster -// AI_CHECK_SLOWER: is target faster -bool32 IsAiFaster(u8 battler) +/* Checks to see if AI will move ahead of another battler + * Output: + * AI_IS_FASTER: is user(ai) faster + * AI_IS_SLOWER: is target faster +*/ +u8 AI_WhoStrikesFirst(u8 battlerAI, u8 battler2) { u32 fasterAI = 0, fasterPlayer = 0, i; - s8 prioAI, prioPlayer; + s8 prioAI = 0; + s8 prioPlayer = 0; // Check move priorities first. - prioAI = GetMovePriority(sBattler_AI, AI_THINKING_STRUCT->moveConsidered); - SaveBattlerData(gBattlerTarget); - SetBattlerData(gBattlerTarget); + prioAI = GetMovePriority(battlerAI, AI_THINKING_STRUCT->moveConsidered); for (i = 0; i < MAX_MON_MOVES; i++) { - if (gBattleMons[gBattlerTarget].moves[i] == 0 || gBattleMons[gBattlerTarget].moves[i] == 0xFFFF) + if (gBattleMons[battler2].moves[i] == 0 || gBattleMons[battler2].moves[i] == 0xFFFF) continue; - prioPlayer = GetMovePriority(gBattlerTarget, gBattleMons[gBattlerTarget].moves[i]); + prioPlayer = GetMovePriority(battler2, gBattleMons[battler2].moves[i]); if (prioAI > prioPlayer) fasterAI++; else if (prioPlayer > prioAI) fasterPlayer++; } - RestoreBattlerData(gBattlerTarget); if (fasterAI > fasterPlayer) { - if (battler == 0) // is user (ai) faster - return TRUE; - else - return FALSE; + return AI_IS_FASTER; } else if (fasterAI < fasterPlayer) { - if (battler == 1) // is target (player) faster - return TRUE; - else - return FALSE; + return AI_IS_SLOWER; } else { // Priorities are the same(at least comparing to moves the AI is aware of), decide by speed. - if (GetWhoStrikesFirst(sBattler_AI, gBattlerTarget, TRUE) == battler) + if (GetWhoStrikesFirst(battlerAI, battler2, TRUE) == 0) return TRUE; else return FALSE; @@ -1016,7 +1033,7 @@ bool32 IsAiFaster(u8 battler) bool32 CanTargetFaintAi(u8 battlerDef, u8 battlerAtk) { s32 i, dmg; - u32 unusable = CheckMoveLimitations(battlerDef, 0, 0xFF & ~MOVE_LIMITATION_PP); + u32 unusable = CheckMoveLimitations(battlerDef, 0, 0xFF); u16 *moves = gBattleResources->battleHistory->usedMoves[battlerDef]; for (i = 0; i < MAX_MON_MOVES; i++) @@ -1031,10 +1048,36 @@ bool32 CanTargetFaintAi(u8 battlerDef, u8 battlerAtk) return FALSE; } +// Check if AI mon has the means to faint the target with any of its moves. +// If numHits > 1, check if the target will be KO'ed by that number of hits (ignoring healing effects) +bool32 CanAIFaintTarget(u8 battlerAtk, u8 battlerDef, u8 numHits) +{ + s32 i, dmg; + u32 moveLimitations = CheckMoveLimitations(battlerAtk, 0, 0xFF); + u16 *moves = gBattleMons[battlerAtk].moves; + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && !(moveLimitations & gBitTable[i])) + { + // Use the pre-calculated value in simulatedDmg instead of re-calculating it + dmg = AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][i]; + + if (numHits) + dmg *= numHits; + + if (gBattleMons[battlerDef].hp <= dmg) + return TRUE; + } + } + + return FALSE; +} + bool32 CanMoveFaintBattler(u16 move, u8 battlerDef, u8 battlerAtk, u8 nHits) { s32 i, dmg; - u32 unusable = CheckMoveLimitations(battlerDef, 0, 0xFF & ~MOVE_LIMITATION_PP); + u32 unusable = CheckMoveLimitations(battlerDef, 0, 0xFF); if (move != MOVE_NONE && move != 0xFFFF && !(unusable & gBitTable[i]) && AI_CalcDamage(move, battlerDef, battlerAtk) >= gBattleMons[battlerAtk].hp) return TRUE; @@ -1046,13 +1089,17 @@ bool32 CanMoveFaintBattler(u16 move, u8 battlerDef, u8 battlerAtk, u8 nHits) bool32 CanTargetFaintAiWithMod(u8 battlerDef, u8 battlerAtk, s32 hpMod, s32 dmgMod) { u32 i; - u32 unusable = CheckMoveLimitations(battlerDef, 0, 0xFF & ~MOVE_LIMITATION_PP); + u32 unusable = CheckMoveLimitations(battlerDef, 0, 0xFF); + s32 dmg; u16 *moves = gBattleResources->battleHistory->usedMoves[battlerDef]; + u32 hpCheck = gBattleMons[battlerAtk].hp + hpMod; + + if (hpCheck > gBattleMons[battlerAtk].maxHP) + hpCheck = gBattleMons[battlerAtk].maxHP; for (i = 0; i < MAX_MON_MOVES; i++) { - u32 dmg = AI_CalcDamage(moves[i], battlerDef, battlerAtk); - u32 hpCheck = gBattleMons[battlerAtk].hp + hpMod; + dmg = AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][i]; if (dmgMod) dmg *= dmgMod; @@ -1065,34 +1112,48 @@ bool32 CanTargetFaintAiWithMod(u8 battlerDef, u8 battlerAtk, s32 hpMod, s32 dmgM return FALSE; } +bool32 AI_IsAbilityOnSide(u32 battlerId, u32 ability) +{ + if (IsBattlerAlive(battlerId) && AI_GetAbility(battlerId) == ability) + return TRUE; + else if (IsBattlerAlive(BATTLE_PARTNER(battlerId)) && AI_GetAbility(BATTLE_PARTNER(battlerId)) == ability) + return TRUE; + else + return FALSE; +} + // does NOT include ability suppression checks s32 AI_GetAbility(u32 battlerId) { + u32 knownAbility = GetBattlerAbility(battlerId); + // The AI knows its own ability. if (IsBattlerAIControlled(battlerId)) - return gBattleMons[battlerId].ability; + return knownAbility; + + // Check neutralizing gas, gastro acid + if (knownAbility == ABILITY_NONE) + return knownAbility; if (BATTLE_HISTORY->abilities[battlerId] != ABILITY_NONE) return BATTLE_HISTORY->abilities[battlerId]; - // Abilities that prevent fleeing. - if (gBattleMons[battlerId].ability == ABILITY_SHADOW_TAG - || gBattleMons[battlerId].ability == ABILITY_MAGNET_PULL - || gBattleMons[battlerId].ability == ABILITY_ARENA_TRAP) - return gBattleMons[battlerId].ability; + // Abilities that prevent fleeing - treat as always known + if (knownAbility == ABILITY_SHADOW_TAG || knownAbility == ABILITY_MAGNET_PULL || knownAbility == ABILITY_ARENA_TRAP) + return knownAbility; + // Else, guess the ability if (gBaseStats[gBattleMons[battlerId].species].abilities[0] != ABILITY_NONE) { - if (gBaseStats[gBattleMons[battlerId].species].abilities[1] != ABILITY_NONE) + u16 abilityGuess = ABILITY_NONE; + while (abilityGuess == ABILITY_NONE) { - // AI has no knowledge of opponent, so it guesses which ability. - return gBaseStats[gBattleMons[battlerId].species].abilities[Random() & 1]; - } - else - { - return gBaseStats[gBattleMons[battlerId].species].abilities[0]; // It's definitely ability 1. + abilityGuess = gBaseStats[gBattleMons[battlerId].species].abilities[Random() % NUM_ABILITY_SLOTS]; } + + return abilityGuess; } + return ABILITY_NONE; // Unknown. } @@ -1650,7 +1711,7 @@ u32 CountNegativeStatStages(u8 battlerId) bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility) { - if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) + if (WillAIStrikeFirst() && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. if (gBattleMons[battlerDef].statStages[STAT_ATK] > 4 @@ -1658,7 +1719,7 @@ bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility) && defAbility != ABILITY_CONTRARY && defAbility != ABILITY_CLEAR_BODY && defAbility != ABILITY_WHITE_SMOKE - //&& defAbility != ABILITY_FULL_METAL_BODY + && defAbility != ABILITY_FULL_METAL_BODY && defAbility != ABILITY_HYPER_CUTTER) return TRUE; return FALSE; @@ -1666,7 +1727,7 @@ bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility) bool32 ShouldLowerDefense(u8 battlerAtk, u8 battlerDef, u16 defAbility) { - if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) + if (WillAIStrikeFirst() && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. if (gBattleMons[battlerDef].statStages[STAT_DEF] > 4 @@ -1674,7 +1735,7 @@ bool32 ShouldLowerDefense(u8 battlerAtk, u8 battlerDef, u16 defAbility) && defAbility != ABILITY_CONTRARY && defAbility != ABILITY_CLEAR_BODY && defAbility != ABILITY_WHITE_SMOKE - //&& defAbility != ABILITY_FULL_METAL_BODY + && defAbility != ABILITY_FULL_METAL_BODY && defAbility != ABILITY_BIG_PECKS) return TRUE; return FALSE; @@ -1682,13 +1743,13 @@ bool32 ShouldLowerDefense(u8 battlerAtk, u8 battlerDef, u16 defAbility) bool32 ShouldLowerSpeed(u8 battlerAtk, u8 battlerDef, u16 defAbility) { - if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) + if (WillAIStrikeFirst() && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. - if (IsAiFaster(AI_CHECK_SLOWER) + if (!WillAIStrikeFirst() && defAbility != ABILITY_CONTRARY && defAbility != ABILITY_CLEAR_BODY - //&& defAbility != ABILITY_FULL_METAL_BODY + && defAbility != ABILITY_FULL_METAL_BODY && defAbility != ABILITY_WHITE_SMOKE) return TRUE; return FALSE; @@ -1696,14 +1757,14 @@ bool32 ShouldLowerSpeed(u8 battlerAtk, u8 battlerDef, u16 defAbility) bool32 ShouldLowerSpAtk(u8 battlerAtk, u8 battlerDef, u16 defAbility) { - if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) + if (WillAIStrikeFirst() && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. if (gBattleMons[battlerDef].statStages[STAT_SPATK] > 4 && HasMoveWithSplit(battlerDef, SPLIT_SPECIAL) && defAbility != ABILITY_CONTRARY && defAbility != ABILITY_CLEAR_BODY - //&& defAbility != ABILITY_FULL_METAL_BODY + && defAbility != ABILITY_FULL_METAL_BODY && defAbility != ABILITY_WHITE_SMOKE) return TRUE; return FALSE; @@ -1711,14 +1772,14 @@ bool32 ShouldLowerSpAtk(u8 battlerAtk, u8 battlerDef, u16 defAbility) bool32 ShouldLowerSpDef(u8 battlerAtk, u8 battlerDef, u16 defAbility) { - if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) + if (WillAIStrikeFirst() && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. if (gBattleMons[battlerDef].statStages[STAT_SPDEF] > 4 && HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL) && defAbility != ABILITY_CONTRARY && defAbility != ABILITY_CLEAR_BODY - //&& defAbility != ABILITY_FULL_METAL_BODY + && defAbility != ABILITY_FULL_METAL_BODY && defAbility != ABILITY_WHITE_SMOKE) return TRUE; return FALSE; @@ -1726,13 +1787,13 @@ bool32 ShouldLowerSpDef(u8 battlerAtk, u8 battlerDef, u16 defAbility) bool32 ShouldLowerAccuracy(u8 battlerAtk, u8 battlerDef, u16 defAbility) { - if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) + if (WillAIStrikeFirst() && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. if (defAbility != ABILITY_CONTRARY && defAbility != ABILITY_CLEAR_BODY && defAbility != ABILITY_WHITE_SMOKE - //&& defAbility != ABILITY_FULL_METAL_BODY + && defAbility != ABILITY_FULL_METAL_BODY && defAbility != ABILITY_KEEN_EYE) return TRUE; return FALSE; @@ -1740,19 +1801,19 @@ bool32 ShouldLowerAccuracy(u8 battlerAtk, u8 battlerDef, u16 defAbility) bool32 ShouldLowerEvasion(u8 battlerAtk, u8 battlerDef, u16 defAbility) { - if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) + if (WillAIStrikeFirst() && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. if (gBattleMons[battlerDef].statStages[STAT_EVASION] > DEFAULT_STAT_STAGE && defAbility != ABILITY_CONTRARY && defAbility != ABILITY_CLEAR_BODY - //&& defAbility != ABILITY_FULL_METAL_BODY + && defAbility != ABILITY_FULL_METAL_BODY && defAbility != ABILITY_WHITE_SMOKE) return TRUE; return FALSE; } -bool32 CanAttackerFaintTarget(u8 battlerAtk, u8 battlerDef, u8 index, u8 numHits) +bool32 CanIndexMoveFaintTarget(u8 battlerAtk, u8 battlerDef, u8 index, u8 numHits) { s32 dmg = AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][index]; @@ -2355,9 +2416,19 @@ static bool32 AnyUsefulStatIsRaised(u8 battler) return FALSE; } +struct Pokemon *GetPartyBattlerPartyData(u8 battlerId, u8 switchBattler) +{ + struct Pokemon *mon; + if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) + mon = &gPlayerParty[switchBattler]; + else + mon = &gEnemyParty[switchBattler]; + return mon; +} + static bool32 PartyBattlerShouldAvoidHazards(u8 currBattler, u8 switchBattler) { - struct Pokemon *mon = GetBattlerPartyData(switchBattler); + struct Pokemon *mon = GetPartyBattlerPartyData(currBattler, switchBattler); u16 ability = GetMonAbility(mon); // we know our own party data u16 holdEffect = GetBattlerHoldEffect(GetMonData(mon, MON_DATA_HELD_ITEM), TRUE); u32 flags = gSideStatuses[GetBattlerSide(currBattler)] & (SIDE_STATUS_SPIKES | SIDE_STATUS_STEALTH_ROCK | SIDE_STATUS_STICKY_WEB | SIDE_STATUS_TOXIC_SPIKES); @@ -2404,11 +2475,11 @@ bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 mo /*if (IsPredictedToSwitch(battlerDef, battlerAtk) && !hasStatBoost) return PIVOT; // Try pivoting so you can switch to a better matchup to counter your new opponent*/ - if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // Attacker goes first + if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) // Attacker goes first { - if (!CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0)) // Can't KO foe otherwise + if (!CanAIFaintTarget(battlerAtk, battlerDef, 0)) // Can't KO foe otherwise { - if (CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 2)) + if (CanAIFaintTarget(battlerAtk, battlerDef, 2)) { // attacker can kill target in two hits (theoretically) if (CanTargetFaintAi(battlerDef, battlerAtk)) @@ -2473,7 +2544,7 @@ bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 mo } else if (CanTargetFaintAiWithMod(battlerDef, battlerAtk, 0, 2)) // Foe can 2HKO AI { - if (CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0)) + if (CanAIFaintTarget(battlerAtk, battlerDef, 0)) { if (!BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->atkAbility)) return CAN_TRY_PIVOT; // Use this move to KO if you must @@ -2485,7 +2556,7 @@ bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 mo } else // Foe can 3HKO+ AI { - if (CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0)) + if (CanAIFaintTarget(battlerAtk, battlerDef, 0)) { if (!BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->atkAbility) // This is the only move that can KO && !hasStatBoost) //You're not wasting a valuable stat boost @@ -2493,7 +2564,7 @@ bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 mo return CAN_TRY_PIVOT; } } - else if (CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 2)) + else if (CanAIFaintTarget(battlerAtk, battlerDef, 2)) { // can knock out foe in 2 hits if (IS_MOVE_STATUS(move) && (shouldSwitch //Damaging move @@ -2606,27 +2677,38 @@ bool32 AI_CanSleep(u8 battler, u16 ability) bool32 AI_CanPutToSleep(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove) { if (!AI_CanSleep(battlerDef, defAbility) - || AI_GetMoveEffectiveness(move, battlerAtk, battlerDef) == AI_EFFECTIVENESS_x0 || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) || PartnerMoveEffectIsStatusSameTarget(BATTLE_PARTNER(battlerAtk), battlerDef, partnerMove)) // shouldn't try to sleep mon that partner is trying to make sleep return FALSE; return TRUE; } -bool32 AI_CanBePoisoned(u8 battler, u16 ability) +static bool32 AI_CanPoisonType(u8 battlerAttacker, u8 battlerTarget) { - if (ability == ABILITY_IMMUNITY - || IsAbilityOnSide(battler, ABILITY_PASTEL_VEIL) - || gBattleMons[battler].status1 & STATUS1_ANY - || IsAbilityStatusProtected(battler) - || gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD) + return ((AI_GetAbility(battlerAttacker) == ABILITY_CORROSION && gBattleMoves[gCurrentMove].split == SPLIT_STATUS) + || !(IS_BATTLER_OF_TYPE(battlerTarget, TYPE_POISON) || IS_BATTLER_OF_TYPE(battlerTarget, TYPE_STEEL))); +} + +static bool32 AI_CanBePoisoned(u8 battlerAtk, u8 battlerDef) +{ + u16 ability = AI_GetAbility(battlerDef); + + if (!(AI_CanPoisonType(battlerAtk, battlerDef)) + || gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD + || gBattleMons[battlerDef].status1 & STATUS1_ANY + || ability == ABILITY_IMMUNITY + || ability == ABILITY_COMATOSE + || AI_IsAbilityOnSide(battlerDef, ABILITY_PASTEL_VEIL) + || gBattleMons[battlerDef].status1 & STATUS1_ANY + || IsAbilityStatusProtected(battlerDef) + || AI_IsTerrainAffected(battlerDef, STATUS_FIELD_MISTY_TERRAIN)) return FALSE; return TRUE; } bool32 ShouldPoisonSelf(u8 battler, u16 ability) { - if (AI_CanBePoisoned(battler, ability) && ( + if (AI_CanBePoisoned(battler, battler) && ( ability == ABILITY_MARVEL_SCALE || ability == ABILITY_POISON_HEAL || ability == ABILITY_QUICK_FEET @@ -2641,7 +2723,7 @@ bool32 ShouldPoisonSelf(u8 battler, u16 ability) bool32 AI_CanPoison(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove) { - if (!AI_CanBePoisoned(battlerDef, defAbility) + if (!AI_CanBePoisoned(battlerAtk, battlerDef) || AI_GetMoveEffectiveness(move, battlerAtk, battlerDef) == AI_EFFECTIVENESS_x0 || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) || PartnerMoveEffectIsStatusSameTarget(BATTLE_PARTNER(battlerAtk), battlerDef, partnerMove)) @@ -2654,7 +2736,7 @@ bool32 AI_CanPoison(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 return TRUE; } -static bool32 CanBeParayzed(u8 battler, u16 ability) +static bool32 AI_CanBeParalyzed(u8 battler, u16 ability) { if (ability == ABILITY_LIMBER || IS_BATTLER_OF_TYPE(battler, TYPE_ELECTRIC) @@ -2666,7 +2748,7 @@ static bool32 CanBeParayzed(u8 battler, u16 ability) bool32 AI_CanParalyze(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove) { - if (!CanBeParayzed(battlerDef, defAbility) + if (!AI_CanBeParalyzed(battlerDef, defAbility) || AI_GetMoveEffectiveness(move, battlerAtk, battlerDef) == AI_EFFECTIVENESS_x0 || gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) @@ -2744,7 +2826,7 @@ bool32 AI_CanBeInfatuated(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 atkGe || atkGender == defGender || atkGender == MON_GENDERLESS || defGender == MON_GENDERLESS - || IsAbilityOnSide(battlerDef, ABILITY_AROMA_VEIL)) + || AI_IsAbilityOnSide(battlerDef, ABILITY_AROMA_VEIL)) return FALSE; return TRUE; } @@ -2753,7 +2835,7 @@ u32 ShouldTryToFlinch(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbili { if (defAbility == ABILITY_INNER_FOCUS || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) - || GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 1) // opponent goes first + || AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER) // Opponent goes first { return 0; // don't try to flinch } @@ -2866,7 +2948,7 @@ bool32 ShouldUseRecoilMove(u8 battlerAtk, u8 battlerDef, u32 recoilDmg, u8 moveI if (recoilDmg >= gBattleMons[battlerAtk].hp //Recoil kills attacker && CountUsablePartyMons(battlerDef) != 0) //Foe has more than 1 target left { - if (recoilDmg >= gBattleMons[battlerDef].hp && !CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0)) + if (recoilDmg >= gBattleMons[battlerDef].hp && !CanAIFaintTarget(battlerAtk, battlerDef, 0)) return TRUE; //If it's the only KO move then just use it else return FALSE; //Not as good to use move if you'll faint and not win @@ -2877,7 +2959,7 @@ bool32 ShouldUseRecoilMove(u8 battlerAtk, u8 battlerDef, u32 recoilDmg, u8 moveI bool32 ShouldAbsorb(u8 battlerAtk, u8 battlerDef, u16 move, s32 damage) { - if (move == 0xFFFF || GetWhoStrikesFirst(battlerAtk, gBattlerTarget, TRUE) == 0) + if (move == 0xFFFF || AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) { // using item or user goes first u8 healPercent = (gBattleMoves[move].argument == 0) ? 50 : gBattleMoves[move].argument; @@ -2904,7 +2986,7 @@ bool32 ShouldAbsorb(u8 battlerAtk, u8 battlerDef, u16 move, s32 damage) bool32 ShouldRecover(u8 battlerAtk, u8 battlerDef, u16 move, u8 healPercent) { - if (move == 0xFFFF || GetWhoStrikesFirst(battlerAtk, gBattlerTarget, TRUE) == 0) + if (move == 0xFFFF || AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) { // using item or user going first s32 damage = AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex]; @@ -3304,6 +3386,47 @@ static const u16 sRecycleEncouragedItems[] = // TODO expand this }; +// Its assumed that the berry is strategically given, so no need to check benefits of the berry +bool32 IsStatBoostingBerry(u16 item) +{ + switch (item) + { + case ITEM_LIECHI_BERRY: + case ITEM_GANLON_BERRY: + case ITEM_SALAC_BERRY: + case ITEM_PETAYA_BERRY: + case ITEM_APICOT_BERRY: + //case ITEM_LANSAT_BERRY: + case ITEM_STARF_BERRY: + #ifdef ITEM_EXPANSION + case ITEM_MICLE_BERRY: + #endif + return TRUE; + default: + return FALSE; + } +} + +bool32 ShouldRestoreHpBerry(u8 battlerAtk, u16 item) +{ + switch (item) + { + case ITEM_ORAN_BERRY: + if (gBattleMons[battlerAtk].maxHP <= 50) + return TRUE; // Only worth it in the early game + return FALSE; + case ITEM_SITRUS_BERRY: + case ITEM_FIGY_BERRY: + case ITEM_WIKI_BERRY: + case ITEM_MAGO_BERRY: + case ITEM_AGUAV_BERRY: + case ITEM_IAPAPA_BERRY: + return TRUE; + default: + return FALSE; + } +} + bool32 IsRecycleEncouragedItem(u16 item) { u32 i; @@ -3325,6 +3448,9 @@ void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score) if (GetHealthPercentage(battlerAtk) < 80 && AI_RandLessThan(128)) return; + + if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + return; // Damaging moves would get a score boost from AI_TryToFaint or PreferStrongestMove so we don't consider them here switch (statId) { @@ -3350,7 +3476,7 @@ void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score) } break; case STAT_SPEED: - if (IsAiFaster(AI_CHECK_SLOWER)) + if (!WillAIStrikeFirst()) { if (gBattleMons[battlerAtk].statStages[STAT_SPEED] < STAT_UP_2_STAGE) *score += 2; @@ -3397,6 +3523,9 @@ void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score) void IncreasePoisonScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) { + if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + return; + if (AI_CanPoison(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove) && GetHealthPercentage(battlerDef) > 20) { if (!HasDamagingMove(battlerDef)) @@ -3417,6 +3546,9 @@ void IncreasePoisonScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) void IncreaseBurnScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) { + if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + return; + if (AI_CanBurn(battlerAtk, battlerDef, AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)) { (*score)++; // burning is good @@ -3433,6 +3565,9 @@ void IncreaseBurnScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) void IncreaseParalyzeScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) { + if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + return; + if (AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) { u8 atkSpeed = GetBattlerTotalSpeedStat(battlerAtk); @@ -3451,6 +3586,9 @@ void IncreaseParalyzeScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) void IncreaseSleepScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) { + if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + return; + if (AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove)) *score += 2; else @@ -3466,6 +3604,9 @@ void IncreaseSleepScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) void IncreaseConfusionScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) { + if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + return; + if (AI_CanConfuse(battlerAtk, battlerDef, AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove) && AI_DATA->defHoldEffect != HOLD_EFFECT_CURE_CONFUSION && AI_DATA->defHoldEffect != HOLD_EFFECT_CURE_STATUS) @@ -3478,3 +3619,12 @@ void IncreaseConfusionScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) *score += 2; } } + +bool32 AI_MoveMakesContact(u32 ability, u32 holdEffect, u16 move) +{ + if (TestMoveFlags(move, FLAG_MAKES_CONTACT) + && ability != ABILITY_LONG_REACH + && holdEffect != HOLD_EFFECT_PROTECTIVE_PADS) + return TRUE; + return FALSE; +} diff --git a/src/battle_anim.c b/src/battle_anim.c index 44a382296b..e6152a7cfb 100644 --- a/src/battle_anim.c +++ b/src/battle_anim.c @@ -2052,14 +2052,14 @@ const struct BattleAnimBackground gBattleAnimBackgroundTable[] = [BG_SOLARBEAM_CONTESTS] = {gBattleAnimBgImage_Impact, gBattleAnimBgPalette_Solarbeam, gBattleAnimBgTilemap_ImpactContests}, //new bgs [BG_MAGMA_STORM] = {gBattleAnimBgImage_InAir, gBattleAnimBgPalette_MagmaStorm, gBattleAnimBgTilemap_InAir}, - [BG_GIGA_IMPACT_OPPONENT] = {gBattleAnimBgImage_Impact, gBattleAnimBgPalette_GigaImpact, gBattleAnimBgTilemap_ImpactOpponent}, - [BG_GIGA_IMPACT_PLAYER] = {gBattleAnimBgImage_Impact, gBattleAnimBgPalette_GigaImpact, gBattleAnimBgTilemap_ImpactPlayer}, - [BG_GIGA_IMPACT_CONTEST] = {gBattleAnimBgImage_Impact, gBattleAnimBgPalette_GigaImpact, gBattleAnimBgTilemap_ImpactContests}, + [BG_GIGA_IMPACT_OPPONENT] = {gBattleAnimBgImage_GigaImpact, gBattleAnimBgPalette_GigaImpact, gBattleAnimBgTilemap_GigaImpactOpponent}, + [BG_GIGA_IMPACT_PLAYER] = {gBattleAnimBgImage_GigaImpact, gBattleAnimBgPalette_GigaImpact, gBattleAnimBgTilemap_GigaImpactPlayer}, + [BG_GIGA_IMPACT_CONTEST] = {gBattleAnimBgImage_GigaImpact, gBattleAnimBgPalette_GigaImpact, gBattleAnimBgTilemap_GigaImpactContest}, [BG_TRICK_ROOM] = {gBattleAnimBgImage_TrickRoom, gBattleAnimBgPalette_TrickRoom, gBattleAnimBgTilemap_TrickRoom}, [BG_ROCK_WRECKER] = {gBattleAnimBgImage_Hurricane, gBattleAnimBgPalette_RockWrecker, gBattleAnimBgTilemap_Hurricane}, - [BG_SPACIAL_REND_ON_OPPONENT] = {gBattleAnimBgImage_SpacialRend, gBattleAnimBgPalette_SpacialRend, gBattleAnimBgTilemap_SpacialRendOpponent}, - [BG_SPACIAL_REND_ON_PLAYER] = {gBattleAnimBgImage_SpacialRend, gBattleAnimBgPalette_SpacialRend, gBattleAnimBgTilemap_SpacialRendPlayer}, - [BG_DARK_VOID] = {gBattleAnimBgImage_DarkVoid, gBattleAnimBgPalette_DarkVoid, gBattleAnimBgTilemap_DarkVoid}, + [BG_SPACIAL_REND_ON_OPPONENT] = {gBattleAnimBgImage_SpacialRend, gBattleAnimBgPalette_SpacialRend, gBattleAnimBgTilemap_GigaImpactOpponent}, + [BG_SPACIAL_REND_ON_PLAYER] = {gBattleAnimBgImage_SpacialRend, gBattleAnimBgPalette_SpacialRend, gBattleAnimBgTilemap_GigaImpactPlayer}, + [BG_DARK_VOID] = {gBattleAnimBgImage_Waterfall, gBattleAnimBgPalette_DarkVoid, gBattleAnimBgTilemap_DarkVoid}, [BG_WATER] = {gBattleAnimBgImage_HydroPump, gBattleAnimBgPalette_HydroPump, gBattleAnimBgTilemap_HydroPump}, [BG_NIGHTMARE] = {gBattleAnimBgImage_Nightmare, gBattleAnimBgPalette_Nightmare, gBattleAnimBgTilemap_Nightmare}, [BG_LEAF_STORM] = {gBattleAnimBgImage_LeafStorm, gBattleAnimBgPalette_LeafStorm, gBattleAnimBgTilemap_LeafStorm}, diff --git a/src/battle_anim_new.c b/src/battle_anim_new.c index d04483e6b1..63fed0b3d6 100644 --- a/src/battle_anim_new.c +++ b/src/battle_anim_new.c @@ -5064,3 +5064,34 @@ void AnimTask_PrimalReversion(u8 taskId) gBattleAnimArgs[0] = 0; DestroyAnimVisualTask(taskId); } + +void AnimTask_ShellSideArm(u8 taskId) +{ + if (gSwapDamageCategory) + gBattleAnimArgs[0] = TRUE; + else + gBattleAnimArgs[0] = FALSE; + DestroyAnimVisualTask(taskId); +} + +void AnimTask_TerrainPulse(u8 taskId) +{ + if (IsBattlerTerrainAffected(gBattleAnimAttacker, STATUS_FIELD_TERRAIN_ANY)) + { + if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) + gBattleAnimArgs[0] = TYPE_ELECTRIC; + else if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN) + gBattleAnimArgs[0] = TYPE_GRASS; + else if (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN) + gBattleAnimArgs[0] = TYPE_FAIRY; + else if (gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN) + gBattleAnimArgs[0] = TYPE_PSYCHIC; + else //failsafe + gBattleAnimArgs[0] = 0; + } + else + { + gBattleAnimArgs[0] = 0; + } + DestroyAnimVisualTask(taskId); +} diff --git a/src/battle_anim_throw.c b/src/battle_anim_throw.c index 207d1255d6..f325cba07a 100755 --- a/src/battle_anim_throw.c +++ b/src/battle_anim_throw.c @@ -2496,6 +2496,8 @@ void AnimTask_GetTrappedMoveAnimId(u8 taskId) gBattleAnimArgs[0] = TRAP_ANIM_CLAMP; else if (gBattleSpritesDataPtr->animationData->animArg == MOVE_SAND_TOMB) gBattleAnimArgs[0] = TRAP_ANIM_SAND_TOMB; + else if (gBattleSpritesDataPtr->animationData->animArg == MOVE_MAGMA_STORM) + gBattleAnimArgs[0] = TRAP_ANIM_MAGMA_STORM; else if (gBattleSpritesDataPtr->animationData->animArg == MOVE_INFESTATION) gBattleAnimArgs[0] = TRAP_ANIM_INFESTATION; else diff --git a/src/battle_anim_utility_funcs.c b/src/battle_anim_utility_funcs.c index 6cefba92a6..c85a918da8 100644 --- a/src/battle_anim_utility_funcs.c +++ b/src/battle_anim_utility_funcs.c @@ -136,6 +136,7 @@ void AnimTask_SetCamouflageBlend(u8 taskId) gBattleAnimArgs[4] = RGB(31, 31, 31); break; case BATTLE_TERRAIN_PLAIN: + default: gBattleAnimArgs[4] = RGB(31, 31, 31); break; } @@ -904,6 +905,12 @@ void AnimTask_GetBattleTerrain(u8 taskId) DestroyAnimVisualTask(taskId); } +void AnimTask_GetFieldTerrain(u8 taskId) +{ + gBattleAnimArgs[0] = gFieldStatuses & STATUS_FIELD_TERRAIN_ANY; + DestroyAnimVisualTask(taskId); +} + void AnimTask_AllocBackupPalBuffer(u8 taskId) { gMonSpritesGfxPtr->buffer = AllocZeroed(0x2000); diff --git a/src/battle_controller_opponent.c b/src/battle_controller_opponent.c index b43e80225b..f4982b8043 100644 --- a/src/battle_controller_opponent.c +++ b/src/battle_controller_opponent.c @@ -1545,7 +1545,7 @@ static void OpponentHandlePrintSelectionString(void) static void OpponentHandleChooseAction(void) { - AI_TrySwitchOrUseItem(); + AI_TrySwitchOrUseItem(); // TODO consider move choice first OpponentBufferExecCompleted(); } @@ -1565,12 +1565,12 @@ static void OpponentHandleChooseMove(void) { u8 chosenMoveId; struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct*)(&gBattleResources->bufferA[gActiveBattler][4]); - + if (gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FIRST_BATTLE | BATTLE_TYPE_SAFARI | BATTLE_TYPE_ROAMER)) { BattleAI_SetupAIData(0xF); chosenMoveId = BattleAI_ChooseMoveOrAction(); - + switch (chosenMoveId) { case AI_CHOICE_WATCH: @@ -1594,15 +1594,18 @@ static void OpponentHandleChooseMove(void) if (gAbsentBattlerFlags & gBitTable[gBattlerTarget]) gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT); } - if (CanMegaEvolve(gActiveBattler)) // If opponent can mega evolve, do it. + + // If opponent can mega evolve, do it. + if (CanMegaEvolve(gActiveBattler)) BtlController_EmitTwoReturnValues(1, 10, (chosenMoveId) | (RET_MEGA_EVOLUTION) | (gBattlerTarget << 8)); else BtlController_EmitTwoReturnValues(1, 10, (chosenMoveId) | (gBattlerTarget << 8)); break; } + OpponentBufferExecCompleted(); } - else + else // Wild pokemon - use random move { u16 move; do diff --git a/src/battle_controller_player_partner.c b/src/battle_controller_player_partner.c index f0540e65f5..2b4187a31c 100644 --- a/src/battle_controller_player_partner.c +++ b/src/battle_controller_player_partner.c @@ -1539,6 +1539,7 @@ static void PlayerPartnerHandleChooseMove(void) BtlController_EmitTwoReturnValues(1, 10, (chosenMoveId) | (RET_MEGA_EVOLUTION) | (gBattlerTarget << 8)); else BtlController_EmitTwoReturnValues(1, 10, (chosenMoveId) | (gBattlerTarget << 8)); + PlayerPartnerBufferExecCompleted(); } diff --git a/src/battle_debug.c b/src/battle_debug.c index c967cfe00e..a10e60412f 100644 --- a/src/battle_debug.c +++ b/src/battle_debug.c @@ -1924,12 +1924,20 @@ static const u8 sText_HoldEffectPsychicPower[] = _("Psychic Power"); static const u8 sText_HoldEffectFirePower[] = _("Fire Power"); static const u8 sText_HoldEffectDragonPower[] = _("Dragon Power"); static const u8 sText_HoldEffectNormalPower[] = _("Normal Power"); -static const u8 sText_HoldEffectUpGrade[] = _("Up Grade"); +#ifdef ITEM_EXPANSION +static const u8 sText_HoldEffectUpgrade[] = _("Upgrade"); +#else +static const u8 sText_HoldEffectUpgrade[] = _("Up Grade"); +#endif static const u8 sText_HoldEffectShellBell[] = _("Shell Bell"); static const u8 sText_HoldEffectLuckyPunch[] = _("Lucky Punch"); static const u8 sText_HoldEffectMetalPowder[] = _("Metal Powder"); static const u8 sText_HoldEffectThickClub[] = _("Thick Club"); -static const u8 sText_HoldEffectStick[] = _("Stick"); +#ifdef ITEM_EXPANSION +static const u8 sText_HoldEffectLeek[] = _("Leek"); +#else +static const u8 sText_HoldEffectLeek[] = _("Stick"); +#endif static const u8 sText_HoldEffectChoiceScarf[] = _("Choice Scarf"); static const u8 sText_HoldEffectChoiceSpecs[] = _("Choice Specs"); static const u8 sText_HoldEffectDampRock[] = _("Damp Rock"); @@ -2064,12 +2072,12 @@ static const u8 *const sHoldEffectNames[] = [HOLD_EFFECT_FIRE_POWER] = sText_HoldEffectFirePower, [HOLD_EFFECT_DRAGON_POWER] = sText_HoldEffectDragonPower, [HOLD_EFFECT_NORMAL_POWER] = sText_HoldEffectNormalPower, - [HOLD_EFFECT_UP_GRADE] = sText_HoldEffectUpGrade, + [HOLD_EFFECT_UPGRADE] = sText_HoldEffectUpgrade, [HOLD_EFFECT_SHELL_BELL] = sText_HoldEffectShellBell, [HOLD_EFFECT_LUCKY_PUNCH] = sText_HoldEffectLuckyPunch, [HOLD_EFFECT_METAL_POWDER] = sText_HoldEffectMetalPowder, [HOLD_EFFECT_THICK_CLUB] = sText_HoldEffectThickClub, - [HOLD_EFFECT_STICK] = sText_HoldEffectStick, + [HOLD_EFFECT_LEEK] = sText_HoldEffectLeek, [HOLD_EFFECT_CHOICE_SCARF] = sText_HoldEffectChoiceScarf, [HOLD_EFFECT_CHOICE_SPECS] = sText_HoldEffectChoiceSpecs, [HOLD_EFFECT_DAMP_ROCK] = sText_HoldEffectDampRock, diff --git a/src/battle_main.c b/src/battle_main.c index 0e2afa3dee..7667360488 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -49,6 +49,7 @@ #include "trig.h" #include "tv.h" #include "util.h" +#include "wild_encounter.h" #include "window.h" #include "constants/abilities.h" #include "constants/battle_config.h" @@ -103,6 +104,7 @@ static void RunTurnActionsFunctions(void); static void SetActionsAndBattlersTurnOrder(void); static void sub_803CDF8(void); static bool8 AllAtActionConfirmed(void); +static void TryChangeTurnOrder(void); static void CheckFocusPunch_ClearVarsBeforeTurnStarts(void); static void CheckMegaEvolutionBeforeTurn(void); static void CheckQuickClaw_CustapBerryActivation(void); @@ -232,6 +234,7 @@ EWRAM_DATA struct TotemBoost gTotemBoosts[MAX_BATTLERS_COUNT] = {0}; EWRAM_DATA bool8 gHasFetchedBall = FALSE; EWRAM_DATA u8 gLastUsedBall = 0; EWRAM_DATA u16 gLastThrownBall = 0; +EWRAM_DATA bool8 gSwapDamageCategory = FALSE; // Photon Geyser, Shell Side Arm, Light That Burns the Sky // IWRAM common vars void (*gPreBattleCallback1)(void); @@ -2941,6 +2944,8 @@ static void BattleStartClearSetData(void) gBattleStruct->usedHeldItems[i][1] = 0; gBattleStruct->itemStolen[i].originalItem = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM); } + + gSwapDamageCategory = FALSE; // Photon Geyser, Shell Side Arm, Light That Burns the Sky } void SwitchInClearSetData(void) @@ -3544,7 +3549,11 @@ static void TryDoEventsBeforeFirstTurn(void) return; } } - + + // Check neutralizing gas + if (AbilityBattleEffects(ABILITYEFFECT_NEUTRALIZINGGAS, 0, 0, 0, 0) != 0) + return; + // Check all switch in abilities happening from the fastest mon to slowest. while (gBattleStruct->switchInAbilitiesCounter < gBattlersCount) { @@ -3883,7 +3892,7 @@ static void HandleTurnActionSelectionState(void) gBattleMons[gActiveBattler].ppBonuses, i); } - + BtlController_EmitChooseMove(0, (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) != 0, FALSE, &moveInfo); MarkBattlerForControllerExec(gActiveBattler); } @@ -4680,10 +4689,37 @@ static void CheckMegaEvolutionBeforeTurn(void) } } + #if B_MEGA_EVO_TURN_ORDER <= GEN_6 + gBattleMainFunc = CheckFocusPunch_ClearVarsBeforeTurnStarts; + gBattleStruct->focusPunchBattlerId = 0; + #else + gBattleMainFunc = TryChangeTurnOrder; // This will just do nothing if no mon has mega evolved + #endif +} + +// In gen7, priority and speed are recalculated during the turn in which a pokemon mega evolves +static void TryChangeTurnOrder(void) +{ + s32 i, j; + for (i = 0; i < gBattlersCount - 1; i++) + { + for (j = i + 1; j < gBattlersCount; j++) + { + u8 battler1 = gBattlerByTurnOrder[i]; + u8 battler2 = gBattlerByTurnOrder[j]; + if (gActionsByTurnOrder[i] == B_ACTION_USE_MOVE + && gActionsByTurnOrder[j] == B_ACTION_USE_MOVE) + { + if (GetWhoStrikesFirst(battler1, battler2, FALSE)) + SwapTurnOrder(i, j); + } + } + } gBattleMainFunc = CheckFocusPunch_ClearVarsBeforeTurnStarts; gBattleStruct->focusPunchBattlerId = 0; } + static void CheckFocusPunch_ClearVarsBeforeTurnStarts(void) { u32 i; @@ -5018,6 +5054,8 @@ static void FreeResetData_ReturnToOvOrDoEvolutions(void) { if (!gPaletteFade.active) { + gIsFishingEncounter = FALSE; + gIsSurfingEncounter = FALSE; ResetSpriteData(); if (gLeveledUpInBattle && (gBattleOutcome == B_OUTCOME_WON || gBattleOutcome == B_OUTCOME_CAUGHT)) { @@ -5189,6 +5227,22 @@ void SetTypeBeforeUsingMove(u16 move, u8 battlerAtk) if (ItemId_GetPocket(gBattleMons[battlerAtk].item) == POCKET_BERRIES) gBattleStruct->dynamicMoveType = gNaturalGiftTable[ITEM_TO_BERRY(gBattleMons[battlerAtk].item)].type; } + else if (gBattleMoves[move].effect == EFFECT_TERRAIN_PULSE) + { + if (IsBattlerTerrainAffected(battlerAtk, STATUS_FIELD_TERRAIN_ANY)) + { + if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) + gBattleStruct->dynamicMoveType = TYPE_ELECTRIC | 0x80; + else if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN) + gBattleStruct->dynamicMoveType = TYPE_GRASS | 0x80; + else if (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN) + gBattleStruct->dynamicMoveType = TYPE_FAIRY | 0x80; + else if (gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN) + gBattleStruct->dynamicMoveType = TYPE_PSYCHIC | 0x80; + else //failsafe + gBattleStruct->dynamicMoveType = TYPE_NORMAL | 0x80; + } + } attackerAbility = GetBattlerAbility(battlerAtk); GET_MOVE_TYPE(move, moveType); @@ -5229,6 +5283,10 @@ void SetTypeBeforeUsingMove(u16 move, u8 battlerAtk) { gBattleStruct->dynamicMoveType = 0x80 | TYPE_ELECTRIC; } + else if (move == MOVE_AURA_WHEEL && gBattleMons[battlerAtk].species == SPECIES_MORPEKO_HANGRY) + { + gBattleStruct->dynamicMoveType = 0x80 | TYPE_DARK; + } // Check if a gem should activate. GET_MOVE_TYPE(move, moveType); diff --git a/src/battle_message.c b/src/battle_message.c index a1a24b3b13..d64d02f902 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -549,7 +549,7 @@ static const u8 sText_BecameNimble[] =_("{B_ATK_NAME_WITH_PREFIX} became nimble! static const u8 sText_HurledIntoTheAir[] =_("{B_DEF_NAME_WITH_PREFIX} was hurled\ninto the air!"); static const u8 sText_HeldItemsLoseEffects[] =_("It created a bizarre area in which\nPokémon's held items lose their effects!"); static const u8 sText_FellStraightDown[] =_("{B_DEF_NAME_WITH_PREFIX} fell\nstraight down!"); -static const u8 sText_TransformedIntoWaterType[] =_("{B_DEF_NAME_WITH_PREFIX} transformed\ninto the water type!"); +static const u8 sText_TargetChangedType[] =_("{B_DEF_NAME_WITH_PREFIX} transformed\ninto the {B_BUFF1} type!"); static const u8 sText_PkmnAcquiredSimple[] =_("{B_DEF_NAME_WITH_PREFIX} acquired\nSimple!"); static const u8 sText_KindOffer[] =_("{B_DEF_NAME_WITH_PREFIX}\ntook the kind offer!"); static const u8 sText_ResetsTargetsStatLevels[] =_("{B_DEF_NAME_WITH_PREFIX}'s stat changes\nwere removed!"); @@ -629,7 +629,7 @@ static const u8 sText_TerrainBecomesGrassy[] = _("Grass grew to cover\nthe battl static const u8 sText_TerrainBecomesElectric[] = _("An electric current runs across\nthe battlefield!"); static const u8 sText_TerrainBecomesPsychic[] = _("The battlefield got weird!"); static const u8 sText_TargetElectrified[] = _("The {B_DEF_NAME_WITH_PREFIX}'s moves\nhave been electrified!"); -static const u8 sText_AssaultVestDoesntAllow[] = _("The effects of the {B_LAST_ITEM} prevent status\nmoves from being used!\p"); +static const u8 sText_AssaultVestDoesntAllow[] = _("{B_LAST_ITEM}'s effects prevent\nstatus moves from being used!\p"); static const u8 sText_GravityPreventsUsage[] = _("{B_ATK_NAME_WITH_PREFIX} can't use {B_CURRENT_MOVE}\nbecause of gravity!\p"); static const u8 sText_HealBlockPreventsUsage[] = _("{B_ATK_NAME_WITH_PREFIX} was\nprevented from healing!\p"); static const u8 sText_MegaEvoReacting[] = _("{B_ATK_NAME_WITH_PREFIX}'s {B_LAST_ITEM} is \nreacting to {B_ATK_TRAINER_NAME}'s Mega Ring!"); @@ -727,9 +727,20 @@ static const u8 sText_AbilityAllowsOnlyMove[] = _("{B_ATK_ABILITY} allows the\nu static const u8 sText_SwappedAbilities[] = _("{B_DEF_NAME_WITH_PREFIX} swapped Abilities\nwith its target!"); static const u8 sText_PastelVeilProtected[] = _("{B_DEF_NAME_WITH_PREFIX} is protected\nby a pastel veil!"); static const u8 sText_PastelVeilEnters[] = _("{B_DEF_NAME_WITH_PREFIX} was cured\nof its poisoning!"); +static const u8 sText_BattlerTypeChangedTo[] = _("{B_BUFF1}'s type\nchanged to {B_BUFF2}!"); +static const u8 sText_BothCanNoLongerEscape[] = _("Neither POKéMON can run away!"); +static const u8 sText_CantEscapeDueToUsedMove[] = _("{B_ATK_NAME_WITH_PREFIX} can no longer escape\nbecause it used {B_CURRENT_MOVE}!"); +static const u8 sText_PkmnBecameWeakerToFire[] = _("{B_DEF_NAME_WITH_PREFIX} became\nweaker to fire!"); +static const u8 sText_PkmnAboutToBeAttackedByItsItem[] = _("{B_DEF_NAME_WITH_PREFIX} is about\nto be attacked by its {B_BUFF1}!"); +static const u8 sText_CantEscapeBecauseOfCurrentMove[] = _("{B_DEF_NAME_WITH_PREFIX} can no longer escape\nbecause of {B_CURRENT_MOVE}!"); +static const u8 sText_NeutralizingGasEnters[] = _("Neutralizing Gas filled the area!"); +static const u8 sText_NeutralizingGasOver[] = _("The effects of Neutralizing\nGas wore off!"); const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = { + [STRINGID_NEUTRALIZINGGASOVER - 12] = sText_NeutralizingGasOver, + [STRINGID_NEUTRALIZINGGASENTERS - 12] = sText_NeutralizingGasEnters, + [STRINGID_BATTLERTYPECHANGEDTO - 12] = sText_BattlerTypeChangedTo, [STRINGID_PASTELVEILENTERS - 12] = sText_PastelVeilEnters, [STRINGID_PASTELVEILPROTECTED -12] = sText_PastelVeilProtected, [STRINGID_SWAPPEDABILITIES - 12] = sText_SwappedAbilities, @@ -1198,7 +1209,7 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = [STRINGID_PKMNTWISTEDDIMENSIONS - 12] = sText_PkmnTwistedDimensions, [STRINGID_POINTEDSTONESFLOAT - 12] = sText_PointedStonesFloat, [STRINGID_CLOAKEDINMYSTICALMOONLIGHT - 12] = sText_CloakedInMysticalMoonlight, - [STRINGID_TRAPPERBYSWIRLINGMAGMA - 12] = sText_TrappedBySwirlingMagma, + [STRINGID_TRAPPEDBYSWIRLINGMAGMA - 12] = sText_TrappedBySwirlingMagma, [STRINGID_VANISHEDINSTANTLY - 12] = sText_VanishedInstantly, [STRINGID_PROTECTEDTEAM - 12] = sText_ProtectedTeam, [STRINGID_SHAREDITSGUARD - 12] = sText_SharedItsGuard, @@ -1208,7 +1219,7 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = [STRINGID_HURLEDINTOTHEAIR - 12] = sText_HurledIntoTheAir, [STRINGID_HELDITEMSLOSEEFFECTS - 12] = sText_HeldItemsLoseEffects, [STRINGID_FELLSTRAIGHTDOWN - 12] = sText_FellStraightDown, - [STRINGID_TRANSFORMEDINTOWATERTYPE - 12] = sText_TransformedIntoWaterType, + [STRINGID_TARGETCHANGEDTYPE - 12] = sText_TargetChangedType, [STRINGID_PKMNACQUIREDSIMPLE - 12] = sText_PkmnAcquiredSimple, [STRINGID_EMPTYSTRING5 - 12] = sText_EmptyString4, [STRINGID_KINDOFFER - 12] = sText_KindOffer, @@ -1318,6 +1329,11 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = [STRINGID_AURABREAKENTERS - 12] = sText_AuraBreakActivates, [STRINGID_COMATOSEENTERS - 12] = sText_ComatoseActivates, [STRINGID_SCREENCLEANERENTERS - 12] = sText_ScreenCleanerActivates, + [STRINGID_BOTHCANNOLONGERESCAPE - 12] = sText_BothCanNoLongerEscape, + [STRINGID_CANTESCAPEDUETOUSEDMOVE - 12] = sText_CantEscapeDueToUsedMove, + [STRINGID_PKMNBECAMEWEAKERTOFIRE - 12] = sText_PkmnBecameWeakerToFire, + [STRINGID_ABOUTTOUSEPOLTERGEIST - 12] = sText_PkmnAboutToBeAttackedByItsItem, + [STRINGID_CANTESCAPEBECAUSEOFCURRENTMOVE - 12] = sText_CantEscapeBecauseOfCurrentMove, }; const u16 gMentalHerbCureStringIds[] = @@ -1380,6 +1396,7 @@ const u16 gSwitchInAbilityStringIds[] = [B_MSG_SWITCHIN_ASONE] = STRINGID_ASONEENTERS, [B_MSG_SWITCHIN_CURIOUS_MEDICINE] = STRINGID_CURIOUSMEDICINEENTERS, [B_MSG_SWITCHIN_PASTEL_VEIL] = STRINGID_PASTELVEILENTERS, + [B_MSG_SWITCHIN_NEUTRALIZING_GAS] = STRINGID_NEUTRALIZINGGASENTERS, }; const u16 gMissStringIds[] = @@ -1533,16 +1550,17 @@ const u16 gFirstTurnOfTwoStringIds[] = [B_MSG_TURN1_FREEZE_SHOCK] = STRINGID_CLOAKEDINAFREEZINGLIGHT, }; -// Index copied from move's index in gTrappingMoves +// Index copied from move's index in sTrappingMoves const u16 gWrappedStringIds[] = { - STRINGID_PKMNSQUEEZEDBYBIND, // MOVE_BIND - STRINGID_PKMNWRAPPEDBY, // MOVE_WRAP - STRINGID_PKMNTRAPPEDINVORTEX, // MOVE_FIRE_SPIN - STRINGID_PKMNCLAMPED, // MOVE_CLAMP - STRINGID_PKMNTRAPPEDINVORTEX, // MOVE_WHIRLPOOL - STRINGID_PKMNTRAPPEDBYSANDTOMB,// MOVE_SAND_TOMB - STRINGID_INFESTATION, // MOVE_INFESTATION + STRINGID_PKMNSQUEEZEDBYBIND, // MOVE_BIND + STRINGID_PKMNWRAPPEDBY, // MOVE_WRAP + STRINGID_PKMNTRAPPEDINVORTEX, // MOVE_FIRE_SPIN + STRINGID_PKMNCLAMPED, // MOVE_CLAMP + STRINGID_PKMNTRAPPEDINVORTEX, // MOVE_WHIRLPOOL + STRINGID_PKMNTRAPPEDBYSANDTOMB, // MOVE_SAND_TOMB + STRINGID_TRAPPEDBYSWIRLINGMAGMA, // MOVE_MAGMA_STORM + STRINGID_INFESTATION, // MOVE_INFESTATION }; const u16 gMistUsedStringIds[] = @@ -1753,11 +1771,6 @@ const u16 gCaughtMonStringIds[] = [B_MSG_LANETTES_BOX_FULL] = STRINGID_PKMNBOXLANETTESPCFULL, }; -const u16 gTrappingMoves[] = -{ - MOVE_BIND, MOVE_WRAP, MOVE_FIRE_SPIN, MOVE_CLAMP, MOVE_WHIRLPOOL, MOVE_SAND_TOMB, MOVE_INFESTATION, 0xFFFF -}; - const u16 gRoomsStringIds[] = { STRINGID_PKMNTWISTEDDIMENSIONS, STRINGID_TRICKROOMENDS, diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 0fb2e55995..8c328926df 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -42,6 +42,8 @@ #include "constants/battle_string_ids.h" #include "battle_setup.h" #include "overworld.h" +#include "wild_encounter.h" +#include "rtc.h" #include "party_menu.h" #include "constants/battle_config.h" #include "battle_arena.h" @@ -54,6 +56,7 @@ #include "constants/rgb.h" #include "data.h" #include "constants/party_menu.h" +#include "battle_util.h" extern struct MusicPlayerInfo gMPlayInfo_BGM; extern struct Evolution gEvolutionTable[][EVOS_PER_MON]; @@ -278,6 +281,11 @@ static const s32 sExperienceScalingFactors[] = 159767, }; +static const u16 sTrappingMoves[] = +{ + MOVE_BIND, MOVE_WRAP, MOVE_FIRE_SPIN, MOVE_CLAMP, MOVE_WHIRLPOOL, MOVE_SAND_TOMB, MOVE_MAGMA_STORM, MOVE_INFESTATION, 0xFFFF +}; + #define STAT_CHANGE_WORKED 0 #define STAT_CHANGE_DIDNT_WORK 1 @@ -1091,18 +1099,76 @@ static const u16 sMoveEffectsForbiddenToInstruct[] = FORBIDDEN_INSTRUCT_END }; -static const u16 sNaturePowerMoves[] = +static const u16 sNaturePowerMoves[BATTLE_TERRAIN_COUNT] = { +#if B_NATURE_POWER_MOVES >= GEN_7 [BATTLE_TERRAIN_GRASS] = MOVE_ENERGY_BALL, [BATTLE_TERRAIN_LONG_GRASS] = MOVE_ENERGY_BALL, [BATTLE_TERRAIN_SAND] = MOVE_EARTH_POWER, - [BATTLE_TERRAIN_UNDERWATER] = MOVE_HYDRO_PUMP, [BATTLE_TERRAIN_WATER] = MOVE_HYDRO_PUMP, [BATTLE_TERRAIN_POND] = MOVE_HYDRO_PUMP, [BATTLE_TERRAIN_MOUNTAIN] = MOVE_EARTH_POWER, - [BATTLE_TERRAIN_CAVE] = MOVE_POWER_GEM, + [BATTLE_TERRAIN_CAVE] = MOVE_EARTH_POWER, [BATTLE_TERRAIN_BUILDING] = MOVE_TRI_ATTACK, - [BATTLE_TERRAIN_PLAIN] = MOVE_TRI_ATTACK + [BATTLE_TERRAIN_PLAIN] = MOVE_TRI_ATTACK, + [BATTLE_TERRAIN_SNOW] = MOVE_ICE_BEAM, +#elif B_NATURE_POWER_MOVES == GEN_6 + [BATTLE_TERRAIN_GRASS] = MOVE_ENERGY_BALL, + [BATTLE_TERRAIN_LONG_GRASS] = MOVE_ENERGY_BALL, + [BATTLE_TERRAIN_SAND] = MOVE_EARTH_POWER, + [BATTLE_TERRAIN_WATER] = MOVE_HYDRO_PUMP, + [BATTLE_TERRAIN_POND] = MOVE_HYDRO_PUMP, + [BATTLE_TERRAIN_MOUNTAIN] = MOVE_EARTH_POWER, + [BATTLE_TERRAIN_CAVE] = MOVE_EARTH_POWER, + [BATTLE_TERRAIN_BUILDING] = MOVE_TRI_ATTACK, + [BATTLE_TERRAIN_PLAIN] = MOVE_TRI_ATTACK, + [BATTLE_TERRAIN_SNOW] = MOVE_FROST_BREATH, +#elif B_NATURE_POWER_MOVES == GEN_5 + [BATTLE_TERRAIN_GRASS] = MOVE_SEED_BOMB, + [BATTLE_TERRAIN_LONG_GRASS] = MOVE_SEED_BOMB, + [BATTLE_TERRAIN_SAND] = MOVE_EARTHQUAKE, + [BATTLE_TERRAIN_WATER] = MOVE_HYDRO_PUMP, + [BATTLE_TERRAIN_POND] = MOVE_HYDRO_PUMP, + [BATTLE_TERRAIN_MOUNTAIN] = MOVE_EARTHQUAKE, + [BATTLE_TERRAIN_CAVE] = MOVE_EARTHQUAKE, + [BATTLE_TERRAIN_BUILDING] = MOVE_TRI_ATTACK, + [BATTLE_TERRAIN_PLAIN] = MOVE_EARTHQUAKE, + [BATTLE_TERRAIN_SNOW] = MOVE_BLIZZARD, +#elif B_NATURE_POWER_MOVES == GEN_4 + [BATTLE_TERRAIN_GRASS] = MOVE_SEED_BOMB, + [BATTLE_TERRAIN_LONG_GRASS] = MOVE_SEED_BOMB, + [BATTLE_TERRAIN_SAND] = MOVE_EARTHQUAKE, + [BATTLE_TERRAIN_WATER] = MOVE_HYDRO_PUMP, + [BATTLE_TERRAIN_POND] = MOVE_HYDRO_PUMP, + [BATTLE_TERRAIN_MOUNTAIN] = MOVE_ROCK_SLIDE, + [BATTLE_TERRAIN_CAVE] = MOVE_ROCK_SLIDE, + [BATTLE_TERRAIN_BUILDING] = MOVE_TRI_ATTACK, + [BATTLE_TERRAIN_PLAIN] = MOVE_EARTHQUAKE, + [BATTLE_TERRAIN_SNOW] = MOVE_BLIZZARD, +#else // Gen 1-3 + [BATTLE_TERRAIN_GRASS] = MOVE_STUN_SPORE, + [BATTLE_TERRAIN_LONG_GRASS] = MOVE_RAZOR_LEAF, + [BATTLE_TERRAIN_SAND] = MOVE_EARTHQUAKE, + [BATTLE_TERRAIN_WATER] = MOVE_SURF, + [BATTLE_TERRAIN_POND] = MOVE_BUBBLE_BEAM, + [BATTLE_TERRAIN_MOUNTAIN] = MOVE_ROCK_SLIDE, + [BATTLE_TERRAIN_CAVE] = MOVE_SHADOW_BALL, + [BATTLE_TERRAIN_BUILDING] = MOVE_SWIFT, + [BATTLE_TERRAIN_PLAIN] = MOVE_SWIFT, + [BATTLE_TERRAIN_SNOW] = MOVE_BLIZZARD, +#endif + [BATTLE_TERRAIN_UNDERWATER] = MOVE_HYDRO_PUMP, + [BATTLE_TERRAIN_SOARING] = MOVE_AIR_SLASH, + [BATTLE_TERRAIN_SKY_PILLAR] = MOVE_AIR_SLASH, + [BATTLE_TERRAIN_BURIAL_GROUND] = MOVE_SHADOW_BALL, + [BATTLE_TERRAIN_PUDDLE] = MOVE_MUD_BOMB, + [BATTLE_TERRAIN_MARSH] = MOVE_MUD_BOMB, + [BATTLE_TERRAIN_SWAMP] = MOVE_MUD_BOMB, + [BATTLE_TERRAIN_ICE] = MOVE_ICE_BEAM, + [BATTLE_TERRAIN_VOLCANO] = MOVE_LAVA_PLUME, + [BATTLE_TERRAIN_DISTORTION_WORLD] = MOVE_TRI_ATTACK, + [BATTLE_TERRAIN_SPACE] = MOVE_DRACO_METEOR, + [BATTLE_TERRAIN_ULTRA_SPACE] = MOVE_PSYSHOCK, }; static const u16 sPickupItems[] = @@ -1147,27 +1213,38 @@ static const u8 sPickupProbabilities[] = 30, 40, 50, 60, 70, 80, 90, 94, 98 }; -static const u8 sTerrainToType[] = +static const u8 sTerrainToType[BATTLE_TERRAIN_COUNT] = { - [BATTLE_TERRAIN_GRASS] = TYPE_GRASS, - [BATTLE_TERRAIN_LONG_GRASS] = TYPE_GRASS, - [BATTLE_TERRAIN_SAND] = TYPE_GROUND, - [BATTLE_TERRAIN_UNDERWATER] = TYPE_WATER, - [BATTLE_TERRAIN_WATER] = TYPE_WATER, - [BATTLE_TERRAIN_POND] = TYPE_WATER, - [BATTLE_TERRAIN_MOUNTAIN] = TYPE_GROUND, - [BATTLE_TERRAIN_CAVE] = TYPE_ROCK, - [BATTLE_TERRAIN_BUILDING] = TYPE_NORMAL, - [BATTLE_TERRAIN_PLAIN] = TYPE_NORMAL, -}; - -// - ITEM_ULTRA_BALL skips Master Ball and ITEM_NONE -static const u8 sBallCatchBonuses[] = -{ - [ITEM_ULTRA_BALL - ITEM_ULTRA_BALL] = 20, - [ITEM_GREAT_BALL - ITEM_ULTRA_BALL] = 15, - [ITEM_POKE_BALL - ITEM_ULTRA_BALL] = 10, - [ITEM_SAFARI_BALL - ITEM_ULTRA_BALL] = 15 + [BATTLE_TERRAIN_GRASS] = TYPE_GRASS, + [BATTLE_TERRAIN_LONG_GRASS] = TYPE_GRASS, + [BATTLE_TERRAIN_SAND] = TYPE_GROUND, + [BATTLE_TERRAIN_UNDERWATER] = TYPE_WATER, + [BATTLE_TERRAIN_WATER] = TYPE_WATER, + [BATTLE_TERRAIN_POND] = TYPE_WATER, + [BATTLE_TERRAIN_CAVE] = TYPE_ROCK, + [BATTLE_TERRAIN_BUILDING] = TYPE_NORMAL, + [BATTLE_TERRAIN_SOARING] = TYPE_FLYING, + [BATTLE_TERRAIN_SKY_PILLAR] = TYPE_FLYING, + [BATTLE_TERRAIN_BURIAL_GROUND] = TYPE_GHOST, + [BATTLE_TERRAIN_PUDDLE] = TYPE_GROUND, + [BATTLE_TERRAIN_MARSH] = TYPE_GROUND, + [BATTLE_TERRAIN_SWAMP] = TYPE_GROUND, + [BATTLE_TERRAIN_SNOW] = TYPE_ICE, + [BATTLE_TERRAIN_ICE] = TYPE_ICE, + [BATTLE_TERRAIN_VOLCANO] = TYPE_FIRE, + [BATTLE_TERRAIN_DISTORTION_WORLD] = TYPE_NORMAL, + [BATTLE_TERRAIN_SPACE] = TYPE_DRAGON, + [BATTLE_TERRAIN_ULTRA_SPACE] = TYPE_PSYCHIC, +#if B_CAMOUFLAGE_TYPES >= GEN_5 + [BATTLE_TERRAIN_MOUNTAIN] = TYPE_GROUND, + [BATTLE_TERRAIN_PLAIN] = TYPE_GROUND, +#elif B_CAMOUFLAGE_TYPES == GEN_4 + [BATTLE_TERRAIN_MOUNTAIN] = TYPE_ROCK, + [BATTLE_TERRAIN_PLAIN] = TYPE_GROUND, +#else + [BATTLE_TERRAIN_MOUNTAIN] = TYPE_ROCK, + [BATTLE_TERRAIN_PLAIN] = TYPE_NORMAL, +#endif }; // In Battle Palace, moves are chosen based on the pokemons nature rather than by the player @@ -1236,47 +1313,6 @@ static const u8 sBattlePalaceNatureToFlavorTextId[NUM_NATURES] = [NATURE_QUIRKY] = B_MSG_EAGER_FOR_MORE, }; -bool32 IsBattlerProtected(u8 battlerId, u16 move) -{ - // Decorate bypasses protect and detect, but not crafty shield - if (move == MOVE_DECORATE) - { - if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_CRAFTY_SHIELD) - return TRUE; - else if (gProtectStructs[battlerId].protected) - return FALSE; - } - - if (!(gBattleMoves[move].flags & FLAG_PROTECT_AFFECTED)) - return FALSE; - else if (gBattleMoves[move].effect == MOVE_EFFECT_FEINT) - return FALSE; - else if (gProtectStructs[battlerId].protected) - return TRUE; - else if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_WIDE_GUARD - && gBattleMoves[move].target & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY)) - return TRUE; - else if (gProtectStructs[battlerId].banefulBunkered) - return TRUE; - else if (gProtectStructs[battlerId].obstructed && !IS_MOVE_STATUS(move)) - return TRUE; - else if (gProtectStructs[battlerId].spikyShielded) - return TRUE; - else if (gProtectStructs[battlerId].kingsShielded && gBattleMoves[move].power != 0) - return TRUE; - else if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_QUICK_GUARD - && GetChosenMovePriority(gBattlerAttacker) > 0) - return TRUE; - else if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_CRAFTY_SHIELD - && IS_MOVE_STATUS(move)) - return TRUE; - else if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_MAT_BLOCK - && !IS_MOVE_STATUS(move)) - return TRUE; - else - return FALSE; -} - static bool32 NoTargetPresent(u32 move) { if (!IsBattlerAlive(gBattlerTarget)) @@ -1494,7 +1530,7 @@ static void Cmd_attackcanceler(void) && ((!IsTwoTurnsMove(gCurrentMove) || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS))) && gBattleMoves[gCurrentMove].effect != EFFECT_SUCKER_PUNCH) { - if (gBattleMoves[gCurrentMove].flags & FLAG_MAKES_CONTACT) + if (IsMoveMakingContact(gCurrentMove, gBattlerAttacker)) gProtectStructs[gBattlerAttacker].touchedProtectLike = TRUE; CancelMultiTurnMoves(gBattlerAttacker); gMoveResultFlags |= MOVE_RESULT_MISSED; @@ -1821,11 +1857,13 @@ static void Cmd_ppreduce(void) static const u8 sCriticalHitChance[] = {16, 8, 4, 3, 2}; // Gens 2,3,4,5 #endif // B_CRIT_CHANCE +#define BENEFITS_FROM_LEEK(battler, holdEffect)((holdEffect == HOLD_EFFECT_LEEK) && (GET_BASE_SPECIES_ID(gBattleMons[battler].species) == SPECIES_FARFETCHD || gBattleMons[battler].species == SPECIES_SIRFETCHD)) s32 CalcCritChanceStage(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recordAbility) { s32 critChance = 0; u32 abilityAtk = GetBattlerAbility(gBattlerAttacker); u32 abilityDef = GetBattlerAbility(gBattlerTarget); + u32 holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE); if (gSideStatuses[battlerDef] & SIDE_STATUS_LUCKY_CHANT || gStatuses3[gBattlerAttacker] & STATUS3_CANT_SCORE_A_CRIT) @@ -1841,19 +1879,21 @@ s32 CalcCritChanceStage(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recordAbi else if (gStatuses3[battlerAtk] & STATUS3_LASER_FOCUS || gBattleMoves[move].effect == EFFECT_ALWAYS_CRIT || (abilityAtk == ABILITY_MERCILESS && gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY) - || move == MOVE_SURGING_STRIKES) + || move == MOVE_SURGING_STRIKES + #if B_LEEK_ALWAYS_CRIT >= GEN_6 + || ((gBattleMoves[gCurrentMove].flags & FLAG_HIGH_CRIT) && BENEFITS_FROM_LEEK(battlerAtk, holdEffectAtk)) + #endif + ) { critChance = -2; } else { - u32 holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE); - critChance = 2 * ((gBattleMons[gBattlerAttacker].status2 & STATUS2_FOCUS_ENERGY) != 0) + ((gBattleMoves[gCurrentMove].flags & FLAG_HIGH_CRIT) != 0) + (holdEffectAtk == HOLD_EFFECT_SCOPE_LENS) + 2 * (holdEffectAtk == HOLD_EFFECT_LUCKY_PUNCH && gBattleMons[gBattlerAttacker].species == SPECIES_CHANSEY) - + 2 * (holdEffectAtk == HOLD_EFFECT_STICK && gBattleMons[gBattlerAttacker].species == SPECIES_FARFETCHD) + + 2 * BENEFITS_FROM_LEEK(battlerAtk, holdEffectAtk) + (abilityAtk == ABILITY_SUPER_LUCK); if (critChance >= ARRAY_COUNT(sCriticalHitChance)) @@ -1862,6 +1902,7 @@ s32 CalcCritChanceStage(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recordAbi return critChance; } +#undef BENEFITS_FROM_LEEK s8 GetInverseCritChance(u8 battlerAtk, u8 battlerDef, u32 move) { @@ -2973,9 +3014,9 @@ void SetMoveEffect(bool32 primary, u32 certain) for (gBattleCommunication[MULTISTRING_CHOOSER] = 0; ; gBattleCommunication[MULTISTRING_CHOOSER]++) { - if (gBattleCommunication[MULTISTRING_CHOOSER] > 5) + if (gBattleCommunication[MULTISTRING_CHOOSER] > ARRAY_COUNT(sTrappingMoves) - 1) break; - if (gTrappingMoves[gBattleCommunication[MULTISTRING_CHOOSER]] == gCurrentMove) + if (sTrappingMoves[gBattleCommunication[MULTISTRING_CHOOSER]] == gCurrentMove) break; } } @@ -2987,9 +3028,10 @@ void SetMoveEffect(bool32 primary, u32 certain) case MOVE_EFFECT_SP_DEF_PLUS_1: case MOVE_EFFECT_ACC_PLUS_1: case MOVE_EFFECT_EVS_PLUS_1: - if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(1), + if (NoAliveMonsForEitherParty() + || ChangeStatBuffs(SET_STAT_BUFF_VALUE(1), gBattleScripting.moveEffect - MOVE_EFFECT_ATK_PLUS_1 + 1, - affectsUser, 0)) + affectsUser | STAT_BUFF_UPDATE_MOVE_EFFECT, 0)) { gBattlescriptCurrInstr++; } @@ -3014,7 +3056,7 @@ void SetMoveEffect(bool32 primary, u32 certain) if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(1) | STAT_BUFF_NEGATIVE, gBattleScripting.moveEffect - MOVE_EFFECT_ATK_MINUS_1 + 1, - flags, gBattlescriptCurrInstr + 1)) + flags | STAT_BUFF_UPDATE_MOVE_EFFECT, gBattlescriptCurrInstr + 1)) { if (!mirrorArmorReflected) gBattlescriptCurrInstr++; @@ -3034,9 +3076,10 @@ void SetMoveEffect(bool32 primary, u32 certain) case MOVE_EFFECT_SP_DEF_PLUS_2: case MOVE_EFFECT_ACC_PLUS_2: case MOVE_EFFECT_EVS_PLUS_2: - if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(2), + if (NoAliveMonsForEitherParty() + || ChangeStatBuffs(SET_STAT_BUFF_VALUE(2), gBattleScripting.moveEffect - MOVE_EFFECT_ATK_PLUS_2 + 1, - affectsUser, 0)) + affectsUser | STAT_BUFF_UPDATE_MOVE_EFFECT, 0)) { gBattlescriptCurrInstr++; } @@ -3060,7 +3103,7 @@ void SetMoveEffect(bool32 primary, u32 certain) flags |= STAT_BUFF_ALLOW_PTR; if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(2) | STAT_BUFF_NEGATIVE, gBattleScripting.moveEffect - MOVE_EFFECT_ATK_MINUS_2 + 1, - flags, gBattlescriptCurrInstr + 1)) + flags | STAT_BUFF_UPDATE_MOVE_EFFECT, gBattlescriptCurrInstr + 1)) { if (!mirrorArmorReflected) gBattlescriptCurrInstr++; @@ -3122,7 +3165,11 @@ void SetMoveEffect(bool32 primary, u32 certain) RecordAbilityBattle(gBattlerTarget, gLastUsedAbility); } else if (gBattleMons[gBattlerAttacker].item != 0 + #ifdef ITEM_EXPANSION + || gBattleMons[gBattlerTarget].item == ITEM_ENIGMA_BERRY_E_READER + #else || gBattleMons[gBattlerTarget].item == ITEM_ENIGMA_BERRY + #endif || gBattleMons[gBattlerTarget].item == 0) { gBattlescriptCurrInstr++; @@ -3148,8 +3195,15 @@ void SetMoveEffect(bool32 primary, u32 certain) gBattlescriptCurrInstr++; break; case MOVE_EFFECT_ALL_STATS_UP: - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_AllStatsUp; + if (NoAliveMonsForEitherParty()) + { + gBattlescriptCurrInstr++; + } + else + { + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_AllStatsUp; + } break; case MOVE_EFFECT_RAPIDSPIN: BattleScriptPush(gBattlescriptCurrInstr + 1); @@ -3395,6 +3449,36 @@ void SetMoveEffect(bool32 primary, u32 certain) gBattlescriptCurrInstr = BattleScript_MoveEffectBugBite; } break; + case MOVE_EFFECT_RELIC_SONG: + if (GetBattlerAbility(gBattlerAttacker) != ABILITY_SHEER_FORCE) + { + if (gBattleMons[gBattlerAttacker].species == SPECIES_MELOETTA) + { + gBattleMons[gBattlerAttacker].species = SPECIES_MELOETTA_PIROUETTE; + BattleScriptPushCursorAndCallback(BattleScript_AttackerFormChangeMoveEffect); + } + else if (gBattleMons[gBattlerAttacker].species == SPECIES_MELOETTA_PIROUETTE) + { + gBattleMons[gBattlerAttacker].species = SPECIES_MELOETTA; + BattleScriptPushCursorAndCallback(BattleScript_AttackerFormChangeMoveEffect); + } + } + break; + case MOVE_EFFECT_TRAP_BOTH: + if (!(gBattleMons[gBattlerTarget].status2 & STATUS2_ESCAPE_PREVENTION) && !(gBattleMons[gBattlerAttacker].status2 & STATUS2_ESCAPE_PREVENTION)) + { + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_BothCanNoLongerEscape; + } + if (!gBattleMons[gBattlerTarget].status2 & STATUS2_ESCAPE_PREVENTION) + gDisableStructs[gBattlerTarget].battlerPreventingEscape = gBattlerAttacker; + + if (!(gBattleMons[gBattlerAttacker].status2 & STATUS2_ESCAPE_PREVENTION)) + gDisableStructs[gBattlerAttacker].battlerPreventingEscape = gBattlerTarget; + + gBattleMons[gBattlerTarget].status2 |= STATUS2_ESCAPE_PREVENTION; + gBattleMons[gBattlerAttacker].status2 |= STATUS2_ESCAPE_PREVENTION; + break; } } } @@ -5378,6 +5462,14 @@ static void Cmd_moveend(void) *(gBattleStruct->moveTarget + gBattlerAttacker) = gSpecialStatuses[gBattlerAttacker].instructedChosenTarget & 0x3; if (gSpecialStatuses[gBattlerAttacker].dancerOriginalTarget) *(gBattleStruct->moveTarget + gBattlerAttacker) = gSpecialStatuses[gBattlerAttacker].dancerOriginalTarget & 0x3; + + #if B_RAMPAGE_CANCELLING >= GEN_5 + if (gBattleMoves[gCurrentMove].effect == EFFECT_RAMPAGE // If we're rampaging + && (gMoveResultFlags & MOVE_RESULT_NO_EFFECT) // And it is unusable + && (gBattleMons[gBattlerAttacker].status2 & STATUS2_LOCK_CONFUSE) != STATUS2_LOCK_CONFUSE_TURN(1)) // And won't end this turn + CancelMultiTurnMoves(gBattlerAttacker); // Cancel it + #endif + gProtectStructs[gBattlerAttacker].usesBouncedMove = FALSE; gProtectStructs[gBattlerAttacker].targetAffected = FALSE; gBattleStruct->ateBoost[gBattlerAttacker] = 0; @@ -6080,8 +6172,17 @@ static void Cmd_switchineffects(void) gHitMarker &= ~(HITMARKER_FAINTED(gActiveBattler)); gSpecialStatuses[gActiveBattler].flag40 = 0; - - if (!(gSideStatuses[GetBattlerSide(gActiveBattler)] & SIDE_STATUS_SPIKES_DAMAGED) + + // Neutralizing Gas announces itself before hazards + if (gBattleMons[gActiveBattler].ability == ABILITY_NEUTRALIZING_GAS && gSpecialStatuses[gActiveBattler].announceNeutralizingGas == 0) + { + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWITCHIN_NEUTRALIZING_GAS; + gSpecialStatuses[gActiveBattler].announceNeutralizingGas = TRUE; + gBattlerAbility = gActiveBattler; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_SwitchInAbilityMsgRet; + } + else if (!(gSideStatuses[GetBattlerSide(gActiveBattler)] & SIDE_STATUS_SPIKES_DAMAGED) && (gSideStatuses[GetBattlerSide(gActiveBattler)] & SIDE_STATUS_SPIKES) && GetBattlerAbility(gActiveBattler) != ABILITY_MAGIC_GUARD && IsBattlerAffectedByHazards(gActiveBattler, FALSE) @@ -6155,7 +6256,7 @@ static void Cmd_switchineffects(void) { // There is a hack here to ensure the truant counter will be 0 when the battler's next turn starts. // The truant counter is not updated in the case where a mon switches in after a lost judgement in the battle arena. - if (gBattleMons[gActiveBattler].ability == ABILITY_TRUANT + if (GetBattlerAbility(gActiveBattler) == ABILITY_TRUANT && gCurrentActionFuncId != B_ACTION_USE_MOVE && !gDisableStructs[gActiveBattler].truantSwitchInHack) gDisableStructs[gActiveBattler].truantCounter = 1; @@ -7225,19 +7326,19 @@ static void HandleTerrainMove(u32 moveEffect) switch (moveEffect) { case EFFECT_MISTY_TERRAIN: - statusFlag = STATUS_FIELD_MISTY_TERRAIN, timer = &gFieldTimers.mistyTerrainTimer; + statusFlag = STATUS_FIELD_MISTY_TERRAIN, timer = &gFieldTimers.terrainTimer; gBattleCommunication[MULTISTRING_CHOOSER] = 0; break; case EFFECT_GRASSY_TERRAIN: - statusFlag = STATUS_FIELD_GRASSY_TERRAIN, timer = &gFieldTimers.grassyTerrainTimer; + statusFlag = STATUS_FIELD_GRASSY_TERRAIN, timer = &gFieldTimers.terrainTimer; gBattleCommunication[MULTISTRING_CHOOSER] = 1; break; case EFFECT_ELECTRIC_TERRAIN: - statusFlag = STATUS_FIELD_ELECTRIC_TERRAIN, timer = &gFieldTimers.electricTerrainTimer; + statusFlag = STATUS_FIELD_ELECTRIC_TERRAIN, timer = &gFieldTimers.terrainTimer; gBattleCommunication[MULTISTRING_CHOOSER] = 2; break; case EFFECT_PSYCHIC_TERRAIN: - statusFlag = STATUS_FIELD_PSYCHIC_TERRAIN, timer = &gFieldTimers.psychicTerrainTimer; + statusFlag = STATUS_FIELD_PSYCHIC_TERRAIN, timer = &gFieldTimers.terrainTimer; gBattleCommunication[MULTISTRING_CHOOSER] = 3; break; } @@ -7346,7 +7447,7 @@ u32 IsLeafGuardProtected(u32 battler) bool32 IsShieldsDownProtected(u32 battler) { - return (gBattleMons[battler].ability == ABILITY_SHIELDS_DOWN + return (GetBattlerAbility(battler) == ABILITY_SHIELDS_DOWN && GetFormIdFromFormSpeciesId(gBattleMons[battler].species) < GetFormIdFromFormSpeciesId(SPECIES_MINIOR_CORE_RED)); // Minior is not in core form } @@ -7814,6 +7915,7 @@ static void Cmd_various(void) break; case VARIOUS_SWITCHIN_ABILITIES: gBattlescriptCurrInstr += 3; + AbilityBattleEffects(ABILITYEFFECT_NEUTRALIZINGGAS, gActiveBattler, 0, 0, 0); AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, gActiveBattler, 0, 0, 0); AbilityBattleEffects(ABILITYEFFECT_INTIMIDATE2, gActiveBattler, 0, 0, 0); AbilityBattleEffects(ABILITYEFFECT_TRACE2, gActiveBattler, 0, 0, 0); @@ -7994,6 +8096,9 @@ static void Cmd_various(void) } else { + if (gBattleMons[gBattlerTarget].ability == ABILITY_NEUTRALIZING_GAS) + gSpecialStatuses[gBattlerTarget].neutralizingGasRemoved = TRUE; + gBattleMons[gBattlerTarget].ability = ABILITY_SIMPLE; gBattlescriptCurrInstr += 7; } @@ -8150,13 +8255,15 @@ static void Cmd_various(void) } return; case VARIOUS_TRY_SOAK: - if (gBattleMons[gBattlerTarget].type1 == TYPE_WATER && gBattleMons[gBattlerTarget].type2 == TYPE_WATER) + if (gBattleMons[gBattlerTarget].type1 == gBattleMoves[gCurrentMove].type + && gBattleMons[gBattlerTarget].type2 == gBattleMoves[gCurrentMove].type) { gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); } else { - SET_BATTLER_TYPE(gBattlerTarget, TYPE_WATER); + SET_BATTLER_TYPE(gBattlerTarget, gBattleMoves[gCurrentMove].type); + PREPARE_TYPE_BUFFER(gBattleTextBuff1, gBattleMoves[gCurrentMove].type); gBattlescriptCurrInstr += 7; } return; @@ -8283,6 +8390,9 @@ static void Cmd_various(void) case VARIOUS_ARGUMENT_STATUS_EFFECT: switch (gBattleMoves[gCurrentMove].argument) { + case STATUS1_SLEEP: + gBattleScripting.moveEffect = MOVE_EFFECT_SLEEP; + break; case STATUS1_BURN: gBattleScripting.moveEffect = MOVE_EFFECT_BURN; break; @@ -8830,23 +8940,20 @@ static void Cmd_various(void) else gBattlescriptCurrInstr += 7; // can heal return; - case VARIOUS_REMOVE_TERRAIN: + case VARIOUS_REMOVE_TERRAIN: + gFieldTimers.terrainTimer = 0; switch (gFieldStatuses & STATUS_FIELD_TERRAIN_ANY) { case STATUS_FIELD_MISTY_TERRAIN: - gFieldTimers.mistyTerrainTimer = 0; gBattleCommunication[MULTISTRING_CHOOSER] = 0; break; case STATUS_FIELD_GRASSY_TERRAIN: - gFieldTimers.grassyTerrainTimer = 0; gBattleCommunication[MULTISTRING_CHOOSER] = 1; break; case STATUS_FIELD_ELECTRIC_TERRAIN: - gFieldTimers.electricTerrainTimer = 0; gBattleCommunication[MULTISTRING_CHOOSER] = 2; break; case STATUS_FIELD_PSYCHIC_TERRAIN: - gFieldTimers.psychicTerrainTimer = 0; gBattleCommunication[MULTISTRING_CHOOSER] = 3; break; default: @@ -8854,6 +8961,7 @@ static void Cmd_various(void) break; } gFieldStatuses &= ~STATUS_FIELD_TERRAIN_ANY; // remove the terrain + TryToRevertMimicry(); // restore the types of Pokémon with Mimicry break; case VARIOUS_JUMP_IF_PRANKSTER_BLOCKED: if (BlocksPrankster(gCurrentMove, gBattlerAttacker, gActiveBattler, TRUE)) @@ -8867,11 +8975,11 @@ static void Cmd_various(void) for (i = 0; i < gBattlersCount; i++) { - if (((GetBattlerAbility(i) == ABILITY_DESOLATE_LAND && gBattleWeather & WEATHER_SUN_PRIMAL) - || (GetBattlerAbility(i) == ABILITY_PRIMORDIAL_SEA && gBattleWeather & WEATHER_RAIN_PRIMAL) - || (GetBattlerAbility(i) == ABILITY_DELTA_STREAM && gBattleWeather & WEATHER_STRONG_WINDS)) - && IsBattlerAlive(i) - && !(gStatuses3[i] & STATUS3_GASTRO_ACID)) + u32 ability = GetBattlerAbility(i); + if (((ability == ABILITY_DESOLATE_LAND && gBattleWeather & WEATHER_SUN_PRIMAL) + || (ability == ABILITY_PRIMORDIAL_SEA && gBattleWeather & WEATHER_RAIN_PRIMAL) + || (ability == ABILITY_DELTA_STREAM && gBattleWeather & WEATHER_STRONG_WINDS)) + && IsBattlerAlive(i)) shouldNotClear = TRUE; } if (gBattleWeather & WEATHER_SUN_PRIMAL && !shouldNotClear) @@ -8894,6 +9002,15 @@ static void Cmd_various(void) } break; } + case VARIOUS_TRY_END_NEUTRALIZING_GAS: + if (gSpecialStatuses[gActiveBattler].neutralizingGasRemoved) + { + gSpecialStatuses[gActiveBattler].neutralizingGasRemoved = FALSE; + BattleScriptPush(gBattlescriptCurrInstr + 3); + gBattlescriptCurrInstr = BattleScript_NeutralizingGasExits; + return; + } + break; case VARIOUS_GET_ROTOTILLER_TARGETS: // Gets the battlers to be affected by rototiller. If there are none, print 'But it failed!' { @@ -8974,6 +9091,7 @@ static void Cmd_various(void) else gBattlescriptCurrInstr += 7; return; + } case VARIOUS_JUMP_IF_WEATHER_AFFECTED: { u32 weatherFlags = T1_READ_32(gBattlescriptCurrInstr + 3); @@ -8983,7 +9101,6 @@ static void Cmd_various(void) gBattlescriptCurrInstr += 11; } return; - } case VARIOUS_APPLY_PLASMA_FISTS: for (i = 0; i < gBattlersCount; i++) gStatuses4[i] |= STATUS4_PLASMA_FISTS; @@ -8994,6 +9111,61 @@ static void Cmd_various(void) else gBattlescriptCurrInstr += 9; return; + case VARIOUS_PHOTON_GEYSER_CHECK: + { + u32 attackerAtkStat = gBattleMons[gBattlerAttacker].attack; + u8 attackerAtkStage = gBattleMons[gBattlerAttacker].statStages[STAT_ATK]; + u32 attackerSpAtkStat = gBattleMons[gBattlerAttacker].spAttack; + + gSwapDamageCategory = FALSE; + + attackerAtkStat *= gStatStageRatios[attackerAtkStage][0]; + attackerAtkStat /= gStatStageRatios[attackerAtkStage][1]; + + attackerAtkStage = gBattleMons[gBattlerAttacker].statStages[STAT_SPATK]; + attackerSpAtkStat *= gStatStageRatios[attackerAtkStage][0]; + attackerSpAtkStat /= gStatStageRatios[attackerAtkStage][1]; + + if (attackerAtkStat > attackerSpAtkStat) + gSwapDamageCategory = TRUE; + break; + } + case VARIOUS_SHELL_SIDE_ARM_CHECK: // 0% chance GameFreak actually checks this way according to DaWobblefet, but this is the only functional explanation at the moment + { + u32 attackerAtkStat = gBattleMons[gBattlerAttacker].attack; + u32 targetDefStat = gBattleMons[gBattlerTarget].defense; + u32 attackerSpAtkStat = gBattleMons[gBattlerAttacker].spAttack; + u32 targetSpDefStat = gBattleMons[gBattlerTarget].spDefense; + u8 statStage; + u32 physical; + u32 special; + + gSwapDamageCategory = FALSE; + + statStage = gBattleMons[gBattlerAttacker].statStages[STAT_ATK]; + attackerAtkStat *= gStatStageRatios[statStage][0]; + attackerAtkStat /= gStatStageRatios[statStage][1]; + + statStage = gBattleMons[gBattlerTarget].statStages[STAT_DEF]; + targetDefStat *= gStatStageRatios[statStage][0]; + targetDefStat /= gStatStageRatios[statStage][1]; + + physical = ((((2 * gBattleMons[gBattlerAttacker].level / 5 + 2) * gBattleMoves[gCurrentMove].power * attackerAtkStat) / targetDefStat) / 50); + + statStage = gBattleMons[gBattlerAttacker].statStages[STAT_SPATK]; + attackerSpAtkStat *= gStatStageRatios[statStage][0]; + attackerSpAtkStat /= gStatStageRatios[statStage][1]; + + statStage = gBattleMons[gBattlerTarget].statStages[STAT_SPDEF]; + targetSpDefStat *= gStatStageRatios[statStage][0]; + targetSpDefStat /= gStatStageRatios[statStage][1]; + + special = ((((2 * gBattleMons[gBattlerAttacker].level / 5 + 2) * gBattleMoves[gCurrentMove].power * attackerSpAtkStat) / targetSpDefStat) / 50); + + if (((physical > special) || (physical == special && (Random() % 2) == 0))) + gSwapDamageCategory = TRUE; + break; + } case VARIOUS_JUMP_IF_LEAF_GUARD_PROTECTED: if (IsLeafGuardProtected(gActiveBattler)) { @@ -9013,7 +9185,103 @@ static void Cmd_various(void) if (gBattleStruct->stickyWebUser != 0xFF) gBattlerAttacker = gBattleStruct->stickyWebUser; break; + case VARIOUS_CUT_1_3_HP_RAISE_STATS: + { + bool8 atLeastOneStatBoosted = FALSE; + u16 hpFraction = max(1, gBattleMons[gBattlerAttacker].maxHP / 3); + + for (i = 1; i < NUM_STATS; i++) + { + if (CompareStat(gBattlerAttacker, i, MAX_STAT_STAGE, CMP_LESS_THAN)) + { + atLeastOneStatBoosted = TRUE; + break; + } + } + if (atLeastOneStatBoosted && gBattleMons[gBattlerAttacker].hp > hpFraction) + { + gBattleMoveDamage = hpFraction; + gBattlescriptCurrInstr += 7; + } + else + { + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); + } + } + return; + case VARIOUS_SET_OCTOLOCK: + if (gDisableStructs[gActiveBattler].octolock) + { + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); + } + else + { + gDisableStructs[gActiveBattler].octolock = TRUE; + gBattleMons[gActiveBattler].status2 |= STATUS2_ESCAPE_PREVENTION; + gDisableStructs[gActiveBattler].battlerPreventingEscape = gBattlerAttacker; + gBattlescriptCurrInstr += 7; + } + return; + case VARIOUS_CHECK_POLTERGEIST: + if (gBattleMons[gActiveBattler].item == ITEM_NONE + || gFieldStatuses & STATUS_FIELD_MAGIC_ROOM + || GetBattlerAbility(gActiveBattler) == ABILITY_KLUTZ) + { + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); + } + else + { + PREPARE_ITEM_BUFFER(gBattleTextBuff1, gBattleMons[gActiveBattler].item); + gBattlescriptCurrInstr += 7; + } + return; + case VARIOUS_TRY_NO_RETREAT: + if (gDisableStructs[gActiveBattler].noRetreat) + { + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); + } + else + { + if (!(gBattleMons[gActiveBattler].status2 & STATUS2_ESCAPE_PREVENTION)) + gDisableStructs[gActiveBattler].noRetreat = TRUE; + gBattlescriptCurrInstr += 7; + } + return; + case VARIOUS_TRY_TAR_SHOT: + if (gDisableStructs[gActiveBattler].tarShot) + { + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); + } + else + { + gDisableStructs[gActiveBattler].tarShot = TRUE; + gBattlescriptCurrInstr += 7; + } + return; + case VARIOUS_CAN_TAR_SHOT_WORK: + // Tar Shot will fail if it's already been used on the target and its speed can't be lowered further + if (!gDisableStructs[gActiveBattler].tarShot + && CompareStat(gActiveBattler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN)) + gBattlescriptCurrInstr += 7; + else + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); + return; + case VARIOUS_TRY_TO_APPLY_MIMICRY: + { + bool8 isMimicryDone = FALSE; + + if (GetBattlerAbility(gActiveBattler) == ABILITY_MIMICRY) + { + TryToApplyMimicry(gActiveBattler, TRUE); + isMimicryDone = TRUE; + } + if (!isMimicryDone) + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); + else + gBattlescriptCurrInstr += 7; + return; } + } // End of switch (gBattlescriptCurrInstr[2]) gBattlescriptCurrInstr += 3; } @@ -9541,6 +9809,72 @@ static void Cmd_setdrainedhp(void) gBattlescriptCurrInstr++; } +static u16 ReverseStatChangeMoveEffect(u16 moveEffect) +{ + switch (moveEffect) + { + // +1 + case MOVE_EFFECT_ATK_PLUS_1: + return MOVE_EFFECT_ATK_MINUS_1; + case MOVE_EFFECT_DEF_PLUS_1: + return MOVE_EFFECT_DEF_MINUS_1; + case MOVE_EFFECT_SPD_PLUS_1: + return MOVE_EFFECT_SPD_MINUS_1; + case MOVE_EFFECT_SP_ATK_PLUS_1: + return MOVE_EFFECT_SP_ATK_MINUS_1; + case MOVE_EFFECT_SP_DEF_PLUS_1: + return MOVE_EFFECT_SP_DEF_MINUS_1; + case MOVE_EFFECT_ACC_PLUS_1: + return MOVE_EFFECT_ACC_MINUS_1; + case MOVE_EFFECT_EVS_PLUS_1: + return MOVE_EFFECT_EVS_MINUS_1; + // -1 + case MOVE_EFFECT_ATK_MINUS_1: + return MOVE_EFFECT_ATK_PLUS_1; + case MOVE_EFFECT_DEF_MINUS_1: + return MOVE_EFFECT_DEF_PLUS_1; + case MOVE_EFFECT_SPD_MINUS_1: + return MOVE_EFFECT_SPD_PLUS_1; + case MOVE_EFFECT_SP_ATK_MINUS_1: + return MOVE_EFFECT_SP_ATK_PLUS_1; + case MOVE_EFFECT_SP_DEF_MINUS_1: + return MOVE_EFFECT_SP_DEF_PLUS_1; + case MOVE_EFFECT_ACC_MINUS_1: + return MOVE_EFFECT_ACC_PLUS_1; + case MOVE_EFFECT_EVS_MINUS_1: + // +2 + case MOVE_EFFECT_ATK_PLUS_2: + return MOVE_EFFECT_ATK_MINUS_2; + case MOVE_EFFECT_DEF_PLUS_2: + return MOVE_EFFECT_DEF_MINUS_2; + case MOVE_EFFECT_SPD_PLUS_2: + return MOVE_EFFECT_SPD_MINUS_2; + case MOVE_EFFECT_SP_ATK_PLUS_2: + return MOVE_EFFECT_SP_ATK_MINUS_2; + case MOVE_EFFECT_SP_DEF_PLUS_2: + return MOVE_EFFECT_SP_DEF_MINUS_2; + case MOVE_EFFECT_ACC_PLUS_2: + return MOVE_EFFECT_ACC_MINUS_2; + case MOVE_EFFECT_EVS_PLUS_2: + return MOVE_EFFECT_EVS_MINUS_2; + // -2 + case MOVE_EFFECT_ATK_MINUS_2: + return MOVE_EFFECT_ATK_PLUS_2; + case MOVE_EFFECT_DEF_MINUS_2: + return MOVE_EFFECT_DEF_PLUS_2; + case MOVE_EFFECT_SPD_MINUS_2: + return MOVE_EFFECT_SPD_PLUS_2; + case MOVE_EFFECT_SP_ATK_MINUS_2: + return MOVE_EFFECT_SP_ATK_PLUS_2; + case MOVE_EFFECT_SP_DEF_MINUS_2: + return MOVE_EFFECT_SP_DEF_PLUS_2; + case MOVE_EFFECT_ACC_MINUS_2: + return MOVE_EFFECT_ACC_PLUS_2; + case MOVE_EFFECT_EVS_MINUS_2: + return MOVE_EFFECT_EVS_PLUS_2; + } +} + static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr) { bool32 certain = FALSE; @@ -9569,6 +9903,11 @@ static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr { statValue ^= STAT_BUFF_NEGATIVE; gBattleScripting.statChanger ^= STAT_BUFF_NEGATIVE; + if (flags & STAT_BUFF_UPDATE_MOVE_EFFECT) + { + flags &= ~(STAT_BUFF_UPDATE_MOVE_EFFECT); + gBattleScripting.moveEffect = ReverseStatChangeMoveEffect(gBattleScripting.moveEffect); + } } else if (GetBattlerAbility(gActiveBattler) == ABILITY_SIMPLE) { @@ -9650,8 +9989,9 @@ static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr return STAT_CHANGE_DIDNT_WORK; } else if (!certain - && ((GetBattlerAbility(gActiveBattler) == ABILITY_KEEN_EYE && statId == STAT_ACC) - || (GetBattlerAbility(gActiveBattler) == ABILITY_HYPER_CUTTER && statId == STAT_ATK))) + && ((GetBattlerAbility(gActiveBattler) == ABILITY_KEEN_EYE && statId == STAT_ACC) + || (GetBattlerAbility(gActiveBattler) == ABILITY_HYPER_CUTTER && statId == STAT_ATK) + || (GetBattlerAbility(gActiveBattler) == ABILITY_BIG_PECKS && statId == STAT_DEF))) { if (flags == STAT_BUFF_ALLOW_PTR) { @@ -11086,11 +11426,11 @@ static void Cmd_healpartystatus(void) u16 ability; if (gBattlerPartyIndexes[gBattlerAttacker] == i) - ability = gBattleMons[gBattlerAttacker].ability; + ability = GetBattlerAbility(gBattlerAttacker); else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && gBattlerPartyIndexes[gActiveBattler] == i && !(gAbsentBattlerFlags & gBitTable[gActiveBattler])) - ability = gBattleMons[gActiveBattler].ability; + ability = GetBattlerAbility(gActiveBattler); else ability = GetAbilityBySpecies(species, abilityNum); @@ -11760,13 +12100,15 @@ static void Cmd_callterrainattack(void) // nature power u16 GetNaturePowerMove(void) { if (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN) - return MOVE_MOONBLAST; + return MOVE_MOONBLAST; else if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) - return MOVE_THUNDERBOLT; + return MOVE_THUNDERBOLT; else if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN) - return MOVE_ENERGY_BALL; + return MOVE_ENERGY_BALL; else if (gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN) - return MOVE_PSYCHIC; + return MOVE_PSYCHIC; + else if (sNaturePowerMoves == MOVE_NONE) + return MOVE_TRI_ATTACK; return sNaturePowerMoves[gBattleTerrain]; } @@ -11989,7 +12331,7 @@ static void Cmd_trywish(void) if (gWishFutureKnock.wishCounter[gBattlerAttacker] == 0) { gWishFutureKnock.wishCounter[gBattlerAttacker] = 2; - gWishFutureKnock.wishMonId[gBattlerAttacker] = gBattlerPartyIndexes[gBattlerAttacker]; + gWishFutureKnock.wishPartyId[gBattlerAttacker] = gBattlerPartyIndexes[gBattlerAttacker]; gBattlescriptCurrInstr += 6; } else @@ -11998,13 +12340,17 @@ static void Cmd_trywish(void) } break; case 1: // heal effect - PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBattlerTarget, gWishFutureKnock.wishMonId[gBattlerTarget]) - - gBattleMoveDamage = gBattleMons[gBattlerTarget].maxHP / 2; - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; + PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBattlerTarget, gWishFutureKnock.wishPartyId[gBattlerTarget]) + #if B_WISH_HP_SOURCE >= GEN_5 + if (GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER) + gBattleMoveDamage = max(1, GetMonData(&gPlayerParty[gWishFutureKnock.wishPartyId[gBattlerTarget]], MON_DATA_MAX_HP) / 2); + else + gBattleMoveDamage = max(1, GetMonData(&gEnemyParty[gWishFutureKnock.wishPartyId[gBattlerTarget]], MON_DATA_MAX_HP) / 2); + #else + gBattleMoveDamage = max(1, gBattleMons[gBattlerTarget].maxHP / 2); + #endif + gBattleMoveDamage *= -1; - if (gBattleMons[gBattlerTarget].hp == gBattleMons[gBattlerTarget].maxHP) gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 2); else @@ -12037,6 +12383,9 @@ static void Cmd_setgastroacid(void) } else { + if (gBattleMons[gBattlerTarget].ability == ABILITY_NEUTRALIZING_GAS) + gSpecialStatuses[gBattlerTarget].neutralizingGasRemoved = TRUE; + gStatuses3[gBattlerTarget] |= STATUS3_GASTRO_ACID; gBattlescriptCurrInstr += 5; } @@ -12317,25 +12666,33 @@ static void Cmd_trygetintimidatetarget(void) static void Cmd_switchoutabilities(void) { gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]); - - switch (GetBattlerAbility(gActiveBattler)) + if (gBattleMons[gActiveBattler].ability == ABILITY_NEUTRALIZING_GAS) { - case ABILITY_NATURAL_CURE: - gBattleMons[gActiveBattler].status1 = 0; - BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, gBitTable[*(gBattleStruct->field_58 + gActiveBattler)], 4, &gBattleMons[gActiveBattler].status1); - MarkBattlerForControllerExec(gActiveBattler); - break; - case ABILITY_REGENERATOR: - gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 3; - gBattleMoveDamage += gBattleMons[gActiveBattler].hp; - if (gBattleMoveDamage > gBattleMons[gActiveBattler].maxHP) - gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP; - BtlController_EmitSetMonData(0, REQUEST_HP_BATTLE, gBitTable[*(gBattleStruct->field_58 + gActiveBattler)], 2, &gBattleMoveDamage); - MarkBattlerForControllerExec(gActiveBattler); - break; + gBattleMons[gActiveBattler].ability = ABILITY_NONE; + BattleScriptPush(gBattlescriptCurrInstr); + gBattlescriptCurrInstr = BattleScript_NeutralizingGasExits; + } + else + { + switch (GetBattlerAbility(gActiveBattler)) + { + case ABILITY_NATURAL_CURE: + gBattleMons[gActiveBattler].status1 = 0; + BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, gBitTable[*(gBattleStruct->field_58 + gActiveBattler)], 4, &gBattleMons[gActiveBattler].status1); + MarkBattlerForControllerExec(gActiveBattler); + break; + case ABILITY_REGENERATOR: + gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 3; + gBattleMoveDamage += gBattleMons[gActiveBattler].hp; + if (gBattleMoveDamage > gBattleMons[gActiveBattler].maxHP) + gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP; + BtlController_EmitSetMonData(0, REQUEST_HP_BATTLE, gBitTable[*(gBattleStruct->field_58 + gActiveBattler)], 2, &gBattleMoveDamage); + MarkBattlerForControllerExec(gActiveBattler); + break; + } + + gBattlescriptCurrInstr += 2; } - - gBattlescriptCurrInstr += 2; } static void Cmd_jumpifhasnohp(void) @@ -12350,39 +12707,114 @@ static void Cmd_jumpifhasnohp(void) static void Cmd_getsecretpowereffect(void) { - switch (gBattleTerrain) - { - case BATTLE_TERRAIN_GRASS: - gBattleScripting.moveEffect = MOVE_EFFECT_SLEEP; - break; - case BATTLE_TERRAIN_LONG_GRASS: - gBattleScripting.moveEffect = MOVE_EFFECT_SLEEP; - break; - case BATTLE_TERRAIN_SAND: - gBattleScripting.moveEffect = MOVE_EFFECT_ACC_MINUS_1; - break; - case BATTLE_TERRAIN_UNDERWATER: - gBattleScripting.moveEffect = MOVE_EFFECT_ATK_MINUS_1; - break; - case BATTLE_TERRAIN_WATER: - gBattleScripting.moveEffect = MOVE_EFFECT_ATK_MINUS_1; - break; - case BATTLE_TERRAIN_POND: - gBattleScripting.moveEffect = MOVE_EFFECT_ATK_MINUS_1; - break; - case BATTLE_TERRAIN_MOUNTAIN: - gBattleScripting.moveEffect = MOVE_EFFECT_ACC_MINUS_1; - break; - case BATTLE_TERRAIN_CAVE: - gBattleScripting.moveEffect = MOVE_EFFECT_FLINCH; - break; - default: - gBattleScripting.moveEffect = MOVE_EFFECT_PARALYSIS; - break; - } + gBattleScripting.moveEffect = GetSecretPowerMoveEffect(); gBattlescriptCurrInstr++; } +u16 GetSecretPowerMoveEffect(void) +{ + u16 moveEffect; + u32 fieldTerrain = gFieldStatuses & STATUS_FIELD_TERRAIN_ANY; + if (fieldTerrain) + { + switch (fieldTerrain) + { + case STATUS_FIELD_MISTY_TERRAIN: + moveEffect = MOVE_EFFECT_SP_ATK_MINUS_1; + break; + case STATUS_FIELD_GRASSY_TERRAIN: + moveEffect = MOVE_EFFECT_SLEEP; + break; + case STATUS_FIELD_ELECTRIC_TERRAIN: + moveEffect = MOVE_EFFECT_PARALYSIS; + break; + case STATUS_FIELD_PSYCHIC_TERRAIN: + moveEffect = MOVE_EFFECT_SPD_MINUS_1; + break; + default: + moveEffect = MOVE_EFFECT_PARALYSIS; + break; + } + } + else + { + switch (gBattleTerrain) + { + case BATTLE_TERRAIN_GRASS: + #if B_SECRET_POWER_EFFECT >= GEN_4 + moveEffect = MOVE_EFFECT_SLEEP; + #else + moveEffect = MOVE_EFFECT_POISON; + #endif + break; + case BATTLE_TERRAIN_LONG_GRASS: + moveEffect = MOVE_EFFECT_SLEEP; + break; + case BATTLE_TERRAIN_SAND: + moveEffect = MOVE_EFFECT_ACC_MINUS_1; + break; + case BATTLE_TERRAIN_UNDERWATER: + #if B_SECRET_POWER_EFFECT >= GEN_6 + moveEffect = MOVE_EFFECT_ATK_MINUS_1; + #else + moveEffect = MOVE_EFFECT_DEF_MINUS_1; + #endif + break; + case BATTLE_TERRAIN_WATER: + moveEffect = MOVE_EFFECT_ATK_MINUS_1; + break; + case BATTLE_TERRAIN_POND: + #if B_SECRET_POWER_EFFECT >= GEN_4 + moveEffect = MOVE_EFFECT_ATK_MINUS_1; + #else + moveEffect = MOVE_EFFECT_SPD_MINUS_1; + #endif + break; + case BATTLE_TERRAIN_MOUNTAIN: + #if B_SECRET_POWER_EFFECT >= GEN_5 + moveEffect = MOVE_EFFECT_ACC_MINUS_1; + #elif B_SECRET_POWER_EFFECT == GEN_4 + moveEffect = MOVE_EFFECT_FLINCH; + #else + moveEffect = MOVE_EFFECT_CONFUSION; + #endif + break; + case BATTLE_TERRAIN_CAVE: + case BATTLE_TERRAIN_BURIAL_GROUND: + case BATTLE_TERRAIN_SPACE: + moveEffect = MOVE_EFFECT_FLINCH; + break; + case BATTLE_TERRAIN_SOARING: + case BATTLE_TERRAIN_SKY_PILLAR: + case BATTLE_TERRAIN_MARSH: + case BATTLE_TERRAIN_SWAMP: + moveEffect = MOVE_EFFECT_SPD_MINUS_1; + break; + case BATTLE_TERRAIN_PUDDLE: + #if B_SECRET_POWER_EFFECT >= GEN_5 + moveEffect = MOVE_EFFECT_SPD_MINUS_1; + #else + moveEffect = MOVE_EFFECT_ACC_MINUS_1; + #endif + break; + case BATTLE_TERRAIN_SNOW: + case BATTLE_TERRAIN_ICE: + moveEffect = MOVE_EFFECT_FREEZE; + break; + case BATTLE_TERRAIN_VOLCANO: + moveEffect = MOVE_EFFECT_BURN; + break; + case BATTLE_TERRAIN_ULTRA_SPACE: + moveEffect = MOVE_EFFECT_DEF_MINUS_1; + break; + default: + moveEffect = MOVE_EFFECT_PARALYSIS; + break; + } + } + return moveEffect; +} + static void Cmd_pickup(void) { s32 i; @@ -12610,10 +13042,30 @@ bool32 CanCamouflage(u8 battlerId) static void Cmd_settypetoterrain(void) { - if (!IS_BATTLER_OF_TYPE(gBattlerAttacker, sTerrainToType[gBattleTerrain])) + u8 terrainType; + switch(gFieldStatuses & STATUS_FIELD_TERRAIN_ANY) { - SET_BATTLER_TYPE(gBattlerAttacker, sTerrainToType[gBattleTerrain]); - PREPARE_TYPE_BUFFER(gBattleTextBuff1, sTerrainToType[gBattleTerrain]); + case STATUS_FIELD_ELECTRIC_TERRAIN: + terrainType = TYPE_ELECTRIC; + break; + case STATUS_FIELD_GRASSY_TERRAIN: + terrainType = TYPE_GRASS; + break; + case STATUS_FIELD_MISTY_TERRAIN: + terrainType = TYPE_FAIRY; + break; + case STATUS_FIELD_PSYCHIC_TERRAIN: + terrainType = TYPE_PSYCHIC; + break; + default: + terrainType = sTerrainToType[gBattleTerrain]; + break; + } + + if (!IS_BATTLER_OF_TYPE(gBattlerAttacker, terrainType)) + { + SET_BATTLER_TYPE(gBattlerAttacker, terrainType); + PREPARE_TYPE_BUFFER(gBattleTextBuff1, terrainType); gBattlescriptCurrInstr += 5; } @@ -12660,14 +13112,33 @@ static void Cmd_snatchsetbattlers(void) static void Cmd_removelightscreenreflect(void) // brick break { - u8 opposingSide = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE; - - if (gSideTimers[opposingSide].reflectTimer || gSideTimers[opposingSide].lightscreenTimer) + u8 side; + bool32 failed; + + #if B_BRICK_BREAK >= GEN_4 + // From Gen 4 onwards, Brick Break can remove screens on the user's side if used on an ally + side = GetBattlerSide(gBattlerTarget); + #else + side = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE; + #endif + + #if B_BRICK_BREAK >= GEN_5 + failed = (gMoveResultFlags & MOVE_RESULT_NO_EFFECT); + #else + failed = FALSE; + #endif + + if (!failed + && (gSideTimers[side].reflectTimer + || gSideTimers[side].lightscreenTimer + || gSideTimers[side].auroraVeilTimer)) { - gSideStatuses[opposingSide] &= ~(SIDE_STATUS_REFLECT); - gSideStatuses[opposingSide] &= ~(SIDE_STATUS_LIGHTSCREEN); - gSideTimers[opposingSide].reflectTimer = 0; - gSideTimers[opposingSide].lightscreenTimer = 0; + gSideStatuses[side] &= ~(SIDE_STATUS_REFLECT); + gSideStatuses[side] &= ~(SIDE_STATUS_LIGHTSCREEN); + gSideStatuses[side] &= ~(SIDE_STATUS_AURORA_VEIL); + gSideTimers[side].reflectTimer = 0; + gSideTimers[side].lightscreenTimer = 0; + gSideTimers[side].auroraVeilTimer = 0; gBattleScripting.animTurn = 1; gBattleScripting.animTargetsHit = 1; } @@ -12690,7 +13161,8 @@ u8 GetCatchingBattler(void) static void Cmd_handleballthrow(void) { - u8 ballMultiplier = 0; + u8 ballMultiplier = 10; + s8 ballAddition = 0; if (gBattleControllerExecFlags) return; @@ -12712,62 +13184,202 @@ static void Cmd_handleballthrow(void) } else { - u32 odds; + u32 odds, i; u8 catchRate; gLastThrownBall = gLastUsedItem; - if (gLastUsedItem == ITEM_SAFARI_BALL) + if (gBattleTypeFlags & BATTLE_TYPE_SAFARI) catchRate = gBattleStruct->safariCatchFactor * 1275 / 100; else catchRate = gBaseStats[gBattleMons[gBattlerTarget].species].catchRate; - if (gLastUsedItem > ITEM_SAFARI_BALL) + #ifdef POKEMON_EXPANSION + if (gBaseStats[gBattleMons[gBattlerTarget].species].flags & F_ULTRA_BEAST) { - switch (gLastUsedItem) - { - case ITEM_NET_BALL: - if (IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_WATER) || IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_BUG)) + if (gLastUsedItem == ITEM_BEAST_BALL) + ballMultiplier = 50; + else + ballMultiplier = 1; + } + else + { + #endif + + switch (gLastUsedItem) + { + case ITEM_ULTRA_BALL: + ballMultiplier = 20; + case ITEM_GREAT_BALL: + case ITEM_SAFARI_BALL: + #ifdef ITEM_EXPANSION + case ITEM_SPORT_BALL: + #endif + ballMultiplier = 15; + case ITEM_NET_BALL: + if (IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_WATER) || IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_BUG)) + #if B_NET_BALL_MODIFIER >= GEN_7 + ballMultiplier = 50; + #else ballMultiplier = 30; - else - ballMultiplier = 10; - break; - case ITEM_DIVE_BALL: + #endif + break; + case ITEM_DIVE_BALL: + #if B_DIVE_BALL_MODIFIER >= GEN_4 + if (GetCurrentMapType() == MAP_TYPE_UNDERWATER || gIsFishingEncounter || gIsSurfingEncounter) + ballMultiplier = 35; + #else if (GetCurrentMapType() == MAP_TYPE_UNDERWATER) ballMultiplier = 35; - else - ballMultiplier = 10; - break; - case ITEM_NEST_BALL: + #endif + break; + case ITEM_NEST_BALL: + #if B_NEST_BALL_MODIFIER >= GEN_6 + //((41 - Pokémon's level) ÷ 10)× if Pokémon's level is between 1 and 29, 1× otherwise. + if (gBattleMons[gBattlerTarget].level < 30) + ballMultiplier = 41 - gBattleMons[gBattlerTarget].level; + #elif B_NEST_BALL_MODIFIER == GEN_5 + //((41 - Pokémon's level) ÷ 10)×, minimum 1× + if (gBattleMons[gBattlerTarget].level < 31) + ballMultiplier = 41 - gBattleMons[gBattlerTarget].level; + #else + //((40 - Pokémon's level) ÷ 10)×, minimum 1× if (gBattleMons[gBattlerTarget].level < 40) { ballMultiplier = 40 - gBattleMons[gBattlerTarget].level; if (ballMultiplier <= 9) ballMultiplier = 10; } - else - { - ballMultiplier = 10; - } - break; - case ITEM_REPEAT_BALL: - if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gBattlerTarget].species), FLAG_GET_CAUGHT)) + #endif + break; + case ITEM_REPEAT_BALL: + if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gBattlerTarget].species), FLAG_GET_CAUGHT)) + #if B_REPEAT_BALL_MODIFIER >= GEN_7 + ballMultiplier = 35; + #else ballMultiplier = 30; - else - ballMultiplier = 10; - break; - case ITEM_TIMER_BALL: + #endif + break; + case ITEM_TIMER_BALL: + #if B_TIMER_BALL_MODIFIER >= GEN_5 + ballMultiplier = (gBattleResults.battleTurnCounter * 3) + 10; + #else ballMultiplier = gBattleResults.battleTurnCounter + 10; - if (ballMultiplier > 40) + #endif + if (ballMultiplier > 40) + ballMultiplier = 40; + break; + #ifdef ITEM_EXPANSION + case ITEM_DUSK_BALL: + RtcCalcLocalTime(); + if ((gLocalTime.hours >= 20 && gLocalTime.hours <= 3) || gMapHeader.cave || gMapHeader.mapType == MAP_TYPE_UNDERGROUND) + #if B_DUSK_BALL_MODIFIER >= GEN_7 + ballMultiplier = 30; + #else + ballMultiplier = 35; + #endif + break; + case ITEM_QUICK_BALL: + if (gBattleResults.battleTurnCounter == 0) + #if B_QUICK_BALL_MODIFIER >= GEN_5 + ballMultiplier = 50; + #else + ballMultiplier = 40; + #endif + break; + case ITEM_LEVEL_BALL: + if (gBattleMons[gBattlerAttacker].level >= 4 * gBattleMons[gBattlerTarget].level) + ballMultiplier = 80; + else if (gBattleMons[gBattlerAttacker].level > 2 * gBattleMons[gBattlerTarget].level) + ballMultiplier = 40; + else if (gBattleMons[gBattlerAttacker].level > gBattleMons[gBattlerTarget].level) + ballMultiplier = 20; + break; + case ITEM_LURE_BALL: + if (gIsFishingEncounter) + #if B_LURE_BALL_MODIFIER >= GEN_7 + ballMultiplier = 50; + #else + ballMultiplier = 30; + #endif + break; + case ITEM_MOON_BALL: + for (i = 0; i < EVOS_PER_MON; i++) + { + if (gEvolutionTable[gBattleMons[gBattlerTarget].species][i].method == EVO_ITEM + && gEvolutionTable[gBattleMons[gBattlerTarget].species][i].param == ITEM_MOON_STONE) ballMultiplier = 40; - break; - case ITEM_LUXURY_BALL: - case ITEM_PREMIER_BALL: - ballMultiplier = 10; - break; } + break; + case ITEM_LOVE_BALL: + if (gBattleMons[gBattlerTarget].species == gBattleMons[gBattlerAttacker].species) + { + u8 gender1 = GetMonGender(&gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]]); + u8 gender2 = GetMonGender(&gPlayerParty[gBattlerPartyIndexes[gBattlerAttacker]]); + + if (gender1 != gender2 && gender1 != MON_GENDERLESS && gender2 != MON_GENDERLESS) + ballMultiplier = 80; + } + break; + case ITEM_FAST_BALL: + if (gBaseStats[gBattleMons[gBattlerTarget].species].baseSpeed >= 100) + ballMultiplier = 40; + break; + case ITEM_HEAVY_BALL: + i = GetPokedexHeightWeight(SpeciesToNationalPokedexNum(gBattleMons[gBattlerTarget].species), 1); + #if B_HEAVY_BALL_MODIFIER >= GEN_7 + if (i < 1000) + ballAddition = -20; + else if (i < 2000) + ballAddition = 0; + else if (i < 3000) + ballAddition = 20; + else + ballAddition = 30; + #elif B_HEAVY_BALL_MODIFIER >= GEN_4 + if (i < 2048) + ballAddition = -20; + else if (i < 3072) + ballAddition = 20; + else if (i < 4096) + ballAddition = 30; + else + ballAddition = 40; + #else + if (i < 1024) + ballAddition = -20; + else if (i < 2048) + ballAddition = 0; + else if (i < 3072) + ballAddition = 20; + else if (i < 4096) + ballAddition = 30; + else + ballAddition = 40; + #endif + break; + case ITEM_DREAM_BALL: + #if B_DREAM_BALL_MODIFIER >= GEN_8 + if (gBattleMons[gBattlerTarget].status1 & STATUS1_SLEEP || GetBattlerAbility(gBattlerTarget) == ABILITY_COMATOSE) + ballMultiplier = 40; + #else + ballMultiplier = 10; + #endif + break; + case ITEM_BEAST_BALL: + ballMultiplier = 1; + break; + #endif } + + #ifdef POKEMON_EXPANSION + } + #endif + + // catchRate is unsigned, which means that it may potentially overflow if sum is applied directly. + if (catchRate < 21 && ballAddition == -20) + catchRate = 1; else - ballMultiplier = sBallCatchBonuses[gLastUsedItem - ITEM_ULTRA_BALL]; + catchRate = catchRate + ballAddition; odds = (catchRate * ballMultiplier / 10) * (gBattleMons[gBattlerTarget].maxHP * 3 - gBattleMons[gBattlerTarget].hp * 2) @@ -12809,16 +13421,17 @@ static void Cmd_handleballthrow(void) u8 shakes; u8 maxShakes; - gBattleSpritesDataPtr->animationData->isCriticalCapture = 0; //initialize + gBattleSpritesDataPtr->animationData->isCriticalCapture = 0; gBattleSpritesDataPtr->animationData->criticalCaptureSuccess = 0; + if (CriticalCapture(odds)) { - maxShakes = 1; //critical capture doesn't gauarantee capture + maxShakes = BALL_1_SHAKE; // critical capture doesn't guarantee capture gBattleSpritesDataPtr->animationData->isCriticalCapture = 1; } else { - maxShakes = 4; + maxShakes = BALL_3_SHAKES_SUCCESS; } if (gLastUsedItem == ITEM_MASTER_BALL) @@ -12843,10 +13456,21 @@ static void Cmd_handleballthrow(void) UndoFormChange(gBattlerPartyIndexes[gBattlerTarget], GET_BATTLER_SIDE(gBattlerTarget), FALSE); gBattlescriptCurrInstr = BattleScript_SuccessBallThrow; SetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]], MON_DATA_POKEBALL, &gLastUsedItem); + if (CalculatePlayerPartyCount() == PARTY_SIZE) gBattleCommunication[MULTISTRING_CHOOSER] = 0; else gBattleCommunication[MULTISTRING_CHOOSER] = 1; + + #ifdef ITEM_EXPANSION + if (gLastUsedItem == ITEM_HEAL_BALL) + { + MonRestorePP(&gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]]); + HealStatusConditions(&gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]], gBattlerPartyIndexes[gBattlerTarget], STATUS1_ANY, gBattlerTarget); + gBattleMons[gBattlerTarget].hp = gBattleMons[gBattlerTarget].maxHP; + SetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]], MON_DATA_HP, &gBattleMons[gBattlerTarget].hp); + } + #endif } else // not caught { @@ -12854,7 +13478,7 @@ static void Cmd_handleballthrow(void) gLastUsedBall = gLastUsedItem; if (IsCriticalCapture()) - gBattleCommunication[MULTISTRING_CHOOSER] = shakes + 3; + gBattleCommunication[MULTISTRING_CHOOSER] = BALL_3_SHAKES_FAIL; else gBattleCommunication[MULTISTRING_CHOOSER] = shakes; @@ -13313,4 +13937,3 @@ static bool32 CriticalCapture(u32 odds) return FALSE; #endif } - diff --git a/src/battle_util.c b/src/battle_util.c index 13908c2097..725814a0d4 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -317,8 +317,8 @@ void HandleAction_UseMove(void) else if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && gSideTimers[side].followmeTimer == 0 && (gBattleMoves[gCurrentMove].power != 0 || gBattleMoves[gCurrentMove].target != MOVE_TARGET_USER) - && ((gBattleMons[*(gBattleStruct->moveTarget + gBattlerAttacker)].ability != ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC) - || (gBattleMons[*(gBattleStruct->moveTarget + gBattlerAttacker)].ability != ABILITY_STORM_DRAIN && moveType == TYPE_WATER))) + && ((GetBattlerAbility(*(gBattleStruct->moveTarget + gBattlerAttacker)) != ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC) + || (GetBattlerAbility(*(gBattleStruct->moveTarget + gBattlerAttacker)) != ABILITY_STORM_DRAIN && moveType == TYPE_WATER))) { side = GetBattlerSide(gBattlerAttacker); for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++) @@ -387,9 +387,9 @@ void HandleAction_UseMove(void) { gActiveBattler = gBattlerByTurnOrder[var]; RecordAbilityBattle(gActiveBattler, gBattleMons[gActiveBattler].ability); - if (gBattleMons[gActiveBattler].ability == ABILITY_LIGHTNING_ROD) + if (GetBattlerAbility(gActiveBattler) == ABILITY_LIGHTNING_ROD) gSpecialStatuses[gActiveBattler].lightningRodRedirected = TRUE; - else if (gBattleMons[gActiveBattler].ability == ABILITY_STORM_DRAIN) + else if (GetBattlerAbility(gActiveBattler) == ABILITY_STORM_DRAIN) gSpecialStatuses[gActiveBattler].stormDrainRedirected = TRUE; gBattlerTarget = gActiveBattler; } @@ -627,7 +627,7 @@ bool8 TryRunFromBattle(u8 battler) effect++; } #endif - else if (gBattleMons[battler].ability == ABILITY_RUN_AWAY) + else if (GetBattlerAbility(battler) == ABILITY_RUN_AWAY) { if (InBattlePyramid()) { @@ -1762,7 +1762,7 @@ u8 TrySetCantSelectMoveBattleScript(void) limitations++; } } - else if (holdEffect == HOLD_EFFECT_ASSAULT_VEST && gBattleMoves[move].power == 0) + else if (holdEffect == HOLD_EFFECT_ASSAULT_VEST && gBattleMoves[move].power == 0 && move != MOVE_ME_FIRST) { gCurrentMove = move; gLastUsedItem = gBattleMons[gActiveBattler].item; @@ -1834,7 +1834,7 @@ u8 CheckMoveLimitations(u8 battlerId, u8 unusableMoves, u8 check) unusableMoves |= gBitTable[i]; else if (HOLD_EFFECT_CHOICE(holdEffect) && *choicedMove != 0 && *choicedMove != 0xFFFF && *choicedMove != gBattleMons[battlerId].moves[i]) unusableMoves |= gBitTable[i]; - else if (holdEffect == HOLD_EFFECT_ASSAULT_VEST && gBattleMoves[gBattleMons[battlerId].moves[i]].power == 0) + else if (holdEffect == HOLD_EFFECT_ASSAULT_VEST && gBattleMoves[gBattleMons[battlerId].moves[i]].power == 0 && gBattleMons[battlerId].moves[i] != MOVE_ME_FIRST) unusableMoves |= gBitTable[i]; else if (IsGravityPreventingMove(gBattleMons[battlerId].moves[i])) unusableMoves |= gBitTable[i]; @@ -1894,6 +1894,57 @@ u8 GetImprisonedMovesCount(u8 battlerId, u16 move) return imprisonedMoves; } +void RestoreBattlerOriginalTypes(u8 battlerId) +{ + gBattleMons[battlerId].type1 = gBaseStats[gBattleMons[battlerId].species].type1; + gBattleMons[battlerId].type2 = gBaseStats[gBattleMons[battlerId].species].type2; +} + +void TryToApplyMimicry(u8 battlerId, bool8 various) +{ + u32 moveType, move; + + GET_MOVE_TYPE(move, moveType); + switch (gFieldStatuses) + { + case STATUS_FIELD_ELECTRIC_TERRAIN: + moveType = TYPE_ELECTRIC; + break; + case STATUS_FIELD_MISTY_TERRAIN: + moveType = TYPE_FAIRY; + break; + case STATUS_FIELD_GRASSY_TERRAIN: + moveType = TYPE_GRASS; + break; + case STATUS_FIELD_PSYCHIC_TERRAIN: + moveType = TYPE_PSYCHIC; + break; + default: + moveType = 0; + break; + } + + if (moveType != 0 && !IS_BATTLER_OF_TYPE(battlerId, moveType)) + { + SET_BATTLER_TYPE(battlerId, moveType); + PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, battlerId, gBattlerPartyIndexes[battlerId]) + PREPARE_TYPE_BUFFER(gBattleTextBuff2, moveType); + if (!various) + BattleScriptPushCursorAndCallback(BattleScript_MimicryActivatesEnd3); + } +} + +void TryToRevertMimicry(void) +{ + s32 i; + + for (i = 0; i < MAX_BATTLERS_COUNT; i++) + { + if (GetBattlerAbility(i) == ABILITY_MIMICRY) + RestoreBattlerOriginalTypes(i); + } +} + enum { ENDTURN_ORDER, @@ -2275,9 +2326,10 @@ u8 DoFieldEndTurnEffects(void) break; case ENDTURN_ELECTRIC_TERRAIN: if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN - && (!(gFieldStatuses & STATUS_FIELD_TERRAIN_PERMANENT) && --gFieldTimers.electricTerrainTimer == 0)) + && (!(gFieldStatuses & STATUS_FIELD_TERRAIN_PERMANENT) && --gFieldTimers.terrainTimer == 0)) { gFieldStatuses &= ~(STATUS_FIELD_ELECTRIC_TERRAIN | STATUS_FIELD_TERRAIN_PERMANENT); + TryToRevertMimicry(); BattleScriptExecute(BattleScript_ElectricTerrainEnds); effect++; } @@ -2285,9 +2337,10 @@ u8 DoFieldEndTurnEffects(void) break; case ENDTURN_MISTY_TERRAIN: if (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN - && (!(gFieldStatuses & STATUS_FIELD_TERRAIN_PERMANENT) && --gFieldTimers.mistyTerrainTimer == 0)) + && (!(gFieldStatuses & STATUS_FIELD_TERRAIN_PERMANENT) && --gFieldTimers.terrainTimer == 0)) { gFieldStatuses &= ~(STATUS_FIELD_MISTY_TERRAIN); + TryToRevertMimicry(); BattleScriptExecute(BattleScript_MistyTerrainEnds); effect++; } @@ -2297,9 +2350,11 @@ u8 DoFieldEndTurnEffects(void) if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN) { if (!(gFieldStatuses & STATUS_FIELD_TERRAIN_PERMANENT) - && (gFieldTimers.grassyTerrainTimer == 0 || --gFieldTimers.grassyTerrainTimer == 0)) + && (gFieldTimers.terrainTimer == 0 || --gFieldTimers.terrainTimer == 0)) + { gFieldStatuses &= ~(STATUS_FIELD_GRASSY_TERRAIN); - + TryToRevertMimicry(); + } BattleScriptExecute(BattleScript_GrassyTerrainHeals); effect++; } @@ -2307,9 +2362,10 @@ u8 DoFieldEndTurnEffects(void) break; case ENDTURN_PSYCHIC_TERRAIN: if (gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN - && (!(gFieldStatuses & STATUS_FIELD_TERRAIN_PERMANENT) && --gFieldTimers.psychicTerrainTimer == 0)) + && (!(gFieldStatuses & STATUS_FIELD_TERRAIN_PERMANENT) && --gFieldTimers.terrainTimer == 0)) { gFieldStatuses &= ~(STATUS_FIELD_PSYCHIC_TERRAIN); + TryToRevertMimicry(); BattleScriptExecute(BattleScript_PsychicTerrainEnds); effect++; } @@ -2382,6 +2438,7 @@ enum ENDTURN_NIGHTMARES, ENDTURN_CURSE, ENDTURN_WRAP, + ENDTURN_OCTOLOCK, ENDTURN_UPROAR, ENDTURN_THRASH, ENDTURN_FLINCH, @@ -2652,13 +2709,25 @@ u8 DoBattlerEndTurnEffects(void) } gBattleStruct->turnEffectsTracker++; break; + case ENDTURN_OCTOLOCK: + if (gDisableStructs[gActiveBattler].octolock + && !(GetBattlerAbility(gActiveBattler) == ABILITY_CLEAR_BODY + || GetBattlerAbility(gActiveBattler) == ABILITY_FULL_METAL_BODY + || GetBattlerAbility(gActiveBattler) == ABILITY_WHITE_SMOKE)) + { + gBattlerTarget = gActiveBattler; + BattleScriptExecute(BattleScript_OctolockEndTurn); + effect++; + } + gBattleStruct->turnEffectsTracker++; + break; case ENDTURN_UPROAR: // uproar if (gBattleMons[gActiveBattler].status2 & STATUS2_UPROAR) { for (gBattlerAttacker = 0; gBattlerAttacker < gBattlersCount; gBattlerAttacker++) { if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP) - && gBattleMons[gBattlerAttacker].ability != ABILITY_SOUNDPROOF) + && GetBattlerAbility(gBattlerAttacker) != ABILITY_SOUNDPROOF) { gBattleMons[gBattlerAttacker].status1 &= ~(STATUS1_SLEEP); gBattleMons[gBattlerAttacker].status2 &= ~(STATUS2_NIGHTMARE); @@ -2726,6 +2795,7 @@ u8 DoBattlerEndTurnEffects(void) case ENDTURN_FLINCH: // reset flinch gBattleMons[gActiveBattler].status2 &= ~(STATUS2_FLINCHED); gBattleStruct->turnEffectsTracker++; + break; case ENDTURN_DISABLE: // disable if (gDisableStructs[gActiveBattler].disableTimer != 0) { @@ -3242,7 +3312,7 @@ u8 AtkCanceller_UnableToUseMove(void) gBattleStruct->atkCancellerTracker++; break; case CANCELLER_TRUANT: // truant - if (gBattleMons[gBattlerAttacker].ability == ABILITY_TRUANT && gDisableStructs[gBattlerAttacker].truantCounter) + if (GetBattlerAbility(gBattlerAttacker) == ABILITY_TRUANT && gDisableStructs[gBattlerAttacker].truantCounter) { CancelMultiTurnMoves(gBattlerAttacker); gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; @@ -3683,7 +3753,7 @@ u8 TryWeatherFormChange(u8 battler) if (gBattleMons[battler].species == SPECIES_CASTFORM) { - if (gBattleMons[battler].ability != ABILITY_FORECAST || gBattleMons[battler].hp == 0) + if (GetBattlerAbility(battler) != ABILITY_FORECAST || gBattleMons[battler].hp == 0) { ret = 0; } @@ -3719,11 +3789,11 @@ u8 TryWeatherFormChange(u8 battler) } else if (gBattleMons[battler].species == SPECIES_CHERRIM) { - if (gBattleMons[battler].ability != ABILITY_FLOWER_GIFT || gBattleMons[battler].hp == 0) + if (GetBattlerAbility(battler) != ABILITY_FLOWER_GIFT || gBattleMons[battler].hp == 0) ret = 0; else if (gBattleMonForms[battler] == 0 && weatherEffect && holdEffect != HOLD_EFFECT_UTILITY_UMBRELLA && gBattleWeather & WEATHER_SUN_ANY) ret = 2; - else if (gBattleMonForms[battler] != 0 && (!weatherEffect || holdEffect != HOLD_EFFECT_UTILITY_UMBRELLA || !(gBattleWeather & WEATHER_SUN_ANY))) + else if (gBattleMonForms[battler] != 0 && (!weatherEffect || holdEffect == HOLD_EFFECT_UTILITY_UMBRELLA || !(gBattleWeather & WEATHER_SUN_ANY))) ret = 1; } @@ -3809,7 +3879,7 @@ static bool32 ShouldChangeFormHpBased(u32 battler) for (i = 0; i < ARRAY_COUNT(forms); i++) { - if (gBattleMons[battler].ability == forms[i][0]) + if (GetBattlerAbility(battler) == forms[i][0]) { if (gBattleMons[battler].species == forms[i][2] && gBattleMons[battler].hp > gBattleMons[battler].maxHP / forms[i][3]) @@ -4282,28 +4352,28 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move } break; case ABILITY_ELECTRIC_SURGE: - if (TryChangeBattleTerrain(battler, STATUS_FIELD_ELECTRIC_TERRAIN, &gFieldTimers.electricTerrainTimer)) + if (TryChangeBattleTerrain(battler, STATUS_FIELD_ELECTRIC_TERRAIN, &gFieldTimers.terrainTimer)) { BattleScriptPushCursorAndCallback(BattleScript_ElectricSurgeActivates); effect++; } break; case ABILITY_GRASSY_SURGE: - if (TryChangeBattleTerrain(battler, STATUS_FIELD_GRASSY_TERRAIN, &gFieldTimers.grassyTerrainTimer)) + if (TryChangeBattleTerrain(battler, STATUS_FIELD_GRASSY_TERRAIN, &gFieldTimers.terrainTimer)) { BattleScriptPushCursorAndCallback(BattleScript_GrassySurgeActivates); effect++; } break; case ABILITY_MISTY_SURGE: - if (TryChangeBattleTerrain(battler, STATUS_FIELD_MISTY_TERRAIN, &gFieldTimers.mistyTerrainTimer)) + if (TryChangeBattleTerrain(battler, STATUS_FIELD_MISTY_TERRAIN, &gFieldTimers.terrainTimer)) { BattleScriptPushCursorAndCallback(BattleScript_MistySurgeActivates); effect++; } break; case ABILITY_PSYCHIC_SURGE: - if (TryChangeBattleTerrain(battler, STATUS_FIELD_PSYCHIC_TERRAIN, &gFieldTimers.psychicTerrainTimer)) + if (TryChangeBattleTerrain(battler, STATUS_FIELD_PSYCHIC_TERRAIN, &gFieldTimers.terrainTimer)) { BattleScriptPushCursorAndCallback(BattleScript_PsychicSurgeActivates); effect++; @@ -4390,6 +4460,13 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move effect++; } break; + case ABILITY_MIMICRY: + if (gBattleMons[battler].hp != 0 && gFieldStatuses & STATUS_FIELD_TERRAIN_ANY) + { + TryToApplyMimicry(battler, FALSE); + effect++; + } + break; } break; case ABILITYEFFECT_ENDTURN: // 1 @@ -4572,6 +4649,22 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move effect++; } break; + case ABILITY_HUNGER_SWITCH: + if (!(gBattleMons[battler].status2 & STATUS2_TRANSFORMED)) + { + if (gBattleMons[battler].species == SPECIES_MORPEKO) + { + gBattleMons[battler].species = SPECIES_MORPEKO_HANGRY; + BattleScriptPushCursorAndCallback(BattleScript_AttackerFormChangeEnd3NoPopup); + } + else if (gBattleMons[battler].species == SPECIES_MORPEKO_HANGRY) + { + gBattleMons[battler].species = SPECIES_MORPEKO; + BattleScriptPushCursorAndCallback(BattleScript_AttackerFormChangeEnd3NoPopup); + } + effect++; + } + break; } } break; @@ -4837,7 +4930,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) && IsBattlerAlive(gBattlerAttacker) && TARGET_TURN_DAMAGED - && (gBattleMoves[move].flags & FLAG_MAKES_CONTACT)) + && (IsMoveMakingContact(move, gBattlerAttacker))) { switch (gBattleMons[gBattlerAttacker].ability) { @@ -5056,7 +5149,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) && gBattleMons[gBattlerAttacker].hp != 0 && !gProtectStructs[gBattlerAttacker].confusionSelfDmg - && (gBattleMoves[move].flags & FLAG_MAKES_CONTACT) + && (IsMoveMakingContact(move, gBattlerAttacker)) && TARGET_TURN_DAMAGED && CanBeBurned(gBattlerAttacker) && (Random() % 3) == 0) @@ -5072,7 +5165,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) && gBattleMons[gBattlerAttacker].hp != 0 && !gProtectStructs[gBattlerAttacker].confusionSelfDmg - && (gBattleMoves[move].flags & FLAG_MAKES_CONTACT) + && (IsMoveMakingContact(move, gBattlerAttacker)) && TARGET_TURN_DAMAGED && gBattleMons[gBattlerTarget].hp != 0 && (Random() % 3) == 0 @@ -5148,7 +5241,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move && !gProtectStructs[gBattlerAttacker].confusionSelfDmg && TARGET_TURN_DAMAGED && IsBattlerAlive(battler) - && (gBattleMoves[move].flags & FLAG_MAKES_CONTACT) + && (IsMoveMakingContact(move, gBattlerAttacker)) && !(gStatuses3[gBattlerAttacker] & STATUS3_PERISH_SONG)) { if (!(gStatuses3[battler] & STATUS3_PERISH_SONG)) @@ -5281,7 +5374,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move case ABILITYEFFECT_IMMUNITY: // 5 for (battler = 0; battler < gBattlersCount; battler++) { - switch (gBattleMons[battler].ability) + switch (GetBattlerAbility(battler)) { case ABILITY_IMMUNITY: if (gBattleMons[battler].status1 & (STATUS1_POISON | STATUS1_TOXIC_POISON | STATUS1_TOXIC_COUNTER)) @@ -5371,7 +5464,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move case ABILITYEFFECT_FORECAST: // 6 for (battler = 0; battler < gBattlersCount; battler++) { - if (gBattleMons[battler].ability == ABILITY_FORECAST || gBattleMons[battler].ability == ABILITY_FLOWER_GIFT) + if (GetBattlerAbility(battler) == ABILITY_FORECAST || GetBattlerAbility(battler) == ABILITY_FLOWER_GIFT) { effect = TryWeatherFormChange(battler); if (effect) @@ -5392,8 +5485,10 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move if (!(gBattleMons[gBattlerAttacker].status1 & STATUS1_ANY)) { gBattleStruct->synchronizeMoveEffect &= ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); - if (gBattleStruct->synchronizeMoveEffect == MOVE_EFFECT_TOXIC) - gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_POISON; + #if B_SYNCHRONIZE_TOXIC < GEN_5 + if (gBattleStruct->synchronizeMoveEffect == MOVE_EFFECT_TOXIC) + gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_POISON; + #endif gBattleScripting.moveEffect = gBattleStruct->synchronizeMoveEffect + MOVE_EFFECT_AFFECTS_USER; gBattleScripting.battler = gBattlerAbility = gBattlerTarget; @@ -5430,7 +5525,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move case ABILITYEFFECT_INTIMIDATE2: for (i = 0; i < gBattlersCount; i++) { - if (gBattleMons[i].ability == ABILITY_INTIMIDATE && gBattleResources->flags->flags[i] & RESOURCE_FLAG_INTIMIDATED) + if (GetBattlerAbility(i) == ABILITY_INTIMIDATE && gBattleResources->flags->flags[i] & RESOURCE_FLAG_INTIMIDATED) { gLastUsedAbility = ABILITY_INTIMIDATE; gBattleResources->flags->flags[i] &= ~(RESOURCE_FLAG_INTIMIDATED); @@ -5497,6 +5592,23 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move } } break; + case ABILITYEFFECT_NEUTRALIZINGGAS: + // Prints message only. separate from ABILITYEFFECT_ON_SWITCHIN bc activates before entry hazards + for (i = 0; i < gBattlersCount; i++) + { + if (gBattleMons[i].ability == ABILITY_NEUTRALIZING_GAS && !(gBattleResources->flags->flags[i] & RESOURCE_FLAG_NEUTRALIZING_GAS)) + { + gBattleResources->flags->flags[i] |= RESOURCE_FLAG_NEUTRALIZING_GAS; + gBattlerAbility = i; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWITCHIN_NEUTRALIZING_GAS; + BattleScriptPushCursorAndCallback(BattleScript_SwitchInAbilityMsg); + effect++; + } + + if (effect) + break; + } + break; } if (effect && gLastUsedAbility != 0xFF) @@ -5507,11 +5619,51 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move return effect; } +bool32 IsNeutralizingGasBannedAbility(u32 ability) +{ + switch (ability) + { + case ABILITY_MULTITYPE: + case ABILITY_ZEN_MODE: + case ABILITY_STANCE_CHANGE: + case ABILITY_POWER_CONSTRUCT: + case ABILITY_SCHOOLING: + case ABILITY_RKS_SYSTEM: + case ABILITY_SHIELDS_DOWN: + case ABILITY_COMATOSE: + case ABILITY_DISGUISE: + case ABILITY_GULP_MISSILE: + case ABILITY_ICE_FACE: + case ABILITY_AS_ONE_ICE_RIDER: + case ABILITY_AS_ONE_SHADOW_RIDER: + return TRUE; + default: + return FALSE; + } +} + +bool32 IsNeutralizingGasOnField(void) +{ + u32 i; + + for (i = 0; i < gBattlersCount; i++) + { + if (IsBattlerAlive(i) && gBattleMons[i].ability == ABILITY_NEUTRALIZING_GAS && !(gStatuses3[i] & STATUS3_GASTRO_ACID)) + return TRUE; + } + + return FALSE; +} + u32 GetBattlerAbility(u8 battlerId) { if (gStatuses3[battlerId] & STATUS3_GASTRO_ACID) return ABILITY_NONE; - else if ((((gBattleMons[gBattlerAttacker].ability == ABILITY_MOLD_BREAKER + + if (IsNeutralizingGasOnField() && !IsNeutralizingGasBannedAbility(gBattleMons[battlerId].ability)) + return ABILITY_NONE; + + if ((((gBattleMons[gBattlerAttacker].ability == ABILITY_MOLD_BREAKER || gBattleMons[gBattlerAttacker].ability == ABILITY_TERAVOLT || gBattleMons[gBattlerAttacker].ability == ABILITY_TURBOBLAZE) && !(gStatuses3[gBattlerAttacker] & STATUS3_GASTRO_ACID)) @@ -5521,8 +5673,8 @@ u32 GetBattlerAbility(u8 battlerId) && gActionsByTurnOrder[gBattlerByTurnOrder[gBattlerAttacker]] == B_ACTION_USE_MOVE && gCurrentTurnActionNumber < gBattlersCount) return ABILITY_NONE; - else - return gBattleMons[battlerId].ability; + + return gBattleMons[battlerId].ability; } u32 IsAbilityOnSide(u32 battlerId, u32 ability) @@ -5574,7 +5726,7 @@ u32 IsAbilityPreventingEscape(u32 battlerId) return 0; #endif #if B_SHADOW_TAG_ESCAPE >= GEN_4 - if ((id = IsAbilityOnOpposingSide(battlerId, ABILITY_SHADOW_TAG)) && gBattleMons[battlerId].ability != ABILITY_SHADOW_TAG) + if ((id = IsAbilityOnOpposingSide(battlerId, ABILITY_SHADOW_TAG)) && GetBattlerAbility(battlerId) != ABILITY_SHADOW_TAG) #else if (id = IsAbilityOnOpposingSide(battlerId, ABILITY_SHADOW_TAG)) #endif @@ -6766,6 +6918,10 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn) switch (atkHoldEffect) { case HOLD_EFFECT_FLINCH: + #if B_SERENE_GRACE_BOOST >= GEN_5 + if (GetBattlerAbility(gBattlerAttacker) == ABILITY_SERENE_GRACE) + atkHoldEffectParam *= 2; + #endif if (gBattleMoveDamage != 0 // Need to have done damage && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) && TARGET_TURN_DAMAGED @@ -7121,7 +7277,7 @@ u32 GetMoveTarget(u16 move, u8 setTarget) targetBattler = SetRandomTarget(gBattlerAttacker); if (gBattleMoves[move].type == TYPE_ELECTRIC && IsAbilityOnOpposingSide(gBattlerAttacker, ABILITY_LIGHTNING_ROD) - && gBattleMons[targetBattler].ability != ABILITY_LIGHTNING_ROD) + && GetBattlerAbility(targetBattler) != ABILITY_LIGHTNING_ROD) { targetBattler ^= BIT_FLANK; RecordAbilityBattle(targetBattler, gBattleMons[targetBattler].ability); @@ -7129,7 +7285,7 @@ u32 GetMoveTarget(u16 move, u8 setTarget) } else if (gBattleMoves[move].type == TYPE_WATER && IsAbilityOnOpposingSide(gBattlerAttacker, ABILITY_STORM_DRAIN) - && gBattleMons[targetBattler].ability != ABILITY_STORM_DRAIN) + && GetBattlerAbility(targetBattler) != ABILITY_STORM_DRAIN) { targetBattler ^= BIT_FLANK; RecordAbilityBattle(targetBattler, gBattleMons[targetBattler].ability); @@ -7307,7 +7463,7 @@ u32 GetBattlerHoldEffect(u8 battlerId, bool32 checkNegating) return HOLD_EFFECT_NONE; if (gFieldStatuses & STATUS_FIELD_MAGIC_ROOM) return HOLD_EFFECT_NONE; - if (gBattleMons[battlerId].ability == ABILITY_KLUTZ && !(gStatuses3[battlerId] & STATUS3_GASTRO_ACID)) + if (GetBattlerAbility(battlerId) == ABILITY_KLUTZ) return HOLD_EFFECT_NONE; } @@ -7332,15 +7488,73 @@ u32 GetBattlerHoldEffectParam(u8 battlerId) bool32 IsMoveMakingContact(u16 move, u8 battlerAtk) { if (!(gBattleMoves[move].flags & FLAG_MAKES_CONTACT)) - return FALSE; + { + if (gBattleMoves[move].effect == EFFECT_SHELL_SIDE_ARM && gSwapDamageCategory) + return TRUE; + else + return FALSE; + } else if (GetBattlerAbility(battlerAtk) == ABILITY_LONG_REACH) + { return FALSE; + } else if (GetBattlerHoldEffect(battlerAtk, TRUE) == HOLD_EFFECT_PROTECTIVE_PADS) + { return FALSE; + } else + { return TRUE; + } } +bool32 IsBattlerProtected(u8 battlerId, u16 move) +{ + // Decorate bypasses protect and detect, but not crafty shield + if (move == MOVE_DECORATE) + { + if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_CRAFTY_SHIELD) + return TRUE; + else if (gProtectStructs[battlerId].protected) + return FALSE; + } + + // Protective Pads doesn't stop Unseen Fist from bypassing Protect effects, so IsMoveMakingContact() isn't used here. + // This means extra logic is needed to handle Shell Side Arm. + if (GetBattlerAbility(gBattlerAttacker) == ABILITY_UNSEEN_FIST + && (gBattleMoves[move].flags & FLAG_MAKES_CONTACT || (gBattleMoves[move].effect == EFFECT_SHELL_SIDE_ARM && gSwapDamageCategory))) + return FALSE; + else if (!(gBattleMoves[move].flags & FLAG_PROTECT_AFFECTED)) + return FALSE; + else if (gBattleMoves[move].effect == MOVE_EFFECT_FEINT) + return FALSE; + else if (gProtectStructs[battlerId].protected) + return TRUE; + else if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_WIDE_GUARD + && gBattleMoves[move].target & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY)) + return TRUE; + else if (gProtectStructs[battlerId].banefulBunkered) + return TRUE; + else if (gProtectStructs[battlerId].obstructed && !IS_MOVE_STATUS(move)) + return TRUE; + else if (gProtectStructs[battlerId].spikyShielded) + return TRUE; + else if (gProtectStructs[battlerId].kingsShielded && gBattleMoves[move].power != 0) + return TRUE; + else if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_QUICK_GUARD + && GetChosenMovePriority(gBattlerAttacker) > 0) + return TRUE; + else if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_CRAFTY_SHIELD + && IS_MOVE_STATUS(move)) + return TRUE; + else if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_MAT_BLOCK + && !IS_MOVE_STATUS(move)) + return TRUE; + else + return FALSE; +} + + bool32 IsBattlerGrounded(u8 battlerId) { if (GetBattlerHoldEffect(battlerId, TRUE) == HOLD_EFFECT_IRON_BALL) @@ -7696,7 +7910,7 @@ static u16 CalcMoveBasePower(u16 move, u8 battlerAtk, u8 battlerDef) if (weight >= ARRAY_COUNT(sHeatCrashPowerTable)) basePower = sHeatCrashPowerTable[ARRAY_COUNT(sHeatCrashPowerTable) - 1]; else - basePower = sHeatCrashPowerTable[i]; + basePower = sHeatCrashPowerTable[weight]; break; case EFFECT_PUNISHMENT: basePower = 60 + (CountBattlerStatIncreases(battlerDef, FALSE) * 20); @@ -7731,6 +7945,10 @@ static u16 CalcMoveBasePower(u16 move, u8 battlerAtk, u8 battlerDef) && (gDisableStructs[battlerDef].isFirstTurn != 2 || B_PAYBACK_SWITCH_BOOST < GEN_5)) basePower *= 2; break; + case EFFECT_BOLT_BEAK: + if (GetBattlerTurnOrderNum(battlerAtk) < GetBattlerTurnOrderNum(battlerDef)) + basePower *= 2; + break; case EFFECT_ROUND: if (gChosenMoveByBattler[BATTLE_PARTNER(battlerAtk)] == MOVE_ROUND && !(gAbsentBattlerFlags & gBitTable[BATTLE_PARTNER(battlerAtk)])) basePower *= 2; @@ -7773,6 +7991,11 @@ static u16 CalcMoveBasePower(u16 move, u8 battlerAtk, u8 battlerDef) if (gFieldStatuses & STATUS_FIELD_GRAVITY) MulModifier(&basePower, UQ_4_12(1.5)); break; + case EFFECT_TERRAIN_PULSE: + if ((gFieldStatuses & STATUS_FIELD_TERRAIN_ANY) + && IsBattlerGrounded(gBattlerAttacker)) + basePower *= 2; + break; } // move-specific base power changes @@ -7846,7 +8069,7 @@ static u32 CalcMoveBasePowerAfterModifiers(u16 move, u8 battlerAtk, u8 battlerDe MulModifier(&modifier, UQ_4_12(1.3)); break; case ABILITY_TOUGH_CLAWS: - if (gBattleMoves[move].flags & FLAG_MAKES_CONTACT) + if (IsMoveMakingContact(move, battlerAtk)) MulModifier(&modifier, UQ_4_12(1.3)); break; case ABILITY_STRONG_JAW: @@ -7914,7 +8137,7 @@ static u32 CalcMoveBasePowerAfterModifiers(u16 move, u8 battlerAtk, u8 battlerDe if (IsAbilityOnField(ABILITY_AURA_BREAK)) MulModifier(&modifier, UQ_4_12(0.75)); else - MulModifier(&modifier, UQ_4_12(1.25)); + MulModifier(&modifier, UQ_4_12(1.33)); } // attacker partner's abilities @@ -7996,7 +8219,11 @@ static u32 CalcMoveBasePowerAfterModifiers(u16 move, u8 battlerAtk, u8 battlerDe MulModifier(&modifier, holdEffectModifier); break; case HOLD_EFFECT_SOUL_DEW: - if ((gBattleMons[battlerAtk].species == SPECIES_LATIAS || gBattleMons[battlerAtk].species == SPECIES_LATIOS) && !(gBattleTypeFlags & BATTLE_TYPE_FRONTIER)) + #if B_SOUL_DEW_BOOST >= GEN_7 + if ((gBattleMons[battlerAtk].species == SPECIES_LATIAS || gBattleMons[battlerAtk].species == SPECIES_LATIOS) && (moveType == TYPE_PSYCHIC || moveType == TYPE_DRAGON)) + #else + if ((gBattleMons[battlerAtk].species == SPECIES_LATIAS || gBattleMons[battlerAtk].species == SPECIES_LATIOS) && !(gBattleTypeFlags & BATTLE_TYPE_FRONTIER) && IS_MOVE_SPECIAL(move)) + #endif MulModifier(&modifier, holdEffectModifier); break; case HOLD_EFFECT_GEMS: @@ -8071,8 +8298,11 @@ static u32 CalcMoveBasePowerAfterModifiers(u16 move, u8 battlerAtk, u8 battlerDe MulModifier(&modifier, UQ_4_12(0.5)); break; case EFFECT_KNOCK_OFF: - if (gBattleMons[battlerDef].item != ITEM_NONE && GetBattlerAbility(battlerDef) != ABILITY_STICKY_HOLD) + #if B_KNOCK_OFF_DMG >= GEN_6 + if (gBattleMons[battlerDef].item != ITEM_NONE + && CanBattlerGetOrLoseItem(battlerDef, gBattleMons[battlerDef].item)) MulModifier(&modifier, UQ_4_12(1.5)); + #endif break; } @@ -8409,6 +8639,14 @@ static u32 CalcDefenseStat(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, if (!usesDefStat) MulModifier(&modifier, UQ_4_12(1.5)); break; +#if B_SOUL_DEW_BOOST <= GEN_6 + case HOLD_EFFECT_SOUL_DEW: + if ((gBattleMons[battlerDef].species == SPECIES_LATIAS || gBattleMons[battlerDef].species == SPECIES_LATIOS) + && !(gBattleTypeFlags & BATTLE_TYPE_FRONTIER) + && !usesDefStat) + MulModifier(&modifier, UQ_4_12(1.5)); + break; +#endif } // sandstorm sp.def boost for rock types @@ -8479,7 +8717,9 @@ static u32 CalcFinalDmg(u32 dmg, u16 move, u8 battlerAtk, u8 battlerDef, u8 move if (((gSideStatuses[defSide] & SIDE_STATUS_REFLECT && IS_MOVE_PHYSICAL(move)) || (gSideStatuses[defSide] & SIDE_STATUS_LIGHTSCREEN && IS_MOVE_SPECIAL(move)) || (gSideStatuses[defSide] & SIDE_STATUS_AURORA_VEIL)) - && abilityAtk != ABILITY_INFILTRATOR) + && abilityAtk != ABILITY_INFILTRATOR + && !(isCrit) + && !gProtectStructs[gBattlerAttacker].confusionSelfDmg) { if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) MulModifier(&finalModifier, UQ_4_12(0.66)); @@ -8648,9 +8888,8 @@ static void MulByTypeEffectiveness(u16 *modifier, u16 move, u8 moveType, u8 batt mod = UQ_4_12(2.0); if (moveType == TYPE_GROUND && defType == TYPE_FLYING && IsBattlerGrounded(battlerDef) && mod == UQ_4_12(0.0)) mod = UQ_4_12(1.0); - - if (gProtectStructs[battlerDef].kingsShielded && gBattleMoves[move].effect != EFFECT_FEINT) - mod = UQ_4_12(1.0); + if (moveType == TYPE_FIRE && gDisableStructs[battlerDef].tarShot) + mod = UQ_4_12(2.0); // WEATHER_STRONG_WINDS weakens Super Effective moves against Flying-type Pokémon if (WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_STRONG_WINDS) @@ -8875,9 +9114,9 @@ bool32 CanMegaEvolve(u8 battlerId) struct MegaEvolutionData *mega = &(((struct ChooseMoveStruct*)(&gBattleResources->bufferA[gActiveBattler][4]))->mega); #ifdef ITEM_EXPANSION - // Check if Player has a Mega Bracelet + // Check if Player has a Mega Ring if ((GetBattlerPosition(battlerId) == B_POSITION_PLAYER_LEFT || (!(gBattleTypeFlags & BATTLE_TYPE_MULTI) && GetBattlerPosition(battlerId) == B_POSITION_PLAYER_RIGHT)) - && !CheckBagHasItem(ITEM_MEGA_BRACELET, 1)) + && !CheckBagHasItem(ITEM_MEGA_RING, 1)) return FALSE; #endif @@ -8969,6 +9208,7 @@ void UndoFormChange(u32 monId, u32 side, bool32 isSwitchingOut) // Changed Form ID Default Form ID Should change on switch {SPECIES_MIMIKYU_BUSTED, SPECIES_MIMIKYU, FALSE}, {SPECIES_GRENINJA_ASH, SPECIES_GRENINJA_BATTLE_BOND, FALSE}, + {SPECIES_MELOETTA_PIROUETTE, SPECIES_MELOETTA, FALSE}, {SPECIES_AEGISLASH_BLADE, SPECIES_AEGISLASH, TRUE}, {SPECIES_DARMANITAN_ZEN_MODE, SPECIES_DARMANITAN, TRUE}, {SPECIES_MINIOR, SPECIES_MINIOR_CORE_RED, TRUE}, @@ -8981,6 +9221,7 @@ void UndoFormChange(u32 monId, u32 side, bool32 isSwitchingOut) {SPECIES_WISHIWASHI_SCHOOL, SPECIES_WISHIWASHI, TRUE}, {SPECIES_CRAMORANT_GORGING, SPECIES_CRAMORANT, TRUE}, {SPECIES_CRAMORANT_GULPING, SPECIES_CRAMORANT, TRUE}, + {SPECIES_MORPEKO_HANGRY, SPECIES_MORPEKO, TRUE}, }; currSpecies = GetMonData(&party[monId], MON_DATA_SPECIES, NULL); @@ -9126,7 +9367,9 @@ bool8 ShouldGetStatBadgeBoost(u16 badgeFlag, u8 battlerId) u8 GetBattleMoveSplit(u32 moveId) { - if (IS_MOVE_STATUS(moveId) || B_PHYSICAL_SPECIAL_SPLIT >= GEN_4) + if (gSwapDamageCategory) // Photon Geyser, Shell Side Arm, Light That Burns the Sky + return SPLIT_PHYSICAL; + else if (IS_MOVE_STATUS(moveId) || B_PHYSICAL_SPECIAL_SPLIT >= GEN_4) return gBattleMoves[moveId].split; else if (gBattleMoves[moveId].type < TYPE_MYSTERY) return SPLIT_PHYSICAL; diff --git a/src/battle_util2.c b/src/battle_util2.c index d15700706a..0af19de274 100644 --- a/src/battle_util2.c +++ b/src/battle_util2.c @@ -142,7 +142,7 @@ u32 sub_805725C(u8 battlerId) { u32 toSub; - if (gBattleMons[battlerId].ability == ABILITY_EARLY_BIRD) + if (GetBattlerAbility(battlerId) == ABILITY_EARLY_BIRD) toSub = 2; else toSub = 1; diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index 97d61202a4..a49cf5fd87 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -378,7 +378,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = .secondaryEffectChance = 0, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = FLAG_MAKES_CONTACT | FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_KINGS_ROCK_AFFECTED, + .flags = FLAG_MAKES_CONTACT | FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_KINGS_ROCK_AFFECTED | FLAG_TWO_STRIKES, .split = SPLIT_PHYSICAL, }, @@ -649,7 +649,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = .secondaryEffectChance = 20, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_SHEER_FORCE_BOOST, + .flags = FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_SHEER_FORCE_BOOST | FLAG_TWO_STRIKES, .split = SPLIT_PHYSICAL, }, @@ -2460,7 +2460,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = .secondaryEffectChance = 0, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_KINGS_ROCK_AFFECTED, + .flags = FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_KINGS_ROCK_AFFECTED | FLAG_TWO_STRIKES, .split = SPLIT_PHYSICAL, }, @@ -7267,7 +7267,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = .secondaryEffectChance = 0, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = FLAG_MAKES_CONTACT | FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_KINGS_ROCK_AFFECTED, + .flags = FLAG_MAKES_CONTACT | FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_KINGS_ROCK_AFFECTED | FLAG_TWO_STRIKES, .split = SPLIT_PHYSICAL, }, @@ -8367,7 +8367,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = .secondaryEffectChance = 0, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = FLAG_MAKES_CONTACT | FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_KINGS_ROCK_AFFECTED, + .flags = FLAG_MAKES_CONTACT | FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_KINGS_ROCK_AFFECTED | FLAG_TWO_STRIKES, .split = SPLIT_PHYSICAL, }, @@ -8575,7 +8575,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = .secondaryEffectChance = 0, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = FLAG_MAKES_CONTACT | FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_KINGS_ROCK_AFFECTED, + .flags = FLAG_MAKES_CONTACT | FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_KINGS_ROCK_AFFECTED | FLAG_TWO_STRIKES, .split = SPLIT_PHYSICAL, }, @@ -8614,7 +8614,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_RELIC_SONG] = { - .effect = EFFECT_SLEEP_HIT, + .effect = EFFECT_RELIC_SONG, .power = 75, .type = TYPE_NORMAL, .accuracy = 100, @@ -8624,6 +8624,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = .priority = 0, .flags = FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_SOUND | FLAG_SHEER_FORCE_BOOST, .split = SPLIT_SPECIAL, + .argument = STATUS1_SLEEP, }, [MOVE_SECRET_SWORD] = @@ -10454,7 +10455,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_PHOTON_GEYSER] = { - .effect = EFFECT_PLACEHOLDER, // Needs a custom move effect + .effect = EFFECT_PHOTON_GEYSER, .power = 100, .type = TYPE_PSYCHIC, .accuracy = 100, @@ -10462,7 +10463,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = .secondaryEffectChance = 0, .target = MOVE_TARGET_FOES_AND_ALLY, .priority = 0, - .flags = FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_KINGS_ROCK_AFFECTED, + .flags = FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_KINGS_ROCK_AFFECTED | FLAG_TARGET_ABILITY_IGNORED, .split = SPLIT_SPECIAL, }, @@ -10726,9 +10727,9 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_DOUBLE_IRON_BASH] = { #if B_UPDATED_MOVE_DATA >= GEN_8 - .flags = FLAG_MAKES_CONTACT | FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_IRON_FIST_BOOST | FLAG_SHEER_FORCE_BOOST, + .flags = FLAG_MAKES_CONTACT | FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_IRON_FIST_BOOST | FLAG_SHEER_FORCE_BOOST | FLAG_TWO_STRIKES, #else - .flags = FLAG_MAKES_CONTACT | FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_DMG_MINIMIZE | FLAG_IRON_FIST_BOOST | FLAG_SHEER_FORCE_BOOST, + .flags = FLAG_MAKES_CONTACT | FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_DMG_MINIMIZE | FLAG_IRON_FIST_BOOST | FLAG_SHEER_FORCE_BOOST | FLAG_TWO_STRIKES, #endif .effect = EFFECT_DOUBLE_IRON_BASH, .power = 60, @@ -10771,7 +10772,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_JAW_LOCK] = { - .effect = EFFECT_MEAN_LOOK, + .effect = EFFECT_JAW_LOCK, .power = 80, .type = TYPE_DARK, .accuracy = 100, @@ -10799,7 +10800,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_NO_RETREAT] = { - .effect = EFFECT_PLACEHOLDER, //TODO + .effect = EFFECT_NO_RETREAT, .power = 0, .type = TYPE_FIGHTING, .accuracy = 0, @@ -10813,7 +10814,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_TAR_SHOT] = { - .effect = EFFECT_SPEED_DOWN, + .effect = EFFECT_TAR_SHOT, .power = 0, .type = TYPE_ROCK, .accuracy = 100, @@ -10827,7 +10828,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_MAGIC_POWDER] = { - .effect = EFFECT_THIRD_TYPE, + .effect = EFFECT_SOAK, .power = 0, .type = TYPE_PSYCHIC, .accuracy = 100, @@ -10850,7 +10851,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = .secondaryEffectChance = 0, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_KINGS_ROCK_AFFECTED, + .flags = FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_KINGS_ROCK_AFFECTED | FLAG_TWO_STRIKES, .split = SPLIT_PHYSICAL, }, @@ -10870,7 +10871,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_OCTOLOCK] = { - .effect = EFFECT_MEAN_LOOK, + .effect = EFFECT_OCTOLOCK, .power = 0, .type = TYPE_FIGHTING, .accuracy = 100, @@ -10884,7 +10885,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_BOLT_BEAK] = { - .effect = EFFECT_PLACEHOLDER, //TODO + .effect = EFFECT_BOLT_BEAK, .power = 85, .type = TYPE_ELECTRIC, .accuracy = 100, @@ -10898,7 +10899,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_FISHIOUS_REND] = { - .effect = EFFECT_PLACEHOLDER, //TODO. same as bolt beak + .effect = EFFECT_BOLT_BEAK, .power = 85, .type = TYPE_WATER, .accuracy = 100, @@ -10926,7 +10927,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_CLANGOROUS_SOUL] = { - .effect = EFFECT_PLACEHOLDER, //TODO + .effect = EFFECT_CLANGOROUS_SOUL, .power = 0, .type = TYPE_DRAGON, .accuracy = 100, @@ -11038,7 +11039,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_AURA_WHEEL] = { - .effect = EFFECT_SPEED_UP_HIT, + .effect = EFFECT_AURA_WHEEL, .power = 110, .type = TYPE_ELECTRIC, .accuracy = 100, @@ -11290,12 +11291,12 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_SHELL_SIDE_ARM] = { - .effect = EFFECT_PLACEHOLDER, //TODO + .effect = EFFECT_SHELL_SIDE_ARM, .power = 90, .type = TYPE_POISON, .accuracy = 100, .pp = 10, - .secondaryEffectChance = 0, + .secondaryEffectChance = 20, .target = MOVE_TARGET_SELECTED, .priority = 0, .flags = FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_KINGS_ROCK_AFFECTED | FLAG_SHEER_FORCE_BOOST, @@ -11346,7 +11347,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_TERRAIN_PULSE] = { - .effect = EFFECT_PLACEHOLDER, //TODO + .effect = EFFECT_TERRAIN_PULSE, .power = 50, .type = TYPE_NORMAL, .accuracy = 100, @@ -11402,7 +11403,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_POLTERGEIST] = { - .effect = EFFECT_PLACEHOLDER, //TODO + .effect = EFFECT_POLTERGEIST, .power = 110, .type = TYPE_GHOST, .accuracy = 90, @@ -11480,7 +11481,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = .secondaryEffectChance = 0, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = FLAG_MAKES_CONTACT | FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_KINGS_ROCK_AFFECTED, + .flags = FLAG_MAKES_CONTACT | FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_KINGS_ROCK_AFFECTED | FLAG_TWO_STRIKES, .split = SPLIT_PHYSICAL, }, diff --git a/src/data/items.h b/src/data/items.h index ef5c8825d3..7e62558aa4 100644 --- a/src/data/items.h +++ b/src/data/items.h @@ -2680,7 +2680,7 @@ const struct Item gItems[] = .name = _("UP-GRADE"), .itemId = ITEM_UP_GRADE, .price = 2100, - .holdEffect = HOLD_EFFECT_UP_GRADE, + .holdEffect = HOLD_EFFECT_UPGRADE, .description = sUpGradeDesc, .pocket = POCKET_ITEMS, .type = ITEM_USE_BAG_MENU, @@ -2767,7 +2767,7 @@ const struct Item gItems[] = .name = _("STICK"), .itemId = ITEM_STICK, .price = 200, - .holdEffect = HOLD_EFFECT_STICK, + .holdEffect = HOLD_EFFECT_LEEK, .description = sStickDesc, .pocket = POCKET_ITEMS, .type = ITEM_USE_BAG_MENU, diff --git a/src/data/text/move_descriptions.h b/src/data/text/move_descriptions.h index e204fb1961..037261e321 100644 --- a/src/data/text/move_descriptions.h +++ b/src/data/text/move_descriptions.h @@ -2839,7 +2839,7 @@ static const u8 sMETEOR_BEAMDescription[] = _( "Sp. Attack before attacking."); static const u8 sSHELL_SIDE_ARMDescription[] = _( - "Uses higher of physical and\n" + "Deals better of physical and\n" "special damage. May poison."); static const u8 sMISTY_EXPLOSIONDescription[] = _( diff --git a/src/graphics.c b/src/graphics.c index 5ba3af42bb..1621f9d5b2 100644 --- a/src/graphics.c +++ b/src/graphics.c @@ -1395,11 +1395,6 @@ const u32 gBattleAnimBgPalette_Solarbeam[] = INCBIN_U32("graphics/battle_anims/b const u32 gBattleAnimBgPalette_MagmaStorm[] = INCBIN_U32("graphics/battle_anims/backgrounds/magma_storm.gbapal.lz"); //new battle bgs -const u32 gBattleAnimBgPalette_GigaImpact[] = INCBIN_U32("graphics/battle_anims/backgrounds/giga_impact.gbapal.lz"); - -//const u32 gBattleAnimBgImage_TrickRoom[] = INCBIN_U32("graphics/battle_anims/backgrounds/trick_room.4bpp.lz"); -//const u32 gBattleAnimBgPalette_TrickRoom[] = INCBIN_U32("graphics/battle_anims/backgrounds/trick_room.gbapal.lz"); -//const u32 gBattleAnimBgTilemap_TrickRoom[] = INCBIN_U32("graphics/battle_anims/backgrounds/trick_room_map.bin.lz"); const u32 gBattleAnimBgImage_Hurricane[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/hurricane.4bpp.lz"); const u32 gBattleAnimBgPalette_Hurricane[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/hurricane.gbapal.lz"); @@ -1407,15 +1402,14 @@ const u32 gBattleAnimBgTilemap_Hurricane[] = INCBIN_U32("graphics/battle_anims/b const u32 gBattleAnimBgPalette_RockWrecker[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/rock_wrecker.gbapal.lz"); +const u32 gBattleAnimBgTilemap_GigaImpactPlayer[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/giga_impact_player.bin.lz"); +const u32 gBattleAnimBgTilemap_GigaImpactOpponent[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/giga_impact_opponent.bin.lz"); +const u32 gBattleAnimBgTilemap_GigaImpactContest[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/giga_impact_contest.bin.lz"); +const u32 gBattleAnimBgImage_GigaImpact[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/giga_impact.4bpp.lz"); +const u32 gBattleAnimBgPalette_GigaImpact[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/giga_impact.gbapal.lz"); + const u32 gBattleAnimBgImage_SpacialRend[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/spacial_rend.4bpp.lz"); const u32 gBattleAnimBgPalette_SpacialRend[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/spacial_rend.gbapal.lz"); -const u32 gBattleAnimBgTilemap_SpacialRendOpponent[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/spacial_rend_opponent.bin.lz"); -const u32 gBattleAnimBgTilemap_SpacialRendPlayer[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/spacial_rend_player.bin.lz"); - -const u32 gBattleAnimBgImage_DarkVoid[] = INCBIN_U32("graphics/battle_anims/backgrounds/dark_void.4bpp.lz"); -const u32 gBattleAnimBgPalette_DarkVoid[] = INCBIN_U32("graphics/battle_anims/backgrounds/dark_void.gbapal.lz"); -const u32 gBattleAnimBgTilemap_DarkVoid[] = INCBIN_U32("graphics/battle_anims/backgrounds/dark_void.bin.lz"); - const u32 gBattleAnimBgPalette_SludgeWave[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/sludge_wave.gbapal.lz"); @@ -1441,10 +1435,6 @@ const u32 gBattleAnimBgImage_ClangorousSoulblaze[] = INCBIN_U32("graphics/battle const u32 gBattleAnimBgPalette_ClangorousSoulblaze[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/clangorous_soulblaze.gbapal.lz"); const u32 gBattleAnimBgTilemap_ClangorousSoulblaze[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/clangorous_soulblaze.bin.lz"); -//const u32 gBattleAnimBgImage_DarkVoid[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/dark_void.4bpp.lz"); -//const u32 gBattleAnimBgPalette_DarkVoid[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/dark_void.gbapal.lz"); -//const u32 gBattleAnimBgTilemap_DarkVoid[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/dark_void.bin.lz"); - const u32 gBattleAnimBgPalette_DynamaxCannon[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/dynamax_cannon.gbapal.lz"); const u32 gBattleAnimBgImage_ElectricTerrain[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/electric_terrain.4bpp.lz"); @@ -1463,14 +1453,6 @@ const u32 gBattleAnimBgTilemap_FocusBlast[] = INCBIN_U32("graphics/battle_anims/ const u32 gBattleAnimBgPalette_GarbageFalls[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/garbage_falls.gbapal.lz"); -const u32 gBattleAnimBgImage_GigaImpactOpponent[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/giga_impact_opponent.4bpp.lz"); -const u32 gBattleAnimBgPalette_GigaImpactOpponent[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/giga_impact_opponent.gbapal.lz"); -const u32 gBattleAnimBgTilemap_GigaImpactOpponent[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/giga_impact_opponent.bin.lz"); - -const u32 gBattleAnimBgImage_GigaImpactPlayer[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/giga_impact_player.4bpp.lz"); -const u32 gBattleAnimBgPalette_GigaImpactPlayer[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/giga_impact_player.gbapal.lz"); -const u32 gBattleAnimBgTilemap_GigaImpactPlayer[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/giga_impact_player.bin.lz"); - const u32 gBattleAnimBgImage_GrassyTerrain[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/grassy_terrain.4bpp.lz"); const u32 gBattleAnimBgPalette_GrassyTerrain[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/grassy_terrain.gbapal.lz"); const u32 gBattleAnimBgTilemap_GrassyTerrain[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/grassy_terrain.bin.lz"); @@ -1497,8 +1479,6 @@ const u32 gBattleAnimBgImage_LeafStorm[] = INCBIN_U32("graphics/battle_anims/bac const u32 gBattleAnimBgPalette_LeafStorm[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/leaf_storm.gbapal.lz"); const u32 gBattleAnimBgTilemap_LeafStorm[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/leaf_storm.bin.lz"); -const u32 gBattleAnimBgPalette_MagicRoom[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/magic_room.gbapal.lz"); - const u32 gBattleAnimBgImage_MaliciousMoonsault[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/malicious_moonsault.4bpp.lz"); const u32 gBattleAnimBgPalette_MaliciousMoonsault[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/malicious_moonsault.gbapal.lz"); const u32 gBattleAnimBgTilemap_MaliciousMoonsault[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/malicious_moonsault.bin.lz"); @@ -1553,6 +1533,10 @@ const u32 gBattleAnimBgImage_TrickRoom[] = INCBIN_U32("graphics/battle_anims/bac const u32 gBattleAnimBgPalette_TrickRoom[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/trick_room.gbapal.lz"); const u32 gBattleAnimBgTilemap_TrickRoom[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/trick_room.bin.lz"); +const u32 gBattleAnimBgPalette_MagicRoom[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/magic_room.gbapal.lz"); + +const u32 gBattleAnimBgPalette_WonderRoom[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/wonder_room.gbapal.lz"); + const u32 gBattleAnimBgImage_TwinkleTackle[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/twinkle_tackle.4bpp.lz"); const u32 gBattleAnimBgPalette_TwinkleTackle[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/twinkle_tackle.gbapal.lz"); const u32 gBattleAnimBgTilemap_TwinkleTackle[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/twinkle_tackle.bin.lz"); @@ -1565,7 +1549,8 @@ const u32 gBattleAnimBgImage_Waterfall[] = INCBIN_U32("graphics/battle_anims/bac const u32 gBattleAnimBgPalette_Waterfall[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/waterfall.gbapal.lz"); const u32 gBattleAnimBgTilemap_Waterfall[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/waterfall.bin.lz"); -const u32 gBattleAnimBgPalette_WonderRoom[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/wonder_room.gbapal.lz"); +const u32 gBattleAnimBgPalette_DarkVoid[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/dark_void.gbapal.lz"); +const u32 gBattleAnimBgTilemap_DarkVoid[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/dark_void.bin.lz"); const u32 gBattleAnimBgImage_ZMoveActivate[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/zmove_activate.4bpp.lz"); const u32 gBattleAnimBgPalette_ZMoveActivate[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/zmove_activate.gbapal.lz"); diff --git a/src/wild_encounter.c b/src/wild_encounter.c index 330a0014b9..ef0d572471 100644 --- a/src/wild_encounter.c +++ b/src/wild_encounter.c @@ -41,6 +41,8 @@ static bool8 IsAbilityAllowingEncounter(u8 level); // EWRAM vars EWRAM_DATA static u8 sWildEncountersDisabled = 0; EWRAM_DATA static u32 sFeebasRngValue = 0; +EWRAM_DATA bool8 gIsFishingEncounter = 0; +EWRAM_DATA bool8 gIsSurfingEncounter = 0; #include "data/wild_encounters.h" @@ -652,6 +654,7 @@ bool8 StandardWildEncounter(u16 currMetaTileBehavior, u16 previousMetaTileBehavi { if (TryGenerateWildMon(gWildMonHeaders[headerId].waterMonsInfo, WILD_AREA_WATER, WILD_CHECK_REPEL | WILD_CHECK_KEEN_EYE) == TRUE) { + gIsSurfingEncounter = TRUE; if (TryDoDoubleWildBattle()) { struct Pokemon mon1 = gEnemyParty[0]; @@ -803,6 +806,7 @@ void FishingWildEncounter(u8 rod) } IncrementGameStat(GAME_STAT_FISHING_CAPTURES); SetPokemonAnglerSpecies(species); + gIsFishingEncounter = TRUE; BattleSetup_StartWildBattle(); }