diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index a5ac603ed..062ac9880 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1882,6 +1882,36 @@ 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 diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s index 45d71f81d..b10c937ae 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" @@ -14081,7 +14082,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: @@ -23353,17 +23434,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 diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 3677bc535..cc43b0872 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -391,6 +391,14 @@ gBattleScriptsForMoveEffects:: .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 @@ -428,6 +436,113 @@ BattleScript_EffectAuraWheel: @ Aura Wheel can only be used by Morpeko 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_HOOPA_UNBOUND, BattleScript_EffectHyperspaceFuryUnbound jumpifspecies BS_ATTACKER, SPECIES_HOOPA, BattleScript_ButHoopaCantUseIt @@ -1743,7 +1858,7 @@ BattleScript_EffectSoak: attackanimation waitanimation trysoak BattleScript_ButItFailed - printstring STRINGID_TRANSFORMEDINTOWATERTYPE + printstring STRINGID_TARGETCHANGEDTYPE waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd @@ -6259,7 +6374,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 @@ -8920,7 +9035,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 @@ -8931,13 +9046,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 @@ -8946,7 +9061,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 diff --git a/include/battle.h b/include/battle.h index 3ddfb5c4e..40d884b35 100644 --- a/include/battle.h +++ b/include/battle.h @@ -112,6 +112,9 @@ struct DisableStruct u8 throatChopTimer; u8 usedMoves:4; u8 wrapTurns; + u8 noRetreat:1; + u8 tarShot:1; + u8 octolock:1; }; struct ProtectStruct @@ -227,10 +230,7 @@ struct FieldTimer u8 wonderRoomTimer; u8 magicRoomTimer; u8 trickRoomTimer; - u8 grassyTerrainTimer; - u8 mistyTerrainTimer; - u8 electricTerrainTimer; - u8 psychicTerrainTimer; + u8 terrainTimer; u8 gravityTimer; u8 fairyLockTimer; }; diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index b6df2168e..1b2591899 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -35,7 +35,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); diff --git a/include/battle_script_commands.h b/include/battle_script_commands.h index b55ac1391..5b263410c 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 3a933fe05..7fe96ad95 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -411,6 +411,8 @@ 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_MultiHitPrintStrings[]; extern const u8 BattleScript_BurnUpRemoveType[]; diff --git a/include/constants/battle.h b/include/constants/battle.h index 5a95d1853..282d8c555 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -358,24 +358,40 @@ #define MOVE_EFFECT_BUG_BITE 0x45 #define MOVE_EFFECT_RECOIL_HP_25 0x46 #define MOVE_EFFECT_RELIC_SONG 0x47 -#define MOVE_EFFECT_BURN_UP 0x48 +#define MOVE_EFFECT_TRAP_BOTH 0x48 +#define MOVE_EFFECT_BURN_UP 0x49 -#define NUM_MOVE_EFFECTS 0x49 +#define NUM_MOVE_EFFECTS 0x4A #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_config.h b/include/constants/battle_config.h index 8dc6d7296..0f6f277c7 100644 --- a/include/constants/battle_config.h +++ b/include/constants/battle_config.h @@ -95,7 +95,6 @@ #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. @@ -154,6 +153,7 @@ #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. // 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. @@ -174,6 +174,17 @@ #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. // Flag settings // To use the following features in scripting, replace the 0s with the flag ID you're assigning it to. @@ -186,26 +197,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 6397a09d7..a61a50d9c 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -374,7 +374,15 @@ #define EFFECT_AURA_WHEEL 368 #define EFFECT_PHOTON_GEYSER 369 #define EFFECT_SHELL_SIDE_ARM 370 +#define EFFECT_TERRAIN_PULSE 371 +#define EFFECT_JAW_LOCK 372 +#define EFFECT_NO_RETREAT 373 +#define EFFECT_TAR_SHOT 374 +#define EFFECT_POLTERGEIST 375 +#define EFFECT_OCTOLOCK 376 +#define EFFECT_CLANGOROUS_SOUL 377 +#define EFFECT_BOLT_BEAK 378 -#define NUM_BATTLE_MOVE_EFFECTS 371 +#define NUM_BATTLE_MOVE_EFFECTS 379 -#endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H \ No newline at end of file +#endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index b3fa659c2..3c919da19 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -201,7 +201,14 @@ #define VARIOUS_TRY_TO_APPLY_MIMICRY 128 #define VARIOUS_PHOTON_GEYSER_CHECK 129 #define VARIOUS_SHELL_SIDE_ARM_CHECK 130 -#define VARIOUS_IS_PARENTAL_BOND_LAST_STRIKE 131 +#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_IS_PARENTAL_BOND_LAST_STRIKE 137 + // Cmd_manipulatedamage #define DMG_CHANGE_SIGN 0 @@ -220,6 +227,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 8fba7597c..d439e3e7f 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -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 @@ -602,8 +602,13 @@ #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 BATTLESTRINGS_COUNT 602 +#define BATTLESTRINGS_COUNT 607 // The below IDs are all indexes into battle message tables, // used to determine which of a set of messages to print. diff --git a/include/wild_encounter.h b/include/wild_encounter.h index 200243170..5f4fcf536 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 c739e3d9e..547b1a211 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -1473,7 +1473,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. @@ -1714,7 +1714,7 @@ 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: @@ -2465,7 +2465,7 @@ 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) @@ -2707,7 +2707,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); } @@ -2716,7 +2716,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); } @@ -2782,7 +2782,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); } @@ -2971,7 +2971,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case ABILITY_BEAST_BOOST: if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // 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; @@ -3771,7 +3771,7 @@ 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 score += 9; @@ -4922,7 +4922,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_util.c b/src/battle_ai_util.c index 1e229fbe8..71dc78d0a 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -660,9 +660,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); @@ -1033,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++) @@ -1048,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; @@ -1063,7 +1089,7 @@ 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); u16 *moves = gBattleResources->battleHistory->usedMoves[battlerDef]; for (i = 0; i < MAX_MON_MOVES; i++) @@ -1677,7 +1703,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 (IsAiFaster(AI_CHECK_FASTER) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. if (gBattleMons[battlerDef].statStages[STAT_ATK] > 4 @@ -1685,7 +1711,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; @@ -1693,7 +1719,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 (IsAiFaster(AI_CHECK_FASTER) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. if (gBattleMons[battlerDef].statStages[STAT_DEF] > 4 @@ -1701,7 +1727,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; @@ -1709,13 +1735,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 (IsAiFaster(AI_CHECK_FASTER) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. if (IsAiFaster(AI_CHECK_SLOWER) && 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; @@ -1723,14 +1749,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 (IsAiFaster(AI_CHECK_FASTER) && 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; @@ -1738,14 +1764,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 (IsAiFaster(AI_CHECK_FASTER) && 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; @@ -1753,13 +1779,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 (IsAiFaster(AI_CHECK_FASTER) && 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; @@ -1767,19 +1793,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 (IsAiFaster(AI_CHECK_FASTER) && 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]; @@ -2433,9 +2459,9 @@ bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 mo if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // 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)) @@ -2500,7 +2526,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 @@ -2512,7 +2538,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 @@ -2520,7 +2546,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 @@ -2904,7 +2930,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 diff --git a/src/battle_anim_new.c b/src/battle_anim_new.c index 3bc45939f..63fed0b3d 100644 --- a/src/battle_anim_new.c +++ b/src/battle_anim_new.c @@ -5073,3 +5073,25 @@ void AnimTask_ShellSideArm(u8 taskId) 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_utility_funcs.c b/src/battle_anim_utility_funcs.c index 6cefba92a..c85a918da 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_main.c b/src/battle_main.c index 9b99f96de..9ffaab746 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" @@ -5024,6 +5025,8 @@ static void FreeResetData_ReturnToOvOrDoEvolutions(void) { if (!gPaletteFade.active) { + gIsFishingEncounter = FALSE; + gIsSurfingEncounter = FALSE; ResetSpriteData(); if (gLeveledUpInBattle && (gBattleOutcome == B_OUTCOME_WON || gBattleOutcome == B_OUTCOME_CAUGHT)) { @@ -5195,6 +5198,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); diff --git a/src/battle_message.c b/src/battle_message.c index f52f6be7e..30af20a78 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!"); @@ -728,6 +728,11 @@ static const u8 sText_SwappedAbilities[] = _("{B_DEF_NAME_WITH_PREFIX} swapped A 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}!"); const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = { @@ -1210,7 +1215,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, @@ -1320,6 +1325,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[] = diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 243661622..403d08748 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" @@ -1151,18 +1153,76 @@ static const u16 sFinalStrikeOnlyEffects[] = EFFECT_HIT_PREVENT_ESCAPE, }; -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[] = @@ -1207,27 +1267,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 @@ -3093,9 +3164,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++; } @@ -3120,7 +3192,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++; @@ -3140,9 +3212,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++; } @@ -3166,7 +3239,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++; @@ -3254,8 +3327,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); @@ -3449,6 +3529,21 @@ void SetMoveEffect(bool32 primary, u32 certain) } } 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; case MOVE_EFFECT_BURN_UP: // This seems unnecessary but is done to make it work properly with Parental Bond BattleScriptPush(gBattlescriptCurrInstr + 1); @@ -7413,19 +7508,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; } @@ -8338,13 +8433,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; @@ -9021,23 +9118,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: @@ -9166,6 +9260,7 @@ static void Cmd_various(void) else gBattlescriptCurrInstr += 7; return; + } case VARIOUS_JUMP_IF_WEATHER_AFFECTED: { u32 weatherFlags = T1_READ_32(gBattlescriptCurrInstr + 3); @@ -9175,7 +9270,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; @@ -9260,6 +9354,87 @@ 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; @@ -9281,7 +9456,7 @@ static void Cmd_various(void) else gBattlescriptCurrInstr += 7; return; - } + } // End of switch (gBattlescriptCurrInstr[2]) gBattlescriptCurrInstr += 3; } @@ -9812,6 +9987,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; @@ -9840,6 +10081,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) { @@ -9921,8 +10167,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) { @@ -12042,13 +12289,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]; } @@ -12632,39 +12881,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; @@ -12892,10 +13216,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; } @@ -12942,14 +13286,32 @@ 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 + side = GetBattlerSide(gBattlerAttacker); + #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; } @@ -12972,7 +13334,8 @@ u8 GetCatchingBattler(void) static void Cmd_handleballthrow(void) { - u8 ballMultiplier = 0; + u8 ballMultiplier = 10; + s8 ballAddition = 0; if (gBattleControllerExecFlags) return; @@ -12994,7 +13357,7 @@ static void Cmd_handleballthrow(void) } else { - u32 odds; + u32 odds, i; u8 catchRate; gLastThrownBall = gLastUsedItem; @@ -13003,53 +13366,193 @@ static void Cmd_handleballthrow(void) 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) @@ -13091,16 +13594,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 guarantee 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) @@ -13125,10 +13629,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 { @@ -13136,7 +13651,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; diff --git a/src/battle_util.c b/src/battle_util.c index a9cc68ff9..ee17d56ba 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -2344,7 +2344,7 @@ 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(); @@ -2355,7 +2355,7 @@ 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(); @@ -2368,7 +2368,7 @@ 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(); @@ -2380,7 +2380,7 @@ 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(); @@ -2456,6 +2456,7 @@ enum ENDTURN_NIGHTMARES, ENDTURN_CURSE, ENDTURN_WRAP, + ENDTURN_OCTOLOCK, ENDTURN_UPROAR, ENDTURN_THRASH, ENDTURN_FLINCH, @@ -2726,6 +2727,18 @@ 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) { @@ -4447,28 +4460,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++; @@ -6956,6 +6969,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 @@ -7897,7 +7914,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); @@ -7932,6 +7949,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; @@ -7974,6 +7995,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; case EFFECT_BEAT_UP: #if B_BEAT_UP_DMG >= GEN_5 basePower = CalcBeatUpPower(); @@ -8205,7 +8231,7 @@ static u32 CalcMoveBasePowerAfterModifiers(u16 move, u8 battlerAtk, u8 battlerDe #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)) + if ((gBattleMons[battlerAtk].species == SPECIES_LATIAS || gBattleMons[battlerAtk].species == SPECIES_LATIOS) && !(gBattleTypeFlags & BATTLE_TYPE_FRONTIER) && IS_MOVE_SPECIAL(move)) #endif MulModifier(&modifier, holdEffectModifier); break; @@ -8875,6 +8901,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 (moveType == TYPE_FIRE && gDisableStructs[battlerDef].tarShot) + mod = UQ_4_12(2.0); if (gProtectStructs[battlerDef].kingsShielded && gBattleMoves[move].effect != EFFECT_FEINT) mod = UQ_4_12(1.0); diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index 4e7a3f37f..e5a2690a6 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -10772,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, @@ -10800,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, @@ -10814,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, @@ -10828,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, @@ -10871,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, @@ -10885,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, @@ -10899,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, @@ -10927,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, @@ -11347,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, @@ -11403,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, diff --git a/src/wild_encounter.c b/src/wild_encounter.c index 330a0014b..ef0d57247 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(); }