diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 02c2a91d13..f39818f7bc 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1797,6 +1797,11 @@ .4byte \ptr .endm + .macro jumpifpranksterblocked battler:req, ptr:req + various \battler, VARIOUS_JUMP_IF_PRANKSTER_BLOCKED + .4byte \ptr + .endm + .macro eeriespellppreduce ptr:req various BS_TARGET, VARIOUS_EERIE_SPELL_PP_REDUCE .4byte \ptr @@ -1920,6 +1925,12 @@ 1: .endm + .macro jumpifflowerveilattacker jumpptr:req + jumpifnottype BS_ATTACKER, TYPE_GRASS, 1f + jumpifability BS_ATTACKER_SIDE, ABILITY_FLOWER_VEIL, \jumpptr + 1: + .endm + .macro setallytonexttarget jumpptr:req jumpifbyte CMP_GREATER_THAN, gBattlerTarget, 0x1, 1f addbyte gBattlerTarget, 0x2 diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s index d274717dca..d7de920967 100644 --- a/data/battle_anim_scripts.s +++ b/data/battle_anim_scripts.s @@ -532,7 +532,7 @@ gBattleAnims_Moves:: .4byte Move_QUASH .4byte Move_ACROBATICS .4byte Move_REFLECT_TYPE - .4byte Move_RETALITATE + .4byte Move_RETALIATE .4byte Move_FINAL_GAMBIT .4byte Move_BESTOW .4byte Move_INFERNO @@ -822,6 +822,7 @@ gBattleAnims_General:: .4byte General_SlideOffScreen @ B_ANIM_SLIDE_OFFSCREEN .4byte General_RestoreBg @ B_ANIM_RESTORE_BG .4byte General_TotemFlare @ B_ANIM_TOTEM_FLARE + .4byte General_GulpMissile @ B_ANIM_GULP_MISSILE .align 2 gBattleAnims_Special:: @@ -5610,7 +5611,7 @@ Move_REFLECT_TYPE: blendoff end -Move_RETALITATE: +Move_RETALIATE: loadspritegfx ANIM_TAG_CUT @Cut monbg ANIM_DEF_PARTNER setalpha 9, 8 @@ -24397,6 +24398,20 @@ General_TotemFlare:: clearmonbg ANIM_ATTACKER end +General_GulpMissile: @ Tackle anim (placeholder) + loadspritegfx ANIM_TAG_IMPACT + monbg ANIM_ATTACKER + setalpha 12, 8 + createsprite gHorizontalLungeSpriteTemplate, ANIM_ATTACKER, 2, 4, 4 + delay 6 + createsprite gBasicHitSplatSpriteTemplate, ANIM_ATTACKER, 2, 0, 0, ANIM_ATTACKER, 2 + createvisualtask AnimTask_ShakeMon, 2, ANIM_ATTACKER, 3, 0, 6, 1 + playsewithpan SE_M_COMET_PUNCH, SOUND_PAN_TARGET + waitforvisualfinish + clearmonbg ANIM_ATTACKER + blendoff + end + RainbowEndureEffect: launchtemplate gBlueEndureEnergySpriteTemplate 0x2 0x4 0x0 0xffe8 0x1a 0x2 delay 0x3 diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 01b897c774..0615e12398 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -252,7 +252,7 @@ gBattleScriptsForMoveEffects:: .4byte BattleScript_EffectHit @ EFFECT_ROUND .4byte BattleScript_EffectHit @ EFFECT_BRINE .4byte BattleScript_EffectHit @ EFFECT_VENOSHOCK - .4byte BattleScript_EffectHit @ EFFECT_RETALITATE + .4byte BattleScript_EffectHit @ EFFECT_RETALIATE .4byte BattleScript_EffectBulldoze @ EFFECT_BULLDOZE .4byte BattleScript_EffectHit @ EFFECT_FOUL_PLAY .4byte BattleScript_EffectHit @ EFFECT_PSYSHOCK @@ -379,6 +379,7 @@ gBattleScriptsForMoveEffects:: .4byte BattleScript_EffectDecorate @ EFFECT_DECORATE .4byte BattleScript_EffectHit @ EFFECT_SNIPE_SHOT .4byte BattleScript_EffectTripleHit @ EFFECT_TRIPLE_HIT + .4byte BattleScript_EffectRecoilHP25 @ EFFECT_RECOIL_HP_25 BattleScript_EffectDecorate: attackcanceler @@ -3867,19 +3868,25 @@ BattleScript_EffectPerishSong:: waitanimation printstring STRINGID_FAINTINTHREE waitmessage B_WAIT_TIME_LONG - setbyte sBATTLER, 0 + setbyte gBattlerTarget, 0 BattleScript_PerishSongLoop:: - jumpifability BS_SCRIPTING, ABILITY_SOUNDPROOF, BattleScript_PerishSongNotAffected + jumpifability BS_TARGET, ABILITY_SOUNDPROOF, BattleScript_PerishSongBlocked + jumpifpranksterblocked BS_TARGET, BattleScript_PerishSongNotAffected BattleScript_PerishSongLoopIncrement:: - addbyte sBATTLER, 1 - jumpifbytenotequal sBATTLER, gBattlersCount, BattleScript_PerishSongLoop + addbyte gBattlerTarget, 1 + jumpifbytenotequal gBattlerTarget, gBattlersCount, BattleScript_PerishSongLoop goto BattleScript_MoveEnd -BattleScript_PerishSongNotAffected:: +BattleScript_PerishSongBlocked:: printstring STRINGID_PKMNSXBLOCKSY2 waitmessage B_WAIT_TIME_LONG goto BattleScript_PerishSongLoopIncrement +BattleScript_PerishSongNotAffected: + printstring STRINGID_ITDOESNTAFFECT + waitmessage B_WAIT_TIME_LONG + goto BattleScript_PerishSongLoopIncrement + BattleScript_EffectSandstorm:: attackcanceler attackstring @@ -4905,6 +4912,12 @@ BattleScript_EffectRecoil50: setmoveeffect MOVE_EFFECT_RECOIL_50 | MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN goto BattleScript_EffectHit +BattleScript_EffectRecoilHP25: + setmoveeffect MOVE_EFFECT_RECOIL_HP_25 | MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN + jumpifnotmove MOVE_STRUGGLE, BattleScript_EffectHit + incrementgamestat GAME_STAT_USED_STRUGGLE + goto BattleScript_EffectHit + BattleScript_EffectTeeterDance:: attackcanceler attackstring @@ -5994,6 +6007,76 @@ BattleScript_PerishBodyActivates:: orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_x100000 return +BattleScript_GulpMissileGorging:: + call BattleScript_AbilityPopUp + playanimation BS_ATTACKER, B_ANIM_GULP_MISSILE, NULL + waitanimation + orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_x100000 + effectivenesssound + hitanimation BS_ATTACKER + waitstate + jumpifability BS_ATTACKER, ABILITY_MAGIC_GUARD, BattleScript_GulpMissileNoDmgGorging + healthbarupdate BS_ATTACKER + datahpupdate BS_ATTACKER + tryfaintmon BS_ATTACKER, FALSE, NULL + getbattlerfainted BS_ATTACKER + jumpifbyte CMP_EQUAL, gBattleCommunication, TRUE, BattleScript_GulpMissileNoSecondEffectGorging +BattleScript_GulpMissileNoDmgGorging: + handleformchange BS_TARGET, 0 + playanimation BS_TARGET, B_ANIM_FORM_CHANGE, NULL + waitanimation + swapattackerwithtarget + setmoveeffect MOVE_EFFECT_PARALYSIS + seteffectprimary + swapattackerwithtarget + return +BattleScript_GulpMissileNoSecondEffectGorging: + handleformchange BS_TARGET, 0 + playanimation BS_TARGET, B_ANIM_FORM_CHANGE, NULL + waitanimation + return + +BattleScript_GulpMissileGulping:: + call BattleScript_AbilityPopUp + playanimation BS_ATTACKER, B_ANIM_GULP_MISSILE, NULL + waitanimation + orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_x100000 + effectivenesssound + hitanimation BS_ATTACKER + waitstate + jumpifability BS_ATTACKER, ABILITY_MAGIC_GUARD, BattleScript_GulpMissileNoDmgGulping + healthbarupdate BS_ATTACKER + datahpupdate BS_ATTACKER + tryfaintmon BS_ATTACKER, FALSE, NULL + getbattlerfainted BS_ATTACKER + jumpifbyte CMP_EQUAL, gBattleCommunication, TRUE, BattleScript_GulpMissileNoSecondEffectGulping + jumpifability BS_ATTACKER, ABILITY_CLEAR_BODY, BattleScript_GulpMissileNoSecondEffectGulping + jumpifability BS_ATTACKER, ABILITY_FULL_METAL_BODY, BattleScript_GulpMissileNoSecondEffectGulping + jumpifability BS_ATTACKER, ABILITY_WHITE_SMOKE, BattleScript_GulpMissileNoSecondEffectGulping + jumpifflowerveilattacker BattleScript_GulpMissileNoSecondEffectGulping +BattleScript_GulpMissileNoDmgGulping: + handleformchange BS_TARGET, 0 + playanimation BS_TARGET, B_ANIM_FORM_CHANGE, NULL + waitanimation + swapattackerwithtarget @ to make gStatDownStringIds down below print the right battler + setstatchanger STAT_DEF, 1, TRUE + statbuffchange STAT_BUFF_NOT_PROTECT_AFFECTED, BattleScript_GulpMissileGorgingTargetDefenseCantGoLower + setgraphicalstatchangevalues + playanimation BS_TARGET, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1 + printfromtable gStatDownStringIds + waitmessage B_WAIT_TIME_LONG + swapattackerwithtarget @ restore the battlers, just in case + return +BattleScript_GulpMissileNoSecondEffectGulping: + handleformchange BS_TARGET, 0 + playanimation BS_TARGET, B_ANIM_FORM_CHANGE, NULL + waitanimation + return +BattleScript_GulpMissileGorgingTargetDefenseCantGoLower: + printstring STRINGID_STATSWONTDECREASE + waitmessage B_WAIT_TIME_LONG + return + BattleScript_PerishSongCountGoesDown:: printstring STRINGID_PKMNPERISHCOUNTFELL waitmessage B_WAIT_TIME_LONG @@ -6328,6 +6411,17 @@ BattleScript_MagicCoatBounce:: setmagiccoattarget BS_ATTACKER return +BattleScript_MagicCoatBouncePrankster:: + attackstring + ppreduce + pause B_WAIT_TIME_SHORT + printfromtable gMagicCoatBounceStringIds + waitmessage B_WAIT_TIME_LONG + printstring STRINGID_ITDOESNTAFFECT + waitmessage B_WAIT_TIME_LONG + orhalfword gMoveResultFlags, MOVE_RESULT_NO_EFFECT + goto BattleScript_MoveEnd + BattleScript_SnatchedMove:: attackstring ppreduce @@ -7624,6 +7718,19 @@ BattleScript_AbilityStatusEffect:: seteffectsecondary return +BattleScript_BattleBondActivatesOnMoveEndAttacker:: + pause 5 + copybyte gBattlerAbility, gBattlerAttacker + call BattleScript_AbilityPopUp + printstring STRINGID_ATTACKERBECAMEFULLYCHARGED + handleformchange BS_ATTACKER, 0 + handleformchange BS_ATTACKER, 1 + playanimation BS_ATTACKER, B_ANIM_FORM_CHANGE, NULL + waitanimation + handleformchange BS_ATTACKER, 2 + printstring STRINGID_ATTACKERBECAMEASHSPECIES + return + BattleScript_DancerActivates:: call BattleScript_AbilityPopUp waitmessage B_WAIT_TIME_SHORT @@ -8310,3 +8417,12 @@ BattleScript_EjectPackActivate_End2:: BattleScript_EjectPackActivates:: jumpifcantswitch BS_SCRIPTING, BattleScript_EjectButtonEnd goto BattleScript_EjectPackActivate_Ret + +BattleScript_DarkTypePreventsPrankster:: + attackstring + ppreduce + pause B_WAIT_TIME_SHORT + printstring STRINGID_ITDOESNTAFFECT + waitmessage B_WAIT_TIME_LONG + orhalfword gMoveResultFlags, MOVE_RESULT_NO_EFFECT + goto BattleScript_MoveEnd diff --git a/include/battle.h b/include/battle.h index 05f3a511c4..826a0929ec 100644 --- a/include/battle.h +++ b/include/battle.h @@ -150,6 +150,7 @@ struct ProtectStruct u32 touchedProtectLike:1; u32 disableEjectPack:1; u32 statFell:1; + u32 pranksterElevated:1; u32 physicalDmg; u32 specialDmg; u8 physicalBattlerId; diff --git a/include/battle_scripts.h b/include/battle_scripts.h index b15ab3aeb3..203be65198 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -97,6 +97,7 @@ extern const u8 BattleScript_SelectingImprisonedMove[]; extern const u8 BattleScript_SelectingImprisonedMoveInPalace[]; extern const u8 BattleScript_GrudgeTakesPp[]; extern const u8 BattleScript_MagicCoatBounce[]; +extern const u8 BattleScript_MagicCoatBouncePrankster[]; extern const u8 BattleScript_SnatchedMove[]; extern const u8 BattleScript_EnduredMsg[]; extern const u8 BattleScript_OneHitKOMsg[]; @@ -384,5 +385,9 @@ extern const u8 BattleScript_MentalHerbCureEnd2[]; extern const u8 BattleScript_TerrainPreventsEnd2[]; extern const u8 BattleScript_MistyTerrainPrevents[]; extern const u8 BattleScript_ElectricTerrainPrevents[]; +extern const u8 BattleScript_DarkTypePreventsPrankster[]; +extern const u8 BattleScript_GulpMissileGorging[]; +extern const u8 BattleScript_GulpMissileGulping[]; +extern const u8 BattleScript_BattleBondActivatesOnMoveEndAttacker[]; #endif // GUARD_BATTLE_SCRIPTS_H diff --git a/include/battle_util.h b/include/battle_util.h index 15b238b17d..781a2dd4dd 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -153,6 +153,7 @@ bool32 CompareStat(u8 battlerId, u8 statId, u8 cmpTo, u8 cmpKind); bool32 TryRoomService(u8 battlerId); void BufferStatChange(u8 battlerId, u8 statId, u8 stringId); void DoBurmyFormChange(u32 monId); +bool32 BlocksPrankster(u16 move, u8 battlerPrankster, u8 battlerDef); // ability checks bool32 IsRolePlayBannedAbilityAtk(u16 ability); diff --git a/include/constants/battle.h b/include/constants/battle.h index e88bb66dd7..bf6403a182 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -347,7 +347,8 @@ #define MOVE_EFFECT_THROAT_CHOP 0x43 #define MOVE_EFFECT_INCINERATE 0x44 #define MOVE_EFFECT_BUG_BITE 0x45 -#define NUM_MOVE_EFFECTS 0x46 +#define MOVE_EFFECT_RECOIL_HP_25 0x46 +#define NUM_MOVE_EFFECTS 0x47 #define MOVE_EFFECT_AFFECTS_USER 0x4000 #define MOVE_EFFECT_CERTAIN 0x8000 diff --git a/include/constants/battle_anim.h b/include/constants/battle_anim.h index c04bc14f7e..39e1feda9d 100644 --- a/include/constants/battle_anim.h +++ b/include/constants/battle_anim.h @@ -523,6 +523,7 @@ #define B_ANIM_SLIDE_OFFSCREEN 26 // for Emergency Exit #define B_ANIM_RESTORE_BG 27 // for Terrain Endings #define B_ANIM_TOTEM_FLARE 28 // Totem boosts aura flare +#define B_ANIM_GULP_MISSILE 29 // special animations table (gBattleAnims_Special) #define B_ANIM_LVL_UP 0 diff --git a/include/constants/battle_config.h b/include/constants/battle_config.h index 33a47a5381..bcf4491f94 100644 --- a/include/constants/battle_config.h +++ b/include/constants/battle_config.h @@ -40,6 +40,11 @@ #define SPECIES_BURMY 0 #define SPECIES_BURMY_SANDY_CLOAK 10013 #define SPECIES_BURMY_TRASH_CLOAK 10014 + #define SPECIES_CRAMORANT 0 + #define SPECIES_CRAMORANT_GORGING 10015 + #define SPECIES_CRAMORANT_GULPING 10016 + #define SPECIES_GRENINJA_BATTLE_BOND 0 + #define SPECIES_GRENINJA_ASH 10017 #endif // Items with peculiar battle effects. @@ -124,10 +129,12 @@ #define B_GALE_WINGS GEN_7 // In Gen7+ requires full HP to trigger. #define B_STANCE_CHANGE_FAIL GEN_7 // In Gen7+, Stance Change fails if the Pokémon is unable to use a move because of confusion, paralysis, etc. In Gen6, it doesn't. #define B_GHOSTS_ESCAPE GEN_7 // In Gen6+, Ghost-type Pokémon can escape even when blocked by abilities such as Shadow Tag. +#define B_SHADOW_TAG_ESCAPE GEN_7 // In Gen4+, if both sides have a Pokémon with Shadow Tag, all battlers can escape. Before, neither side could escape this situation. #define B_MOODY_ACC_EVASION GEN_8 // In Gen8, Moody CANNOT raise Accuracy and Evasion anymore. #define B_FLASH_FIRE_FROZEN GEN_7 // In Gen5+, Flash Fire can trigger even when frozen, when it couldn't before. #define B_SYNCHRONIZE_NATURE GEN_8 // In Gen8, if the Pokémon with Synchronize is leading the party, it's 100% guaranteed that wild Pokémon will have the same ability, as opposed to 50% previously. #define B_UPDATED_INTIMIDATE GEN_8 // In Gen8, Intimidate doesn't work on opponents with the Inner Focus, Scrappy, Own Tempo or Oblivious abilities. +#define B_PRANKSTER_DARK_TYPES GEN_7 // In Gen7+, Prankster-elevated status moves do not affect Dark type Pokémon. // Item settings #define B_HP_BERRIES GEN_7 // In Gen4+, berries which restore hp activate immediately after HP drops to half. In Gen3, the effect occurs at the end of the turn. diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index 760ee66fd2..5038b52c32 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -236,7 +236,7 @@ #define EFFECT_ROUND 230 #define EFFECT_BRINE 231 #define EFFECT_VENOSHOCK 232 -#define EFFECT_RETALITATE 233 +#define EFFECT_RETALIATE 233 #define EFFECT_BULLDOZE 234 #define EFFECT_FOUL_PLAY 235 #define EFFECT_PSYSHOCK 236 @@ -363,7 +363,8 @@ #define EFFECT_DECORATE 357 #define EFFECT_SNIPE_SHOT 358 #define EFFECT_TRIPLE_HIT 359 +#define EFFECT_RECOIL_HP_25 360 -#define NUM_BATTLE_MOVE_EFFECTS 360 +#define NUM_BATTLE_MOVE_EFFECTS 361 #endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 12a789c8b8..1f0db2a732 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -183,6 +183,7 @@ #define VARIOUS_JUMP_IF_TEAM_HEALTHY 111 #define VARIOUS_TRY_HEAL_QUARTER_HP 112 #define VARIOUS_REMOVE_TERRAIN 113 +#define VARIOUS_JUMP_IF_PRANKSTER_BLOCKED 114 // Cmd_manipulatedamage #define DMG_CHANGE_SIGN 0 diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index e32fd57780..ff5eb5366f 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -578,8 +578,10 @@ #define STRINGID_ATKGOTOVERINFATUATION 574 #define STRINGID_TORMENTEDNOMORE 575 #define STRINGID_HEALBLOCKEDNOMORE 576 +#define STRINGID_ATTACKERBECAMEFULLYCHARGED 577 +#define STRINGID_ATTACKERBECAMEASHSPECIES 578 -#define BATTLESTRINGS_COUNT 577 +#define BATTLESTRINGS_COUNT 579 // The below IDs are all indexes into battle message tables, // used to determine which of a set of messages to print. diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 03472271d1..42b8b9d408 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -520,6 +520,9 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) u32 i; u16 predictedMove = gLastMoves[battlerDef]; // TODO better move prediction + SetTypeBeforeUsingMove(move, battlerAtk); + GET_MOVE_TYPE(move, moveType); + if (IsTargetingPartner(battlerAtk, battlerDef)) return score; @@ -2472,7 +2475,10 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) bool32 attackerHasBadAbility = (GetAbilityRating(AI_DATA->atkAbility) < 0); bool32 partnerHasBadAbility = (GetAbilityRating(atkPartnerAbility) < 0); u16 predictedMove = gLastMoves[battlerDef]; //for now - + + SetTypeBeforeUsingMove(move, battlerAtk); + GET_MOVE_TYPE(move, moveType); + // check what effect partner is using if (AI_DATA->partnerMove != 0) { @@ -4751,7 +4757,10 @@ static s16 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) { u16 effect = gBattleMoves[move].effect; u8 moveType = gBattleMoves[move].type; - + + SetTypeBeforeUsingMove(move, battlerAtk); + GET_MOVE_TYPE(move, moveType); + if (IsTargetingPartner(battlerAtk, battlerDef)) { if ((effect == EFFECT_HEAL_PULSE || effect == EFFECT_HIT_ENEMY_HEAL_ALLY) diff --git a/src/battle_anim.c b/src/battle_anim.c index 958fb47208..d1a69bcde8 100644 --- a/src/battle_anim.c +++ b/src/battle_anim.c @@ -2213,6 +2213,7 @@ void LaunchBattleAnimation(const u8 *const animsTable[], u16 tableId, bool8 isMo case B_ANIM_DOOM_DESIRE_HIT: case B_ANIM_WISH_HEAL: case B_ANIM_MEGA_EVOLUTION: + case B_ANIM_GULP_MISSILE: hideHpBoxes = TRUE; break; default: diff --git a/src/battle_interface.c b/src/battle_interface.c index 63a05860d3..c1f76c6ce6 100644 --- a/src/battle_interface.c +++ b/src/battle_interface.c @@ -1053,6 +1053,7 @@ static void UpdateLvlInHealthbox(u8 healthboxSpriteId, u8 lvl) if (gBattleStruct->mega.evolvedPartyIds[GetBattlerSide(battler)] & gBitTable[gBattlerPartyIndexes[battler]]) { objVram = ConvertIntToDecimalStringN(text, lvl, STR_CONV_MODE_LEFT_ALIGN, 3); + xPos = 5 * (3 - (objVram - (text + 2))) - 1; } else { @@ -1060,6 +1061,7 @@ static void UpdateLvlInHealthbox(u8 healthboxSpriteId, u8 lvl) text[1] = CHAR_LV_2; objVram = ConvertIntToDecimalStringN(text + 2, lvl, STR_CONV_MODE_LEFT_ALIGN, 3); + xPos = 5 * (3 - (objVram - (text + 2))); } xPos = 5 * (3 - (objVram - (text + 2))); @@ -1507,18 +1509,12 @@ void DestroyMegaTriggerSprite(void) gBattleStruct->mega.triggerSpriteId = 0xFF; } -static const s8 sIndicatorPosSingles[][2] = +static const s8 sIndicatorPositions[][2] = { - [B_POSITION_PLAYER_LEFT] = {53, -8}, - [B_POSITION_OPPONENT_LEFT] = {45, -8}, -}; - -static const s8 sIndicatorPosDoubles[][2] = -{ - [B_POSITION_PLAYER_LEFT] = {53, -8}, - [B_POSITION_OPPONENT_LEFT] = {45, -8}, - [B_POSITION_PLAYER_RIGHT] = {53, -8}, - [B_POSITION_OPPONENT_RIGHT] = {45, -8}, + [B_POSITION_PLAYER_LEFT] = {52, -9}, + [B_POSITION_OPPONENT_LEFT] = {44, -9}, + [B_POSITION_PLAYER_RIGHT] = {52, -9}, + [B_POSITION_OPPONENT_RIGHT] = {44, -9}, }; u32 CreateMegaIndicatorSprite(u32 battlerId, u32 which) @@ -1531,16 +1527,15 @@ u32 CreateMegaIndicatorSprite(u32 battlerId, u32 which) position = GetBattlerPosition(battlerId); GetBattlerHealthboxCoords(battlerId, &x, &y); - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) - { - x += sIndicatorPosDoubles[position][0]; - y += sIndicatorPosDoubles[position][1]; - } - else - { - x += sIndicatorPosSingles[position][0]; - y += sIndicatorPosSingles[position][1]; - } + + x += sIndicatorPositions[position][0]; + y += sIndicatorPositions[position][1]; + + if (gBattleMons[battlerId].level >= 100) + x -= 4; + else if (gBattleMons[battlerId].level < 10) + x += 5; + spriteId = CreateSpriteAtEnd(&sSpriteTemplate_MegaIndicator, x, y, 0); gSprites[gSprites[gHealthboxSpriteIds[battlerId]].oam.affineParam].hOther_IndicatorSpriteId = spriteId; diff --git a/src/battle_main.c b/src/battle_main.c index 6f112bd6a9..055ec9bbe8 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -3096,6 +3096,7 @@ void FaintClearSetData(void) gProtectStructs[gActiveBattler].usedGravityPreventedMove = 0; gProtectStructs[gActiveBattler].usedThroatChopPreventedMove = 0; gProtectStructs[gActiveBattler].statRaised = 0; + gProtectStructs[gActiveBattler].statFell = 0; gDisableStructs[gActiveBattler].isFirstTurn = 2; @@ -3466,10 +3467,13 @@ static void TryDoEventsBeforeFirstTurn(void) return; // Set invalid mons as absent(for example when starting a double battle with only one pokemon). - for (i = 0; i < gBattlersCount; i++) + if (!(gBattleTypeFlags & BATTLE_TYPE_SAFARI)) { - if (gBattleMons[i].hp == 0 || gBattleMons[i].species == SPECIES_NONE) - gAbsentBattlerFlags |= gBitTable[i]; + for (i = 0; i < gBattlersCount; i++) + { + if (gBattleMons[i].hp == 0 || gBattleMons[i].species == SPECIES_NONE) + gAbsentBattlerFlags |= gBitTable[i]; + } } if (gBattleStruct->switchInAbilitiesCounter == 0) @@ -3683,7 +3687,7 @@ u8 IsRunningFromBattleImpossible(void) return 0; if (gBattleTypeFlags & BATTLE_TYPE_LINK) return 0; - if (gBattleMons[gActiveBattler].ability == ABILITY_RUN_AWAY) + if (GetBattlerAbility(gActiveBattler) == ABILITY_RUN_AWAY) return 0; if ((i = IsAbilityPreventingEscape(gActiveBattler))) @@ -4315,6 +4319,7 @@ s8 GetChosenMovePriority(u32 battlerId) { u16 move; + gProtectStructs[battlerId].pranksterElevated = 0; if (gProtectStructs[battlerId].noValidMoves) move = MOVE_STRUGGLE; else @@ -4336,6 +4341,7 @@ s8 GetMovePriority(u32 battlerId, u16 move) } else if (GetBattlerAbility(battlerId) == ABILITY_PRANKSTER && IS_MOVE_STATUS(move)) { + gProtectStructs[battlerId].pranksterElevated = 1; priority++; } else if (gBattleMoves[move].effect == EFFECT_GRASSY_GLIDE && gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN && IsBattlerGrounded(battlerId)) diff --git a/src/battle_message.c b/src/battle_message.c index ab10ceff06..69829a731a 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -704,10 +704,13 @@ static const u8 sText_EjectButtonActivate[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} static const u8 sText_AttackerGotOverInfatuation[] =_("{B_ATK_NAME_WITH_PREFIX} got over\nits infatuation!"); static const u8 sText_TormentedNoMore[] = _("{B_ATK_NAME_WITH_PREFIX} is\ntormented no more!"); static const u8 sText_HealBlockedNoMore[] = _("{B_ATK_NAME_WITH_PREFIX} is cured of\nits heal block!"); - +static const u8 sText_AttackerBecameFullyCharged[] = _("{B_ATK_NAME_WITH_PREFIX} became fully charged\ndue to its bond with its trainer!\p"); +static const u8 sText_AttackerBecameAshSpecies[] = _("{B_ATK_NAME_WITH_PREFIX} became Ash-{B_BUFF1}!\p"); const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = { + [STRINGID_ATTACKERBECAMEASHSPECIES - 12] = sText_AttackerBecameAshSpecies, + [STRINGID_ATTACKERBECAMEFULLYCHARGED - 12] = sText_AttackerBecameFullyCharged, [STRINGID_HEALBLOCKEDNOMORE - 12] = sText_HealBlockedNoMore, [STRINGID_TORMENTEDNOMORE - 12] = sText_TormentedNoMore, [STRINGID_ATKGOTOVERINFATUATION - 12] = sText_AttackerGotOverInfatuation, diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 6b4d0b9ab1..5a2b55da6b 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1416,8 +1416,17 @@ static void Cmd_attackcanceler(void) gProtectStructs[gBattlerTarget].bounceMove = 0; gProtectStructs[gBattlerTarget].usesBouncedMove = 1; gBattleCommunication[MULTISTRING_CHOOSER] = 0; - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_MagicCoatBounce; + if (BlocksPrankster(gCurrentMove, gBattlerTarget, gBattlerAttacker)) + { + // Opponent used a prankster'd magic coat -> reflected status move should fail against a dark-type attacker + gBattlerTarget = gBattlerAttacker; + gBattlescriptCurrInstr = BattleScript_MagicCoatBouncePrankster; + } + else + { + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_MagicCoatBounce; + } return; } else if (GetBattlerAbility(gBattlerTarget) == ABILITY_MAGIC_BOUNCE @@ -3058,7 +3067,7 @@ void SetMoveEffect(bool32 primary, u32 certain) gBattlescriptCurrInstr++; } else if (gBattleMons[gBattlerTarget].item - && gBattleMons[gBattlerTarget].ability == ABILITY_STICKY_HOLD) + && GetBattlerAbility(gBattlerTarget) == ABILITY_STICKY_HOLD) { BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_NoItemSteal; @@ -3168,6 +3177,14 @@ void SetMoveEffect(bool32 primary, u32 certain) BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_MoveEffectRecoilWithStatus; break; + case MOVE_EFFECT_RECOIL_HP_25: // Struggle + gBattleMoveDamage = (gBattleMons[gEffectBattler].maxHP) / 4; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_MoveEffectRecoil; + break; case MOVE_EFFECT_THRASH: if (gBattleMons[gEffectBattler].status2 & STATUS2_LOCK_CONFUSE) { @@ -5092,6 +5109,7 @@ static void Cmd_moveend(void) MoveValuesCleanUp(); gBattleScripting.moveEffect = gBattleScripting.savedMoveEffect; BattleScriptPush(gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]); + gBattleStruct->atkCancellerTracker = 0; // Run all cancellers on next target gBattlescriptCurrInstr = BattleScript_FlushMessageBox; return; } @@ -5183,6 +5201,7 @@ static void Cmd_moveend(void) u8 battler = battlers[i]; if (IsBattlerAlive(battler) && gProtectStructs[battler].statFell + && gProtectStructs[battler].disableEjectPack == 0 && GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_EJECT_PACK && !(gCurrentMove == MOVE_PARTING_SHOT && CanBattlerSwitch(gBattlerAttacker)) // Does not activate if attacker used Parting Shot and can switch out && CountUsablePartyMons(battler) > 0) // Has mon to switch into @@ -6573,6 +6592,7 @@ static void Cmd_jumptocalledmove(void) else gChosenMove = gCurrentMove = gCalledMove; + gBattleStruct->atkCancellerTracker = 0; gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]; } @@ -7273,7 +7293,7 @@ u32 IsLeafGuardProtected(u32 battler) bool32 IsShieldsDownProtected(u32 battler) { return (gBattleMons[battler].ability == ABILITY_SHIELDS_DOWN - && gBattleMons[battler].species == SPECIES_MINIOR); + && GetFormIdFromFormSpeciesId(gBattleMons[battler].species) < GetFormIdFromFormSpeciesId(SPECIES_MINIOR_CORE_RED)); // Minior is not in core form } u32 IsAbilityStatusProtected(u32 battler) @@ -7898,15 +7918,15 @@ static void Cmd_various(void) gBattlescriptCurrInstr += 7; return; case VARIOUS_SET_SIMPLE_BEAM: - if (IsEntrainmentTargetOrSimpleBeamBannedAbility(gBattleMons[gActiveBattler].ability)) + if (IsEntrainmentTargetOrSimpleBeamBannedAbility(gBattleMons[gBattlerTarget].ability) + || gBattleMons[gBattlerTarget].ability == ABILITY_SIMPLE) { gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); } else { - gBattleMons[gActiveBattler].ability = ABILITY_SIMPLE; + gBattleMons[gBattlerTarget].ability = ABILITY_SIMPLE; gBattlescriptCurrInstr += 7; - break; } return; case VARIOUS_TRY_ENTRAINMENT: @@ -8127,7 +8147,8 @@ static void Cmd_various(void) // Change species. if (gBattlescriptCurrInstr[3] == 0) { - PREPARE_SPECIES_BUFFER(gBattleTextBuff1, gBattleMons[gActiveBattler].species); + if (!gBattleTextBuff1) + PREPARE_SPECIES_BUFFER(gBattleTextBuff1, gBattleMons[gActiveBattler].species); BtlController_EmitSetMonData(0, REQUEST_SPECIES_BATTLE, gBitTable[gBattlerPartyIndexes[gActiveBattler]], 2, &gBattleMons[gActiveBattler].species); MarkBattlerForControllerExec(gActiveBattler); } @@ -8721,6 +8742,12 @@ static void Cmd_various(void) } gFieldStatuses &= ~STATUS_FIELD_TERRAIN_ANY; // remove the terrain break; + case VARIOUS_JUMP_IF_PRANKSTER_BLOCKED: + if (BlocksPrankster(gCurrentMove, gBattlerAttacker, gActiveBattler)) + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); + else + gBattlescriptCurrInstr += 7; + return; } gBattlescriptCurrInstr += 3; @@ -9103,7 +9130,7 @@ bool8 UproarWakeUpCheck(u8 battlerId) for (i = 0; i < gBattlersCount; i++) { - if (!(gBattleMons[i].status2 & STATUS2_UPROAR) || gBattleMons[battlerId].ability == ABILITY_SOUNDPROOF) + if (!(gBattleMons[i].status2 & STATUS2_UPROAR) || GetBattlerAbility(battlerId) == ABILITY_SOUNDPROOF) continue; gBattleScripting.battler = i; @@ -9425,9 +9452,7 @@ static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr } else { - // Check eject pack. disableEjectPack set for edge cases (e.g. attacking weak armor'd eject pack holder with u-turn) - if (gProtectStructs[gActiveBattler].disableEjectPack == 0) - gProtectStructs[gActiveBattler].statFell = 1; + gProtectStructs[gActiveBattler].statFell = 1; // Eject pack, lash out gBattleCommunication[MULTISTRING_CHOOSER] = (gBattlerTarget == gActiveBattler); // B_MSG_ATTACKER_STAT_FELL or B_MSG_DEFENDER_STAT_FELL } } @@ -10754,7 +10779,7 @@ static void Cmd_healpartystatus(void) else party = gEnemyParty; - if (gBattleMons[gBattlerAttacker].ability != ABILITY_SOUNDPROOF) + if (GetBattlerAbility(gBattlerAttacker) != ABILITY_SOUNDPROOF) { gBattleMons[gBattlerAttacker].status1 = 0; gBattleMons[gBattlerAttacker].status2 &= ~(STATUS2_NIGHTMARE); @@ -10770,7 +10795,7 @@ static void Cmd_healpartystatus(void) if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && !(gAbsentBattlerFlags & gBitTable[gActiveBattler])) { - if (gBattleMons[gActiveBattler].ability != ABILITY_SOUNDPROOF) + if (GetBattlerAbility(gActiveBattler) != ABILITY_SOUNDPROOF) { gBattleMons[gActiveBattler].status1 = 0; gBattleMons[gActiveBattler].status2 &= ~(STATUS2_NIGHTMARE); @@ -10883,7 +10908,8 @@ static void Cmd_trysetperishsong(void) for (i = 0; i < gBattlersCount; i++) { if (gStatuses3[i] & STATUS3_PERISH_SONG - || gBattleMons[i].ability == ABILITY_SOUNDPROOF) + || GetBattlerAbility(i) == ABILITY_SOUNDPROOF + || BlocksPrankster(gCurrentMove, gBattlerAttacker, i)) { notAffectedCount++; } @@ -11598,7 +11624,7 @@ static void Cmd_tryswapitems(void) // trick gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); } // check if ability prevents swapping - else if (gBattleMons[gBattlerTarget].ability == ABILITY_STICKY_HOLD) + else if (GetBattlerAbility(gBattlerTarget) == ABILITY_STICKY_HOLD) { gBattlescriptCurrInstr = BattleScript_StickyHoldActivates; gLastUsedAbility = gBattleMons[gBattlerTarget].ability; diff --git a/src/battle_util.c b/src/battle_util.c index bb5ee4be3f..b1f8b8009d 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -994,6 +994,11 @@ static const u8 sAbilitiesAffectedByMoldBreaker[] = [ABILITY_FLUFFY] = 1, [ABILITY_QUEENLY_MAJESTY] = 1, [ABILITY_WATER_BUBBLE] = 1, + [ABILITY_MIRROR_ARMOR] = 1, + [ABILITY_PUNK_ROCK] = 1, + [ABILITY_ICE_SCALES] = 1, + [ABILITY_ICE_FACE] = 1, + [ABILITY_PASTEL_VEIL] = 1, }; static const u8 sAbilitiesNotTraced[ABILITIES_COUNT] = @@ -1274,7 +1279,7 @@ void PressurePPLose(u8 target, u8 attacker, u16 move) { int moveIndex; - if (gBattleMons[target].ability != ABILITY_PRESSURE) + if (GetBattlerAbility(target) != ABILITY_PRESSURE) return; for (moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++) @@ -1306,7 +1311,7 @@ void PressurePPLoseOnUsingImprison(u8 attacker) for (i = 0; i < gBattlersCount; i++) { - if (atkSide != GetBattlerSide(i) && gBattleMons[i].ability == ABILITY_PRESSURE) + if (atkSide != GetBattlerSide(i) && GetBattlerAbility(i) == ABILITY_PRESSURE) { for (j = 0; j < MAX_MON_MOVES; j++) { @@ -1339,7 +1344,7 @@ void PressurePPLoseOnUsingPerishSong(u8 attacker) for (i = 0; i < gBattlersCount; i++) { - if (gBattleMons[i].ability == ABILITY_PRESSURE && i != attacker) + if (GetBattlerAbility(i) == ABILITY_PRESSURE && i != attacker) { for (j = 0; j < MAX_MON_MOVES; j++) { @@ -2734,8 +2739,8 @@ u8 DoBattlerEndTurnEffects(void) { gStatuses3[gActiveBattler] -= STATUS3_YAWN_TURN(1); if (!(gStatuses3[gActiveBattler] & STATUS3_YAWN) && !(gBattleMons[gActiveBattler].status1 & STATUS1_ANY) - && gBattleMons[gActiveBattler].ability != ABILITY_VITAL_SPIRIT - && gBattleMons[gActiveBattler].ability != ABILITY_INSOMNIA && !UproarWakeUpCheck(gActiveBattler) + && GetBattlerAbility(gActiveBattler) != ABILITY_VITAL_SPIRIT + && GetBattlerAbility(gActiveBattler) != ABILITY_INSOMNIA && !UproarWakeUpCheck(gActiveBattler) && !IsLeafGuardProtected(gActiveBattler)) { CancelMultiTurnMoves(gActiveBattler); @@ -3098,6 +3103,7 @@ enum CANCELLER_POWDER_MOVE, CANCELLER_POWDER_STATUS, CANCELLER_THROAT_CHOP, + CANCELLER_PRANKSTER, CANCELLER_END, CANCELLER_PSYCHIC_TERRAIN, CANCELLER_END2, @@ -3131,7 +3137,7 @@ u8 AtkCanceller_UnableToUseMove(void) else { u8 toSub; - if (gBattleMons[gBattlerAttacker].ability == ABILITY_EARLY_BIRD) + if (GetBattlerAbility(gBattlerAttacker) == ABILITY_EARLY_BIRD) toSub = 2; else toSub = 1; @@ -3141,7 +3147,7 @@ u8 AtkCanceller_UnableToUseMove(void) gBattleMons[gBattlerAttacker].status1 -= toSub; if (gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP) { - if (gCurrentMove != MOVE_SNORE && gCurrentMove != MOVE_SLEEP_TALK) + if (gChosenMove != MOVE_SNORE && gChosenMove != MOVE_SLEEP_TALK) { gBattlescriptCurrInstr = BattleScript_MoveUsedIsAsleep; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; @@ -3425,6 +3431,18 @@ u8 AtkCanceller_UnableToUseMove(void) } gBattleStruct->atkCancellerTracker++; break; + case CANCELLER_PRANKSTER: + if (BlocksPrankster(gCurrentMove, gBattlerAttacker, gBattlerTarget) + && !(IS_MOVE_STATUS(gCurrentMove) && GetBattlerAbility(gBattlerTarget) == ABILITY_MAGIC_BOUNCE)) + { + if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE) || !(gBattleMoves[gCurrentMove].target & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY))) + CancelMultiTurnMoves(gBattlerAttacker); // Don't cancel moves that can hit two targets bc one target might not be protected + gBattleScripting.battler = gBattlerAbility = gBattlerTarget; + gBattlescriptCurrInstr = BattleScript_DarkTypePreventsPrankster; + effect = 1; + } + gBattleStruct->atkCancellerTracker++; + break; case CANCELLER_END: break; } @@ -3728,6 +3746,8 @@ static bool32 ShouldChangeFormHpBased(u32 battler) {ABILITY_SHIELDS_DOWN, SPECIES_MINIOR_METEOR_VIOLET, SPECIES_MINIOR_CORE_VIOLET, 2}, {ABILITY_SHIELDS_DOWN, SPECIES_MINIOR_METEOR_YELLOW, SPECIES_MINIOR_CORE_YELLOW, 2}, {ABILITY_SCHOOLING, SPECIES_WISHIWASHI_SCHOOL, SPECIES_WISHIWASHI, 4}, + {ABILITY_GULP_MISSILE, SPECIES_CRAMORANT, SPECIES_CRAMORANT_GORGING, 2}, + {ABILITY_GULP_MISSILE, SPECIES_CRAMORANT, SPECIES_CRAMORANT_GULPING, 1}, }; u32 i; @@ -4980,6 +5000,42 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move effect++; } break; + case ABILITY_GULP_MISSILE: + if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + && !gProtectStructs[gBattlerAttacker].confusionSelfDmg + && TARGET_TURN_DAMAGED + && IsBattlerAlive(battler)) + { + if (gBattleMons[gBattlerTarget].species == SPECIES_CRAMORANT_GORGING) + { + gBattleStruct->changedSpecies[gBattlerPartyIndexes[gBattlerTarget]] = gBattleMons[gBattlerTarget].species; + gBattleMons[gBattlerTarget].species = SPECIES_CRAMORANT; + if (GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD) + { + gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 4; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + } + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_GulpMissileGorging; + effect++; + } + else if (gBattleMons[gBattlerTarget].species == SPECIES_CRAMORANT_GULPING) + { + gBattleStruct->changedSpecies[gBattlerPartyIndexes[gBattlerTarget]] = gBattleMons[gBattlerTarget].species; + gBattleMons[gBattlerTarget].species = SPECIES_CRAMORANT; + if (GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD) + { + gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 4; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + } + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_GulpMissileGulping; + effect++; + } + } + break; } break; case ABILITYEFFECT_MOVE_END_ATTACKER: // Same as above, but for attacker @@ -5016,6 +5072,27 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move effect++; } break; + case ABILITY_GULP_MISSILE: + if (((gCurrentMove == MOVE_SURF && TARGET_TURN_DAMAGED) || gStatuses3[gBattlerAttacker] & STATUS3_UNDERWATER) + && (effect = ShouldChangeFormHpBased(gBattlerAttacker))) + { + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_AttackerFormChange; + effect++; + } + break; + case ABILITY_BATTLE_BOND: + if (gBattleMons[gBattlerAttacker].species == SPECIES_GRENINJA_BATTLE_BOND + && gBattleResults.opponentFaintCounter != 0 + && CalculateEnemyPartyCount() > 1) + { + PREPARE_SPECIES_BUFFER(gBattleTextBuff1, gBattleMons[gBattlerAttacker].species); + gBattleStruct->changedSpecies[gBattlerPartyIndexes[gBattlerAttacker]] = gBattleMons[gBattlerAttacker].species; + gBattleMons[gBattlerAttacker].species = SPECIES_GRENINJA_ASH; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_BattleBondActivatesOnMoveEndAttacker; + } + break; } break; case ABILITYEFFECT_MOVE_END_OTHER: // Abilities that activate on *another* battler's moveend: Dancer, Soul-Heart, Receiver, Symbiosis @@ -5338,11 +5415,15 @@ u32 IsAbilityOnFieldExcept(u32 battlerId, u32 ability) u32 IsAbilityPreventingEscape(u32 battlerId) { u32 id; - - if (B_GHOSTS_ESCAPE >= GEN_6 && IS_BATTLER_OF_TYPE(battlerId, TYPE_GHOST)) - return 0; - - if ((id = IsAbilityOnOpposingSide(battlerId, ABILITY_SHADOW_TAG)) && gBattleMons[battlerId].ability != ABILITY_SHADOW_TAG) + #if B_GHOSTS_ESCAPE >= GEN_6 + if (IS_BATTLER_OF_TYPE(battlerId, TYPE_GHOST)) + return 0; + #endif + #if B_SHADOW_TAG_ESCAPE >= GEN_4 + if ((id = IsAbilityOnOpposingSide(battlerId, ABILITY_SHADOW_TAG)) && gBattleMons[battlerId].ability != ABILITY_SHADOW_TAG) + #else + if (id = IsAbilityOnOpposingSide(battlerId, ABILITY_SHADOW_TAG)) + #endif return id; if ((id = IsAbilityOnOpposingSide(battlerId, ABILITY_ARENA_TRAP)) && IsBattlerGrounded(battlerId)) return id; @@ -6009,6 +6090,7 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn) break; case HOLD_EFFECT_EJECT_PACK: if (gProtectStructs[battlerId].statFell + && gProtectStructs[battlerId].disableEjectPack == 0 && !(gCurrentMove == MOVE_PARTING_SHOT && CanBattlerSwitch(gBattlerAttacker))) // Does not activate if attacker used Parting Shot and can switch out { gProtectStructs[battlerId].statFell = FALSE; @@ -6117,7 +6199,20 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn) break; case HOLD_EFFECT_BLACK_SLUDGE: if (IS_BATTLER_OF_TYPE(battlerId, TYPE_POISON)) + { goto LEFTOVERS; + } + else if (GetBattlerAbility(battlerId) != ABILITY_MAGIC_GUARD && !moveTurn) + { + gBattleMoveDamage = gBattleMons[battlerId].maxHP / 8; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + BattleScriptExecute(BattleScript_ItemHurtEnd2); + effect = ITEM_HP_CHANGE; + RecordItemEffectBattle(battlerId, battlerHoldEffect); + PREPARE_ITEM_BUFFER(gBattleTextBuff1, gLastUsedItem); + } + break; case HOLD_EFFECT_LEFTOVERS: LEFTOVERS: if (gBattleMons[battlerId].hp < gBattleMons[battlerId].maxHP && !moveTurn) @@ -6847,7 +6942,11 @@ u8 GetMoveTarget(u16 move, u8 setTarget) moveTarget = setTarget - 1; else moveTarget = gBattleMoves[move].target; - + + // Special cases + if (move == MOVE_CURSE && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GHOST)) + moveTarget = MOVE_TARGET_USER; + switch (moveTarget) { case MOVE_TARGET_SELECTED: @@ -7238,7 +7337,7 @@ static const u16 sWeightToDamageTable[] = }; static const u8 sSpeedDiffPowerTable[] = {40, 60, 80, 120, 150}; -static const u8 sHeatCrushPowerTable[] = {40, 40, 60, 80, 100, 120}; +static const u8 sHeatCrashPowerTable[] = {40, 40, 60, 80, 100, 120}; static const u8 sTrumpCardPowerTable[] = {200, 80, 60, 50, 40}; const struct TypePower gNaturalGiftTable[] = @@ -7410,7 +7509,7 @@ static u16 CalcMoveBasePower(u16 move, u8 battlerAtk, u8 battlerDef) if (gBattleMons[battlerAtk].pp[i] >= ARRAY_COUNT(sTrumpCardPowerTable)) basePower = sTrumpCardPowerTable[ARRAY_COUNT(sTrumpCardPowerTable) - 1]; else - basePower = sTrumpCardPowerTable[i]; + basePower = sTrumpCardPowerTable[gBattleMons[battlerAtk].pp[i]]; } break; case EFFECT_ACROBATICS: @@ -7433,10 +7532,10 @@ static u16 CalcMoveBasePower(u16 move, u8 battlerAtk, u8 battlerDef) break; case EFFECT_HEAT_CRASH: weight = GetBattlerWeight(battlerAtk) / GetBattlerWeight(battlerDef); - if (weight >= ARRAY_COUNT(sHeatCrushPowerTable)) - basePower = sHeatCrushPowerTable[ARRAY_COUNT(sHeatCrushPowerTable) - 1]; + if (weight >= ARRAY_COUNT(sHeatCrashPowerTable)) + basePower = sHeatCrashPowerTable[ARRAY_COUNT(sHeatCrashPowerTable) - 1]; else - basePower = sHeatCrushPowerTable[i]; + basePower = sHeatCrashPowerTable[i]; break; case EFFECT_PUNISHMENT: basePower = 60 + (CountBattlerStatIncreases(battlerDef, FALSE) * 20); @@ -7495,6 +7594,15 @@ static u16 CalcMoveBasePower(u16 move, u8 battlerAtk, u8 battlerDef) break; } + // move-specific base power changes + switch (move) + { + case MOVE_WATER_SHURIKEN: + if (gBattleMons[battlerAtk].species == SPECIES_GRENINJA_ASH) + basePower = 20; + break; + } + if (basePower == 0) basePower = 1; return basePower; @@ -7758,7 +7866,7 @@ static u32 CalcMoveBasePowerAfterModifiers(u16 move, u8 battlerAtk, u8 battlerDe if (gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY) MulModifier(&modifier, UQ_4_12(2.0)); break; - case EFFECT_RETALITATE: + case EFFECT_RETALIATE: // todo break; case EFFECT_SOLARBEAM: @@ -8136,6 +8244,7 @@ static u32 CalcFinalDmg(u32 dmg, u16 move, u8 battlerAtk, u8 battlerDef, u8 move u32 abilityDef = GetBattlerAbility(battlerDef); u32 defSide = GET_BATTLER_SIDE(battlerDef); u16 finalModifier = UQ_4_12(1.0); + u16 itemDef = gBattleMons[battlerDef].item; // check multiple targets in double battle if (GetMoveTargetCount(move, battlerAtk, battlerDef) >= 2) @@ -8256,7 +8365,8 @@ static u32 CalcFinalDmg(u32 dmg, u16 move, u8 battlerAtk, u8 battlerDef, u8 move // berries reducing dmg case HOLD_EFFECT_RESIST_BERRY: if (moveType == GetBattlerHoldEffectParam(battlerDef) - && (moveType == TYPE_NORMAL || typeEffectivenessModifier >= UQ_4_12(2.0))) + && (moveType == TYPE_NORMAL || typeEffectivenessModifier >= UQ_4_12(2.0)) + && !UnnerveOn(battlerDef, itemDef)) { if (abilityDef == ABILITY_RIPEN) MulModifier(&finalModifier, UQ_4_12(0.25)); @@ -8657,6 +8767,9 @@ void UndoFormChange(u32 monId, u32 side, bool32 isSwitchingOut) {SPECIES_MINIOR_METEOR_VIOLET, SPECIES_MINIOR_CORE_VIOLET}, {SPECIES_MINIOR_METEOR_YELLOW, SPECIES_MINIOR_CORE_YELLOW}, {SPECIES_WISHIWASHI_SCHOOL, SPECIES_WISHIWASHI}, + {SPECIES_CRAMORANT_GORGING, SPECIES_CRAMORANT}, + {SPECIES_CRAMORANT_GULPING, SPECIES_CRAMORANT}, + {SPECIES_GRENINJA_ASH, SPECIES_GRENINJA_BATTLE_BOND}, }; if (isSwitchingOut) // Don't revert Mimikyu Busted when switching out @@ -9241,3 +9354,17 @@ void DoBurmyFormChange(u32 monId) } } } + +bool32 BlocksPrankster(u16 move, u8 battlerPrankster, u8 battlerDef) +{ + #if B_PRANKSTER_DARK_TYPES >= GEN_7 + if (gProtectStructs[battlerPrankster].pranksterElevated + && GetBattlerSide(battlerPrankster) != GetBattlerSide(battlerDef) + && !(gBattleMoves[gCurrentMove].target & (MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_DEPENDS)) // Don't block hazards, assist-type moves + && IS_BATTLER_OF_TYPE(battlerDef, TYPE_DARK) // Only Dark-types can block Prankster'd + && !(gStatuses3[battlerDef] & STATUS3_SEMI_INVULNERABLE)) + return TRUE; + else + #endif + return FALSE; +} diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index 097f9e07db..1aa8c4dfd6 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -2599,11 +2599,12 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = #if B_UPDATED_MOVE_DATA >= GEN_4 .accuracy = 0, .flags = FLAG_MAKES_CONTACT | FLAG_PROTECT_AFFECTED | FLAG_KINGS_ROCK_AFFECTED, + .effect = EFFECT_RECOIL_HP_25, #else .accuracy = 100, .flags = FLAG_MAKES_CONTACT | FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_KINGS_ROCK_AFFECTED, + .effect = EFFECT_RECOIL_25, #endif - .effect = EFFECT_RECOIL_25, .power = 50, .type = TYPE_NORMAL, .pp = 1, @@ -3424,6 +3425,11 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_HEAL_BELL] = { + #if B_UPDATED_MOVE_DATA != GEN_5 + .flags = FLAG_SNATCH_AFFECTED | FLAG_SOUND, + #else + .flags = FLAG_SNATCH_AFFECTED, + #endif .effect = EFFECT_HEAL_BELL, .power = 0, .type = TYPE_NORMAL, @@ -3432,7 +3438,6 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = .secondaryEffectChance = 0, .target = MOVE_TARGET_USER, .priority = 0, - .flags = FLAG_SNATCH_AFFECTED | FLAG_SOUND, .split = SPLIT_STATUS, }, @@ -5338,6 +5343,11 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_HOWL] = { + #if B_UPDATED_MOVE_DATA >= GEN_8 + .flags = FLAG_SNATCH_AFFECTED | FLAG_SOUND, + #else + .flags = FLAG_SNATCH_AFFECTED, + #endif .effect = EFFECT_ATTACK_UP, .power = 0, .type = TYPE_NORMAL, @@ -5346,7 +5356,6 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = .secondaryEffectChance = 0, .target = MOVE_TARGET_USER, .priority = 0, - .flags = FLAG_SNATCH_AFFECTED | FLAG_SOUND, .split = SPLIT_STATUS, }, @@ -8097,7 +8106,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_RETALIATE] = { - .effect = EFFECT_RETALITATE, + .effect = EFFECT_RETALIATE, .power = 70, .type = TYPE_NORMAL, .accuracy = 100, @@ -10226,7 +10235,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_PSYCHIC_FANGS] = { .effect = EFFECT_BRICK_BREAK, - .power = 75, + .power = 85, .type = TYPE_PSYCHIC, .accuracy = 100, .pp = 15,