diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index ddecbc0b2..8c11428b4 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1930,6 +1930,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 32f089102..d7de92096 100644 --- a/data/battle_anim_scripts.s +++ b/data/battle_anim_scripts.s @@ -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:: @@ -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 6b2a89afd..d4ba4bb60 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -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 .4byte BattleScript_EffectStuffCheeks @ EFFECT_STUFF_CHEEKS BattleScript_EffectStuffCheeks:: @@ -4940,6 +4941,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 @@ -6029,6 +6036,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 @@ -7674,6 +7751,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 diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 3db5e62d1..fd914b2e3 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -387,5 +387,8 @@ 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/constants/battle.h b/include/constants/battle.h index e88bb66dd..bf6403a18 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 c04bc14f7..39e1feda9 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 99dee5f58..10669e36b 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,6 +129,7 @@ #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. diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index cba86b32a..9a6efb847 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -363,8 +363,9 @@ #define EFFECT_DECORATE 357 #define EFFECT_SNIPE_SHOT 358 #define EFFECT_TRIPLE_HIT 359 -#define EFFECT_STUFF_CHEEKS 360 +#define EFFECT_RECOIL_HP_25 360 +#define EFFECT_STUFF_CHEEKS 361 -#define NUM_BATTLE_MOVE_EFFECTS 361 +#define NUM_BATTLE_MOVE_EFFECTS 362 #endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index 86cd9bd24..d2d68132c 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -578,9 +578,11 @@ #define STRINGID_ATKGOTOVERINFATUATION 574 #define STRINGID_TORMENTEDNOMORE 575 #define STRINGID_HEALBLOCKEDNOMORE 576 -#define STRINGID_STUFFCHEEKSCANTSELECT 577 +#define STRINGID_ATTACKERBECAMEFULLYCHARGED 577 +#define STRINGID_ATTACKERBECAMEASHSPECIES 578 +#define STRINGID_STUFFCHEEKSCANTSELECT 579 -#define BATTLESTRINGS_COUNT 578 +#define BATTLESTRINGS_COUNT 580 // 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 163c1aed6..6cb5dca7b 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; @@ -2468,7 +2471,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) { @@ -4747,7 +4753,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 958fb4720..d1a69bcde 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_main.c b/src/battle_main.c index 5c3f2ecd8..62662d1e4 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -3465,10 +3465,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) @@ -3682,7 +3685,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))) diff --git a/src/battle_message.c b/src/battle_message.c index 64856743b..5ed0d83ad 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -704,11 +704,15 @@ 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"); static const u8 sText_StuffCheeksCantSelect[] = _("Stuff Cheeks cannot be\nselected without a Berry!\p"); const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = { [STRINGID_STUFFCHEEKSCANTSELECT - 12] = sText_StuffCheeksCantSelect, + [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 7e0c1e1e6..74b2deb2c 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -3067,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; @@ -3177,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) { @@ -7291,7 +7299,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) @@ -7916,15 +7924,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: @@ -8145,7 +8153,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); } @@ -9148,7 +9157,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; @@ -10797,7 +10806,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); @@ -10813,7 +10822,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); @@ -10926,7 +10935,7 @@ 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++; @@ -11642,7 +11651,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 9c3242aca..abcb96dea 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -983,6 +983,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] = @@ -1263,7 +1268,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++) @@ -1295,7 +1300,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++) { @@ -1328,7 +1333,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++) { @@ -2740,8 +2745,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); @@ -3138,7 +3143,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; @@ -3148,7 +3153,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; @@ -3747,6 +3752,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; @@ -4999,6 +5006,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 @@ -5035,6 +5078,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 @@ -5357,11 +5421,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; @@ -7280,7 +7348,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[] = @@ -7452,7 +7520,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: @@ -7475,10 +7543,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); @@ -7537,6 +7605,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; @@ -8178,6 +8255,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) @@ -8298,7 +8376,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)); @@ -8699,6 +8778,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 diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index 5bb7d790d..f0312e7bd 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, }, @@ -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,