From f27dcab784b4c25ee1f9724502f21251e67a8783 Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Thu, 10 Jun 2021 12:55:05 +0200 Subject: [PATCH 1/2] Rage powder has powder moves qualities when forcing a target --- include/battle.h | 3 +- include/battle_util.h | 1 + src/battle_ai_util.c | 206 +++++++++++++++++------------------ src/battle_script_commands.c | 15 ++- src/battle_util.c | 86 ++++++++------- 5 files changed, 164 insertions(+), 147 deletions(-) diff --git a/include/battle.h b/include/battle.h index f009cbe7f..b51a3d71b 100644 --- a/include/battle.h +++ b/include/battle.h @@ -191,7 +191,8 @@ struct SideTimer u8 safeguardTimer; u8 safeguardBattlerId; u8 followmeTimer; - u8 followmeTarget; + u8 followmeTarget:3; + u8 followmePowder:1; // Rage powder, does not affect grass type pokemon. u8 spikesAmount; u8 toxicSpikesAmount; u8 stealthRockAmount; diff --git a/include/battle_util.h b/include/battle_util.h index f06a58938..e49931a07 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -46,6 +46,7 @@ struct TypePower extern const struct TypePower gNaturalGiftTable[]; +bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide); void HandleAction_UseMove(void); void HandleAction_Switch(void); void HandleAction_UseItem(void); diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index caabc7519..06d407e0f 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -283,7 +283,7 @@ static const s8 sAiAbilityRatings[ABILITIES_COUNT] = [ABILITY_GORILLA_TACTICS] = 4, }; -static const u16 sEncouragedEncoreEffects[] = +static const u16 sEncouragedEncoreEffects[] = { EFFECT_DREAM_EATER, EFFECT_ATTACK_UP, @@ -365,7 +365,7 @@ static const u16 sDiscouragedPowerfulMoveEffects[] = 0xFFFF }; -static const u16 sIgnoreMoldBreakerMoves[] = +static const u16 sIgnoreMoldBreakerMoves[] = { MOVE_MOONGEIST_BEAM, MOVE_SUNSTEEL_STRIKE, @@ -381,7 +381,7 @@ static const u16 sIgnoreMoldBreakerMoves[] = #endif }; -static const u16 sInstructBannedMoves[] = +static const u16 sInstructBannedMoves[] = { MOVE_INSTRUCT, MOVE_BIDE, @@ -410,7 +410,7 @@ static const u16 sInstructBannedMoves[] = MOVE_SOLAR_BLADE, }; -static const u16 sRechargeMoves[] = +static const u16 sRechargeMoves[] = { MOVE_HYPER_BEAM, MOVE_BLAST_BURN, @@ -424,7 +424,7 @@ static const u16 sRechargeMoves[] = MOVE_ETERNABEAM, }; -static const u16 sOtherMoveCallingMoves[] = +static const u16 sOtherMoveCallingMoves[] = { MOVE_ASSIST, MOVE_COPYCAT, @@ -640,7 +640,7 @@ bool32 IsAffectedByPowder(u8 battler, u16 ability, u16 holdEffect) { if ((B_POWDER_GRASS >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GRASS)) || ability == ABILITY_OVERCOAT - || GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_SAFETY_GOOGLES) + || holdEffect == HOLD_EFFECT_SAFETY_GOOGLES) return FALSE; return TRUE; } @@ -929,7 +929,7 @@ u8 AI_GetMoveEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef) gMoveResultFlags = 0; gCurrentMove = move; effectivenessMultiplier = AI_GetTypeEffectiveness(gCurrentMove, battlerAtk, battlerDef); - + switch (effectivenessMultiplier) { case UQ_4_12(0.0): @@ -1047,7 +1047,7 @@ bool32 CanTargetFaintAiWithMod(u8 battlerDef, u8 battlerAtk, s32 hpMod, s32 dmgM u32 hpCheck = gBattleMons[battlerAtk].hp + hpMod; if (dmgMod) dmg *= dmgMod; - + if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && !(unusable & gBitTable[i]) && dmg >= hpCheck) { return TRUE; @@ -1091,22 +1091,22 @@ s32 AI_GetAbility(u32 battlerId) u16 AI_GetHoldEffect(u32 battlerId) { u32 holdEffect; - + if (!IsBattlerAIControlled(battlerId)) holdEffect = BATTLE_HISTORY->itemEffects[battlerId]; else holdEffect = GetBattlerHoldEffect(battlerId, FALSE); - + if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_NEGATE_UNAWARE) return holdEffect; - + if (gStatuses3[battlerId] & STATUS3_EMBARGO) return HOLD_EFFECT_NONE; if (gFieldStatuses & STATUS_FIELD_MAGIC_ROOM) return HOLD_EFFECT_NONE; if (AI_GetAbility(battlerId) == ABILITY_KLUTZ && !(gStatuses3[battlerId] & STATUS3_GASTRO_ACID)) return HOLD_EFFECT_NONE; - + return holdEffect; } @@ -1114,7 +1114,7 @@ u16 AI_GetHoldEffect(u32 battlerId) bool32 AI_IsBattlerGrounded(u8 battlerId) { u32 holdEffect = AI_GetHoldEffect(battlerId); - + if (holdEffect == HOLD_EFFECT_IRON_BALL) return TRUE; else if (gFieldStatuses & STATUS_FIELD_GRAVITY) @@ -1140,10 +1140,10 @@ bool32 AI_IsBattlerGrounded(u8 battlerId) bool32 DoesBattlerIgnoreAbilityChecks(u16 atkAbility, u16 move) { u32 i; - + if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_NEGATE_UNAWARE) return FALSE; // AI handicap flag: doesn't understand ability suppression concept - + for (i = 0; i < ARRAY_COUNT(sIgnoreMoldBreakerMoves); i++) { if (move == sIgnoreMoldBreakerMoves[i]) @@ -1163,7 +1163,7 @@ bool32 AI_WeatherHasEffect(void) u32 i; if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_NEGATE_UNAWARE) return TRUE; // AI doesn't understand weather supression (handicap) - + // need to manually check since we don't necessarily know opponent ability for (i = 0; i < gBattlersCount; i++) { @@ -1177,7 +1177,7 @@ bool32 AI_WeatherHasEffect(void) bool32 IsAromaVeilProtectedMove(u16 move) { u32 i; - + switch (move) { case MOVE_DISABLE: @@ -1264,7 +1264,7 @@ bool32 IsMoveRedirectionPrevented(u16 move, u16 atkAbility) { if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_NEGATE_UNAWARE) return FALSE; - + if (move == MOVE_SKY_DROP || move == MOVE_SNIPE_SHOT || atkAbility == ABILITY_PROPELLER_TAIL @@ -1278,7 +1278,7 @@ u32 AI_GetMoveAccuracy(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbil { u32 calc, moveAcc, atkParam, defParam; s8 buff, accStage, evasionStage; - + gPotentialItemEffectBattler = battlerDef; accStage = gBattleMons[battlerAtk].statStages[STAT_ACC]; evasionStage = gBattleMons[battlerDef].statStages[STAT_EVASION]; @@ -1357,25 +1357,25 @@ bool32 IsMoveEncouragedToHit(u8 battlerAtk, u8 battlerDef, u16 move) { if (IsSemiInvulnerable(battlerDef, move)) return FALSE; - + //TODO - anticipate protect move? - + // always hits if (gStatuses3[battlerDef] & STATUS3_ALWAYS_HITS || gDisableStructs[battlerDef].battlerWithSureHit == battlerAtk) return TRUE; - + if (AI_GetAbility(battlerDef) == ABILITY_NO_GUARD || AI_GetAbility(battlerAtk) == ABILITY_NO_GUARD) return TRUE; - + if (B_TOXIC_NEVER_MISS >= GEN_6 && gBattleMoves[move].effect == EFFECT_TOXIC && IS_BATTLER_OF_TYPE(battlerAtk, TYPE_POISON)) return TRUE; - + // discouraged from hitting if (AI_WeatherHasEffect() && (gBattleWeather & WEATHER_SUN_ANY) && (gBattleMoves[move].effect == EFFECT_THUNDER || gBattleMoves[move].effect == EFFECT_HURRICANE)) return FALSE; - - // increased accuracy but don't always hit + + // increased accuracy but don't always hit if ((AI_WeatherHasEffect() && (((gBattleWeather & WEATHER_RAIN_ANY) && (gBattleMoves[move].effect == EFFECT_THUNDER || gBattleMoves[move].effect == EFFECT_HURRICANE)) || (((gBattleWeather & WEATHER_HAIL_ANY) && move == MOVE_BLIZZARD)))) @@ -1385,23 +1385,23 @@ bool32 IsMoveEncouragedToHit(u8 battlerAtk, u8 battlerDef, u16 move) { return TRUE; } - + return FALSE; } bool32 ShouldTryOHKO(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u32 accuracy, u16 move) { u32 holdEffect = AI_GetHoldEffect(battlerDef); - + gPotentialItemEffectBattler = battlerDef; if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < GetBattlerHoldEffectParam(battlerDef)) return FALSE; //probabilistically speaking, focus band should activate so dont OHKO else if (holdEffect == HOLD_EFFECT_FOCUS_SASH && AtMaxHp(battlerDef)) return FALSE; - + if (!DoesBattlerIgnoreAbilityChecks(atkAbility, move) && defAbility == ABILITY_STURDY) return FALSE; - + if ((((gStatuses3[battlerDef] & STATUS3_ALWAYS_HITS) && gDisableStructs[battlerDef].battlerWithSureHit == battlerAtk) || atkAbility == ABILITY_NO_GUARD || defAbility == ABILITY_NO_GUARD) @@ -1424,7 +1424,7 @@ bool32 ShouldSetSandstorm(u8 battler, u16 ability, u16 holdEffect) return FALSE; else if (gBattleWeather & WEATHER_SANDSTORM_ANY) return FALSE; - + if (ability == ABILITY_SAND_VEIL || ability == ABILITY_SAND_RUSH || ability == ABILITY_SAND_FORCE @@ -1449,7 +1449,7 @@ bool32 ShouldSetHail(u8 battler, u16 ability, u16 holdEffect) return FALSE; else if (gBattleWeather & WEATHER_HAIL_ANY) return FALSE; - + if (ability == ABILITY_SNOW_CLOAK || ability == ABILITY_ICE_BODY || ability == ABILITY_FORECAST @@ -1463,7 +1463,7 @@ bool32 ShouldSetHail(u8 battler, u16 ability, u16 holdEffect) || HasMoveEffect(battler, EFFECT_WEATHER_BALL)) { return TRUE; - } + } return FALSE; } @@ -1473,7 +1473,7 @@ bool32 ShouldSetRain(u8 battlerAtk, u16 atkAbility, u16 holdEffect) return FALSE; else if (gBattleWeather & WEATHER_RAIN_ANY) return FALSE; - + if (holdEffect != HOLD_EFFECT_UTILITY_UMBRELLA && (atkAbility == ABILITY_SWIFT_SWIM || atkAbility == ABILITY_FORECAST @@ -1496,7 +1496,7 @@ bool32 ShouldSetSun(u8 battlerAtk, u16 atkAbility, u16 holdEffect) return FALSE; else if (gBattleWeather & WEATHER_SUN_ANY) return FALSE; - + if (holdEffect != HOLD_EFFECT_UTILITY_UMBRELLA && (atkAbility == ABILITY_CHLOROPHYLL || atkAbility == ABILITY_FLOWER_GIFT @@ -1524,13 +1524,13 @@ void ProtectChecks(u8 battlerAtk, u8 battlerDef, u16 move, u16 predictedMove, s1 u16 predictedEffect = gBattleMoves[predictedMove].effect; u8 defAbility = AI_GetAbility(battlerDef); u32 uses = gDisableStructs[battlerAtk].protectUses; - + /*if (GetMoveResultFlags(predictedMove) & (MOVE_RESULT_NO_EFFECT | MOVE_RESULT_MISSED)) { (*score) -= 5; return; }*/ - + if (uses == 0) { if (predictedMove != MOVE_NONE && predictedMove != 0xFFFF && !IS_MOVE_STATUS(predictedMove)) @@ -1552,7 +1552,7 @@ void ProtectChecks(u8 battlerAtk, u8 battlerDef, u16 move, u16 predictedMove, s1 { (*score)--; } - + if (gBattleMons[battlerDef].status1 & STATUS1_TOXIC_POISON || gBattleMons[battlerDef].status2 & (STATUS2_CURSED | STATUS2_INFATUATION) || gStatuses3[battlerDef] & (STATUS3_PERISH_SONG | STATUS3_LEECHSEED | STATUS3_YAWN)) @@ -1569,10 +1569,10 @@ bool32 ShouldLowerStat(u8 battler, u16 battlerAbility, u8 stat) || battlerAbility == ABILITY_WHITE_SMOKE || battlerAbility == ABILITY_FULL_METAL_BODY) return FALSE; - + return TRUE; } - + return FALSE; } @@ -1586,7 +1586,7 @@ bool32 BattlerStatCanRise(u8 battler, u16 battlerAbility, u8 stat) bool32 AreBattlersStatsMaxed(u8 battlerId) { - u32 i; + u32 i; for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) { if (gBattleMons[battlerId].statStages[i] < MAX_STAT_STAGE) @@ -1598,7 +1598,7 @@ bool32 AreBattlersStatsMaxed(u8 battlerId) bool32 AnyStatIsRaised(u8 battlerId) { u32 i; - + for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) { if (gBattleMons[battlerId].statStages[i] > DEFAULT_STAT_STAGE) @@ -1738,10 +1738,10 @@ bool32 ShouldLowerEvasion(u8 battlerAtk, u8 battlerDef, u16 defAbility) bool32 CanAttackerFaintTarget(u8 battlerAtk, u8 battlerDef, u8 index, u8 numHits) { s32 dmg = AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][index]; - + if (numHits) dmg *= numHits; - + if (gBattleMons[battlerDef].hp <= dmg) return TRUE; return FALSE; @@ -1767,7 +1767,7 @@ bool32 HasOnlyMovesWithSplit(u32 battlerId, u32 split, bool32 onlyOffensive) if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && GetBattleMoveSplit(moves[i]) != split) return FALSE; } - + return TRUE; } @@ -1832,12 +1832,12 @@ bool32 HasMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef, u8 accCheck, bool32 s32 i; u16 *moves = GetMovesArray(battlerAtk); u8 moveLimitations = CheckMoveLimitations(battlerAtk, 0, 0xFF); - + for (i = 0; i < MAX_MON_MOVES; i++) { if (moves[i] == MOVE_NONE || moves[i] == 0xFFFF) continue; - + if (!(gBitTable[i] & moveLimitations)) { if (ignoreStatus && IS_MOVE_STATUS(moves[i])) @@ -1845,12 +1845,12 @@ bool32 HasMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef, u8 accCheck, bool32 else if ((!IS_MOVE_STATUS(moves[i]) && gBattleMoves[moves[i]].accuracy == 0) || gBattleMoves[moves[i]].target & (MOVE_TARGET_USER | MOVE_TARGET_OPPONENTS_FIELD)) continue; - + if (AI_GetMoveAccuracy(battlerAtk, battlerDef, atkAbility, defAbility, atkHoldEffect, defHoldEffect, moves[i]) <= accCheck) return TRUE; } } - + return FALSE; } @@ -1859,7 +1859,7 @@ bool32 HasSleepMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef) u8 moveLimitations = CheckMoveLimitations(battlerAtk, 0, 0xFF); u32 i; u16 *moves = GetMovesArray(battlerAtk); - + for (i = 0; i < MAX_MON_MOVES; i++) { if (moves[i] == MOVE_NONE) @@ -2058,7 +2058,7 @@ bool32 HasDamagingMove(u8 battlerId) { u32 i; u16 *moves = GetMovesArray(battlerId); - + for (i = 0; i < MAX_MON_MOVES; i++) { if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && gBattleMoves[moves[i]].power != 0) @@ -2097,7 +2097,7 @@ bool32 IsInstructBannedMove(u16 move) bool32 IsEncoreEncouragedEffect(u16 moveEffect) { u32 i; - + for (i = 0; i < ARRAY_COUNT(sEncouragedEncoreEffects); i++) { if (moveEffect == sEncouragedEncoreEffects[i]) @@ -2199,10 +2199,10 @@ static u32 GetTrapDamage(u8 battlerId) static u32 GetPoisonDamage(u8 battlerId) { u32 damage = 0; - + if (AI_GetAbility(battlerId) == ABILITY_POISON_HEAL) return damage; - + if (gBattleMons[battlerId].status1 & STATUS1_POISON) { damage = gBattleMons[battlerId].maxHP / 8; @@ -2251,7 +2251,7 @@ static u32 GetWeatherDamage(u8 battlerId) u32 damage = 0; if (!AI_WeatherHasEffect()) return 0; - + if (gBattleWeather & WEATHER_SANDSTORM_ANY) { if (BattlerAffectedBySandstorm(battlerId, ability) @@ -2280,17 +2280,17 @@ static u32 GetWeatherDamage(u8 battlerId) u32 GetBattlerSecondaryDamage(u8 battlerId) { u32 secondaryDamage; - + if (AI_GetAbility(battlerId) == ABILITY_MAGIC_GUARD) return FALSE; - + secondaryDamage = GetLeechSeedDamage(battlerId) + GetNightmareDamage(battlerId) + GetCurseDamage(battlerId) + GetTrapDamage(battlerId) + GetPoisonDamage(battlerId) + GetWeatherDamage(battlerId); - + return secondaryDamage; } @@ -2314,7 +2314,7 @@ bool32 BattlerWillFaintFromSecondaryDamage(u8 battler, u16 ability) static bool32 AnyUsefulStatIsRaised(u8 battler) { u8 statId; - + for (statId = STAT_ATK; statId < NUM_BATTLE_STATS; statId++) { if (gBattleMons[battler].statStages[statId] > DEFAULT_STAT_STAGE) @@ -2344,17 +2344,17 @@ static bool32 PartyBattlerShouldAvoidHazards(u8 currBattler, u8 switchBattler) u16 ability = GetMonAbility(mon); // we know our own party data u16 holdEffect = GetBattlerHoldEffect(GetMonData(mon, MON_DATA_HELD_ITEM), TRUE); u32 flags = gSideStatuses[GetBattlerSide(currBattler)] & (SIDE_STATUS_SPIKES | SIDE_STATUS_STEALTH_ROCK | SIDE_STATUS_STICKY_WEB | SIDE_STATUS_TOXIC_SPIKES); - + if (flags == 0) return FALSE; - + if (ability == ABILITY_MAGIC_GUARD || ability == ABILITY_LEVITATE || holdEffect == HOLD_EFFECT_HEAVY_DUTY_BOOTS) return FALSE; - + if (flags & (SIDE_STATUS_SPIKES | SIDE_STATUS_STEALTH_ROCK) && GetMonData(mon, MON_DATA_HP) < (GetMonData(mon, MON_DATA_MAX_HP) / 8)) return TRUE; - + return FALSE; } @@ -2369,9 +2369,9 @@ bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 mo u8 backupBattler = gActiveBattler; bool32 shouldSwitch; u8 battlerToSwitch; - + gActiveBattler = battlerAtk; - shouldSwitch = ShouldSwitch(); + shouldSwitch = ShouldSwitch(); battlerToSwitch = *(gBattleStruct->AI_monToSwitchIntoId + gActiveBattler); gActiveBattler = backupBattler; @@ -2549,7 +2549,7 @@ bool32 CanKnockOffItem(u8 battler, u16 item) #endif )) && GetBattlerSide(battler) == B_SIDE_PLAYER) return FALSE; - + if (AI_GetAbility(battler) == ABILITY_STICKY_HOLD) return FALSE; @@ -2564,7 +2564,7 @@ bool32 IsBattlerIncapacitated(u8 battler, u16 ability) { if ((gBattleMons[battler].status1 & STATUS1_FREEZE) && !HasThawingMove(battler)) return TRUE; // if battler has thawing move we assume they will definitely use it, and thus being frozen should be neglected - + if (gBattleMons[battler].status1 & STATUS1_SLEEP) return TRUE; @@ -2677,7 +2677,7 @@ bool32 AI_CanConfuse(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtk { return FALSE; } - + return TRUE; } @@ -2758,7 +2758,7 @@ bool32 ShouldTrap(u8 battlerAtk, u8 battlerDef, u16 move) { if (BattlerWillFaintFromSecondaryDamage(battlerDef, AI_DATA->defAbility)) return TRUE; // battler is taking secondary damage with low HP - + if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_STALL) { if (!CanTargetFaintAi(battlerDef, battlerAtk)) @@ -2772,12 +2772,12 @@ bool32 ShouldFakeOut(u8 battlerAtk, u8 battlerDef, u16 move) { if (AI_DATA->atkHoldEffect == HOLD_EFFECT_CHOICE_BAND && CountUsablePartyMons(battlerAtk) == 0) return FALSE; // don't lock attacker into fake out if can't switch out - + if (gDisableStructs[battlerAtk].isFirstTurn && ShouldTryToFlinch(battlerAtk, battlerDef, AI_DATA->atkAbility, AI_DATA->defAbility, move) && !DoesSubstituteBlockMove(battlerAtk, battlerDef, move)) return TRUE; - + return FALSE; } @@ -2805,12 +2805,12 @@ bool32 AnyPartyMemberStatused(u8 battlerId, bool32 checkSoundproof) { struct Pokemon *party; u32 i; - + if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) party = gPlayerParty; else party = gEnemyParty; - + for (i = 0; i < PARTY_SIZE; i++) { if (checkSoundproof && GetMonAbility(&party[i]) == ABILITY_SOUNDPROOF) @@ -2854,21 +2854,21 @@ bool32 ShouldUseRecoilMove(u8 battlerAtk, u8 battlerDef, u32 recoilDmg, u8 moveI else return FALSE; //Not as good to use move if you'll faint and not win } - + return TRUE; } bool32 ShouldAbsorb(u8 battlerAtk, u8 battlerDef, u16 move, s32 damage) -{ +{ if (move == 0xFFFF || GetWhoStrikesFirst(battlerAtk, gBattlerTarget, TRUE) == 0) { // using item or user goes first u8 healPercent = (gBattleMoves[move].argument == 0) ? 50 : gBattleMoves[move].argument; s32 healDmg = (healPercent * damage) / 100; - + if (gStatuses3[battlerAtk] & STATUS3_HEAL_BLOCK) healDmg = 0; - + if (CanTargetFaintAi(battlerDef, battlerAtk) && !CanTargetFaintAiWithMod(battlerDef, battlerAtk, healDmg, 0)) return TRUE; // target can faint attacker unless they heal @@ -2881,7 +2881,7 @@ bool32 ShouldAbsorb(u8 battlerAtk, u8 battlerDef, u16 move, s32 damage) if (!CanTargetFaintAi(battlerDef, battlerAtk)) return TRUE; } - + return FALSE; } @@ -2944,7 +2944,7 @@ bool32 IsValidDoubleBattle(u8 battlerAtk) u16 GetAllyChosenMove(void) { u8 partnerBattler = BATTLE_PARTNER(sBattler_AI); - + if (!IsBattlerAlive(partnerBattler) || !IsBattlerAIControlled(partnerBattler)) return MOVE_NONE; // TODO: prediction? else if (partnerBattler > sBattler_AI) // Battler with the lower id chooses the move first. @@ -2957,7 +2957,7 @@ bool32 IsTargetingPartner(u8 battlerAtk, u8 battlerDef) { if ((battlerAtk & BIT_SIDE) == (battlerDef & BIT_SIDE)) return TRUE; - + return FALSE; } @@ -2966,7 +2966,7 @@ bool32 DoesPartnerHaveSameMoveEffect(u8 battlerAtkPartner, u8 battlerDef, u16 mo { if (!IsDoubleBattle()) return FALSE; - + if (gBattleMoves[move].effect == gBattleMoves[partnerMove].effect && gChosenMoveByBattler[battlerAtkPartner] != MOVE_NONE && gBattleStruct->moveTarget[battlerAtkPartner] == battlerDef) @@ -2981,7 +2981,7 @@ bool32 PartnerHasSameMoveEffectWithoutTarget(u8 battlerAtkPartner, u16 move, u16 { if (!IsDoubleBattle()) return FALSE; - + if (gBattleMoves[move].effect == gBattleMoves[partnerMove].effect && gChosenMoveByBattler[battlerAtkPartner] != MOVE_NONE) return TRUE; @@ -2993,7 +2993,7 @@ bool32 PartnerMoveEffectIsStatusSameTarget(u8 battlerAtkPartner, u8 battlerDef, { if (!IsDoubleBattle()) return FALSE; - + if (gChosenMoveByBattler[battlerAtkPartner] != MOVE_NONE && gBattleStruct->moveTarget[battlerAtkPartner] == battlerDef && (gBattleMoves[partnerMove].effect == EFFECT_SLEEP @@ -3011,14 +3011,14 @@ bool32 PartnerMoveEffectIsWeather(u8 battlerAtkPartner, u16 partnerMove) { if (!IsDoubleBattle()) return FALSE; - + if (gChosenMoveByBattler[battlerAtkPartner] != MOVE_NONE && (gBattleMoves[partnerMove].effect == EFFECT_SUNNY_DAY || gBattleMoves[partnerMove].effect == EFFECT_RAIN_DANCE || gBattleMoves[partnerMove].effect == EFFECT_SANDSTORM || gBattleMoves[partnerMove].effect == EFFECT_HAIL)) return TRUE; - + return FALSE; } @@ -3027,14 +3027,14 @@ bool32 PartnerMoveEffectIsTerrain(u8 battlerAtkPartner, u16 partnerMove) { if (!IsDoubleBattle()) return FALSE; - + if (gChosenMoveByBattler[battlerAtkPartner] != MOVE_NONE && (gBattleMoves[partnerMove].effect == EFFECT_GRASSY_TERRAIN || gBattleMoves[partnerMove].effect == EFFECT_MISTY_TERRAIN || gBattleMoves[partnerMove].effect == EFFECT_ELECTRIC_TERRAIN || gBattleMoves[partnerMove].effect == EFFECT_PSYCHIC_TERRAIN)) return TRUE; - + return FALSE; } @@ -3043,7 +3043,7 @@ bool32 PartnerMoveIs(u8 battlerAtkPartner, u16 partnerMove, u16 moveCheck) { if (!IsDoubleBattle()) return FALSE; - + if (gChosenMoveByBattler[battlerAtkPartner] != MOVE_NONE && partnerMove == moveCheck) return TRUE; return FALSE; @@ -3054,7 +3054,7 @@ bool32 PartnerMoveIsSameAsAttacker(u8 battlerAtkPartner, u8 battlerDef, u16 move { if (!IsDoubleBattle()) return FALSE; - + if (gChosenMoveByBattler[battlerAtkPartner] != MOVE_NONE && move == partnerMove && gBattleStruct->moveTarget[battlerAtkPartner] == battlerDef) return TRUE; return FALSE; @@ -3079,7 +3079,7 @@ bool32 ShouldUseWishAromatherapy(u8 battlerAtk, u8 battlerDef, u16 move) bool32 needHealing = FALSE; GetAIPartyIndexes(battlerAtk, &firstId, &lastId); - + if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER) party = gPlayerParty; else @@ -3199,12 +3199,12 @@ bool32 IsPartyFullyHealedExceptBattler(u8 battlerId) { struct Pokemon *party; u32 i; - + if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) party = gPlayerParty; else party = gEnemyParty; - + for (i = 0; i < PARTY_SIZE; i++) { if (i != gBattlerPartyIndexes[battlerId] @@ -3227,7 +3227,7 @@ bool32 PartyHasMoveSplit(u8 battlerId, u8 split) { if (GetMonData(&party[i], MON_DATA_HP, NULL) == 0) continue; - + for (j = 0; j < MAX_MON_MOVES; j++) { u16 move = GetMonData(&party[i], MON_DATA_MOVE1 + j, NULL); @@ -3272,7 +3272,7 @@ s8 GetAbilityRating(u16 ability) return sAiAbilityRatings[ability]; } -static const u16 sRecycleEncouragedItems[] = +static const u16 sRecycleEncouragedItems[] = { ITEM_CHESTO_BERRY, ITEM_LUM_BERRY, @@ -3300,15 +3300,15 @@ bool32 IsRecycleEncouragedItem(u16 item) // score increases #define STAT_UP_2_STAGE 8 -#define STAT_UP_STAGE 10 +#define STAT_UP_STAGE 10 void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score) { if (AI_DATA->atkAbility == ABILITY_CONTRARY) return; - + if (GetHealthPercentage(battlerAtk) < 80 && AI_RandLessThan(128)) return; - + switch (statId) { case STAT_ATK: @@ -3384,10 +3384,10 @@ void IncreasePoisonScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) { if (!HasDamagingMove(battlerDef)) *score += 2; - + if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_STALL && HasMoveEffect(battlerAtk, EFFECT_PROTECT)) (*score)++; // stall tactic - + if (HasMoveEffect(battlerAtk, EFFECT_VENOSHOCK) || HasMoveEffect(battlerAtk, EFFECT_HEX) || HasMoveEffect(battlerAtk, EFFECT_VENOM_DRENCH) @@ -3408,7 +3408,7 @@ void IncreaseBurnScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) if (CanTargetFaintAi(battlerDef, battlerAtk)) *score += 2; // burning the target to stay alive is cool } - + if (HasMoveEffect(battlerAtk, EFFECT_HEX) || HasMoveEffect(AI_DATA->battlerAtkPartner, EFFECT_HEX)) (*score)++; } @@ -3420,7 +3420,7 @@ void IncreaseParalyzeScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) { u8 atkSpeed = GetBattlerTotalSpeedStat(battlerAtk); u8 defSpeed = GetBattlerTotalSpeedStat(battlerDef); - + if ((defSpeed >= atkSpeed && defSpeed / 2 < atkSpeed) // You'll go first after paralyzing foe || HasMoveEffect(battlerAtk, EFFECT_HEX) || HasMoveEffect(battlerAtk, EFFECT_FLINCH_HIT) @@ -3438,11 +3438,11 @@ void IncreaseSleepScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) *score += 2; else return; - + if ((HasMoveEffect(battlerAtk, EFFECT_DREAM_EATER) || HasMoveEffect(battlerAtk, EFFECT_NIGHTMARE)) && !(HasMoveEffect(battlerDef, EFFECT_SNORE) || HasMoveEffect(battlerDef, EFFECT_SLEEP_TALK))) (*score)++; - + if (HasMoveEffect(battlerAtk, EFFECT_HEX) || HasMoveEffect(AI_DATA->battlerAtkPartner, EFFECT_HEX)) (*score)++; } diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index c8a393da3..77ef7419c 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -7408,7 +7408,7 @@ static void Cmd_various(void) case VARIOUS_SET_MAGIC_COAT_TARGET: gBattlerAttacker = gBattlerTarget; side = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE; - if (gSideTimers[side].followmeTimer != 0 && gBattleMons[gSideTimers[side].followmeTarget].hp != 0) + if (IsAffectedByFollowMe(gBattlerAttacker, side)) gBattlerTarget = gSideTimers[side].followmeTarget; else gBattlerTarget = gActiveBattler; @@ -9980,7 +9980,7 @@ static void Cmd_counterdamagecalculator(void) { gBattleMoveDamage = gProtectStructs[gBattlerAttacker].physicalDmg * 2; - if (gSideTimers[sideTarget].followmeTimer && gBattleMons[gSideTimers[sideTarget].followmeTarget].hp) + if (IsAffectedByFollowMe(gBattlerAttacker, sideTarget)) gBattlerTarget = gSideTimers[sideTarget].followmeTarget; else gBattlerTarget = gProtectStructs[gBattlerAttacker].physicalBattlerId; @@ -9999,11 +9999,13 @@ static void Cmd_mirrorcoatdamagecalculator(void) // a copy of atkA1 with the phy u8 sideAttacker = GetBattlerSide(gBattlerAttacker); u8 sideTarget = GetBattlerSide(gProtectStructs[gBattlerAttacker].specialBattlerId); - if (gProtectStructs[gBattlerAttacker].specialDmg && sideAttacker != sideTarget && gBattleMons[gProtectStructs[gBattlerAttacker].specialBattlerId].hp) + if (gProtectStructs[gBattlerAttacker].specialDmg + && sideAttacker != sideTarget + && gBattleMons[gProtectStructs[gBattlerAttacker].specialBattlerId].hp) { gBattleMoveDamage = gProtectStructs[gBattlerAttacker].specialDmg * 2; - if (gSideTimers[sideTarget].followmeTimer && gBattleMons[gSideTimers[sideTarget].followmeTarget].hp) + if (IsAffectedByFollowMe(gBattlerAttacker, sideTarget)) gBattlerTarget = gSideTimers[sideTarget].followmeTarget; else gBattlerTarget = gProtectStructs[gBattlerAttacker].specialBattlerId; @@ -11084,6 +11086,7 @@ static void Cmd_setforcedtarget(void) // follow me { gSideTimers[GetBattlerSide(gBattlerAttacker)].followmeTimer = 1; gSideTimers[GetBattlerSide(gBattlerAttacker)].followmeTarget = gBattlerAttacker; + gSideTimers[GetBattlerSide(gBattlerAttacker)].followmePowder = TestMoveFlags(gCurrentMove, FLAG_POWDER); gBattlescriptCurrInstr++; } @@ -12554,7 +12557,7 @@ static void Cmd_metalburstdamagecalculator(void) { gBattleMoveDamage = gProtectStructs[gBattlerAttacker].physicalDmg * 150 / 100; - if (gSideTimers[sideTarget].followmeTimer && gBattleMons[gSideTimers[sideTarget].followmeTarget].hp) + if (IsAffectedByFollowMe(gBattlerAttacker, sideTarget)) gBattlerTarget = gSideTimers[sideTarget].followmeTarget; else gBattlerTarget = gProtectStructs[gBattlerAttacker].physicalBattlerId; @@ -12567,7 +12570,7 @@ static void Cmd_metalburstdamagecalculator(void) { gBattleMoveDamage = gProtectStructs[gBattlerAttacker].specialDmg * 150 / 100; - if (gSideTimers[sideTarget].followmeTimer && gBattleMons[gSideTimers[sideTarget].followmeTarget].hp) + if (IsAffectedByFollowMe(gBattlerAttacker, sideTarget)) gBattlerTarget = gSideTimers[sideTarget].followmeTarget; else gBattlerTarget = gProtectStructs[gBattlerAttacker].specialBattlerId; diff --git a/src/battle_util.c b/src/battle_util.c index a5867a8d9..11abbdde4 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -90,7 +90,7 @@ static const u8 sPkblToEscapeFactor[][3] = { static const u8 sGoNearCounterToCatchFactor[] = {4, 3, 2, 1}; static const u8 sGoNearCounterToEscapeFactor[] = {4, 4, 4, 4}; -static const u16 sSkillSwapBannedAbilities[] = +static const u16 sSkillSwapBannedAbilities[] = { ABILITY_WONDER_GUARD, ABILITY_MULTITYPE, @@ -109,9 +109,9 @@ static const u16 sSkillSwapBannedAbilities[] = ABILITY_GULP_MISSILE, }; -static const u16 sRolePlayBannedAbilities[] = +static const u16 sRolePlayBannedAbilities[] = { - ABILITY_TRACE, + ABILITY_TRACE, ABILITY_WONDER_GUARD, ABILITY_FORECAST, ABILITY_FLOWER_GIFT, @@ -134,7 +134,7 @@ static const u16 sRolePlayBannedAbilities[] = ABILITY_GULP_MISSILE, }; -static const u16 sRolePlayBannedAttackerAbilities[] = +static const u16 sRolePlayBannedAttackerAbilities[] = { ABILITY_MULTITYPE, ABILITY_ZEN_MODE, @@ -150,7 +150,7 @@ static const u16 sRolePlayBannedAttackerAbilities[] = ABILITY_GULP_MISSILE, }; -static const u16 sWorrySeedBannedAbilities[] = +static const u16 sWorrySeedBannedAbilities[] = { ABILITY_MULTITYPE, ABILITY_STANCE_CHANGE, @@ -166,7 +166,7 @@ static const u16 sWorrySeedBannedAbilities[] = ABILITY_GULP_MISSILE, }; -static const u16 sGastroAcidBannedAbilities[] = +static const u16 sGastroAcidBannedAbilities[] = { ABILITY_AS_ONE_ICE_RIDER, ABILITY_AS_ONE_SHADOW_RIDER, @@ -184,7 +184,7 @@ static const u16 sGastroAcidBannedAbilities[] = ABILITY_ZEN_MODE, }; -static const u16 sEntrainmentBannedAttackerAbilities[] = +static const u16 sEntrainmentBannedAttackerAbilities[] = { ABILITY_TRACE, ABILITY_FORECAST, @@ -202,7 +202,7 @@ static const u16 sEntrainmentBannedAttackerAbilities[] = ABILITY_GULP_MISSILE, }; -static const u16 sEntrainmentTargetSimpleBeamBannedAbilities[] = +static const u16 sEntrainmentTargetSimpleBeamBannedAbilities[] = { ABILITY_TRUANT, ABILITY_MULTITYPE, @@ -217,6 +217,21 @@ static const u16 sEntrainmentTargetSimpleBeamBannedAbilities[] = ABILITY_GULP_MISSILE, }; +bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide) +{ + u32 ability = GetBattlerAbility(battlerAtk); + + if (gSideTimers[defSide].followmeTimer == 0 + || gBattleMons[gSideTimers[defSide].followmeTarget].hp == 0 + || ability == ABILITY_PROPELLER_TAIL || ability == ABILITY_STALWART) + return FALSE; + + if (gSideTimers[defSide].followmePowder && !IsAffectedByPowder(battlerAtk, ability, GetBattlerHoldEffect(battlerAtk, TRUE))) + return FALSE; + + return TRUE; +} + // Functions void HandleAction_UseMove(void) { @@ -292,12 +307,9 @@ void HandleAction_UseMove(void) // choose target side = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE; - if (gSideTimers[side].followmeTimer != 0 + if (IsAffectedByFollowMe(gBattlerAttacker, side) && gBattleMoves[gCurrentMove].target == MOVE_TARGET_SELECTED - && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gSideTimers[side].followmeTarget) - && gBattleMons[gSideTimers[side].followmeTarget].hp != 0 - && (GetBattlerAbility(gBattlerAttacker) != ABILITY_PROPELLER_TAIL - || GetBattlerAbility(gBattlerAttacker) != ABILITY_STALWART)) + && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gSideTimers[side].followmeTarget)) { gBattlerTarget = gSideTimers[side].followmeTarget; } @@ -1542,7 +1554,7 @@ bool32 IsHealBlockPreventingMove(u32 battler, u32 move) { if (!(gStatuses3[battler] & STATUS3_HEAL_BLOCK)) return FALSE; - + switch (gBattleMoves[move].effect) { case EFFECT_ABSORB: @@ -3862,7 +3874,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move gBattleCommunication[MULTISTRING_CHOOSER] = 3; break; } - + BattleScriptPushCursorAndCallback(BattleScript_OverworldTerrain); effect++; } @@ -5429,13 +5441,13 @@ static u8 HealConfuseBerry(u32 battlerId, u32 itemId, u8 flavorId, bool32 end2) if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; gBattleMoveDamage *= -1; - + if (GetBattlerAbility(battlerId) == ABILITY_RIPEN) { gBattleMoveDamage *= 2; gBattlerAbility = battlerId; } - + if (end2) { if (GetFlavorRelationByPersonality(gBattleMons[battlerId].personality, flavorId) < 0) @@ -5469,10 +5481,10 @@ static u8 StatRaiseBerry(u32 battlerId, u32 itemId, u32 statId, bool32 end2) SET_STATCHANGER(statId, 2, FALSE); else SET_STATCHANGER(statId, 1, FALSE); - + gBattleScripting.animArg1 = 14 + statId; gBattleScripting.animArg2 = 0; - + if (end2) { BattleScriptExecute(BattleScript_BerryStatRaiseEnd2); @@ -5515,15 +5527,15 @@ static u8 RandomStatRaiseBerry(u32 battlerId, u32 itemId, bool32 end2) gBattleTextBuff2[7] = EOS; gEffectBattler = battlerId; - + if (GetBattlerAbility(battlerId) == ABILITY_RIPEN) SET_STATCHANGER(i + 1, 4, FALSE); else SET_STATCHANGER(i + 1, 2, FALSE); - + gBattleScripting.animArg1 = 0x21 + i + 6; gBattleScripting.animArg2 = 0; - + if (end2) { BattleScriptExecute(BattleScript_BerryStatRaiseEnd2); @@ -5543,7 +5555,7 @@ static u8 TrySetMicleBerry(u32 battlerId, u32 itemId, bool32 end2) if (HasEnoughHpToEatBerry(battlerId, 4, itemId)) { gProtectStructs[battlerId].micle = TRUE; // battler's next attack has increased accuracy - + if (end2) { BattleScriptExecute(BattleScript_MicleBerryActivateEnd2); @@ -5566,7 +5578,7 @@ static u8 DamagedStatBoostBerryEffect(u8 battlerId, u8 statId, u8 split) && !DoesSubstituteBlockMove(gBattlerAttacker, battlerId, gCurrentMove) && GetBattleMoveSplit(gCurrentMove) == split) { - + PREPARE_STAT_BUFFER(gBattleTextBuff1, statId); PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_STATROSE); @@ -5575,7 +5587,7 @@ static u8 DamagedStatBoostBerryEffect(u8 battlerId, u8 statId, u8 split) SET_STATCHANGER(statId, 2, FALSE); else SET_STATCHANGER(statId, 1, FALSE); - + gBattleScripting.animArg1 = 14 + statId; gBattleScripting.animArg2 = 0; BattleScriptPushCursor(); @@ -5593,11 +5605,11 @@ static u8 ItemHealHp(u32 battlerId, u32 itemId, bool32 end2, bool32 percentHeal) gBattleMoveDamage = (gBattleMons[battlerId].maxHP * GetBattlerHoldEffectParam(battlerId) / 100) * -1; else gBattleMoveDamage = GetBattlerHoldEffectParam(battlerId) * -1; - + // check ripen if (ItemId_GetPocket(itemId) == POCKET_BERRIES && GetBattlerAbility(battlerId) == ABILITY_RIPEN) gBattleMoveDamage *= 2; - + gBattlerAbility = battlerId; // in SWSH, berry juice shows ability pop up but has no effect. This is mimicked here if (end2) { @@ -5869,7 +5881,7 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn) { u8 maxPP = CalculatePPWithBonus(move, ppBonuses, i); u8 ppRestored = GetBattlerHoldEffectParam(battlerId); - + if (GetBattlerAbility(battlerId) == ABILITY_RIPEN) { ppRestored *= 2; @@ -6447,7 +6459,7 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn) gBattleMoveDamage = 1; if (GetBattlerAbility(battlerId) == ABILITY_RIPEN) gBattleMoveDamage *= 2; - + effect = ITEM_HP_CHANGE; BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_JabocaRowapBerryActivates; @@ -6467,7 +6479,7 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn) gBattleMoveDamage = 1; if (GetBattlerAbility(battlerId) == ABILITY_RIPEN) gBattleMoveDamage *= 2; - + effect = ITEM_HP_CHANGE; BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_JabocaRowapBerryActivates; @@ -6582,7 +6594,7 @@ u8 GetMoveTarget(u16 move, u8 setTarget) { case MOVE_TARGET_SELECTED: side = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE; - if (gSideTimers[side].followmeTimer && gBattleMons[gSideTimers[side].followmeTarget].hp) + if (IsAffectedByFollowMe(gBattlerAttacker, side)) { targetBattler = gSideTimers[side].followmeTarget; } @@ -6617,7 +6629,7 @@ u8 GetMoveTarget(u16 move, u8 setTarget) break; case MOVE_TARGET_RANDOM: side = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE; - if (gSideTimers[side].followmeTimer && gBattleMons[gSideTimers[side].followmeTarget].hp) + if (IsAffectedByFollowMe(gBattlerAttacker, side)) targetBattler = gSideTimers[side].followmeTarget; else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && moveTarget & MOVE_TARGET_RANDOM) targetBattler = SetRandomTarget(gBattlerAttacker); @@ -7647,7 +7659,7 @@ static u32 CalcAttackStat(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, b break; case ABILITY_ICE_SCALES: if (IS_MOVE_SPECIAL(move)) - MulModifier(&modifier, UQ_4_12(0.5)); + MulModifier(&modifier, UQ_4_12(0.5)); break; } @@ -8521,7 +8533,7 @@ static bool32 TryRemoveScreens(u8 battler) bool32 removed = FALSE; u8 battlerSide = GetBattlerSide(battler); u8 enemySide = GetBattlerSide(BATTLE_OPPOSITE(battler)); - + // try to remove from battler's side if (gSideStatuses[battlerSide] & (SIDE_STATUS_REFLECT | SIDE_STATUS_LIGHTSCREEN | SIDE_STATUS_AURORA_VEIL)) { @@ -8531,7 +8543,7 @@ static bool32 TryRemoveScreens(u8 battler) gSideTimers[battlerSide].auroraVeilTimer = 0; removed = TRUE; } - + // try to remove from battler opponent's side if (gSideStatuses[enemySide] & (SIDE_STATUS_REFLECT | SIDE_STATUS_LIGHTSCREEN | SIDE_STATUS_AURORA_VEIL)) { @@ -8541,7 +8553,7 @@ static bool32 TryRemoveScreens(u8 battler) gSideTimers[enemySide].auroraVeilTimer = 0; removed = TRUE; } - + return removed; } @@ -8568,7 +8580,7 @@ struct Pokemon *GetBattlerPartyData(u8 battlerId) mon = &gPlayerParty[gBattlerPartyIndexes[battlerId]]; else mon = &gEnemyParty[gBattlerPartyIndexes[battlerId]]; - + return mon; } From 34f869ef4054c467cd834fead13e5abf8479dfa6 Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Tue, 6 Jul 2021 10:37:17 +0200 Subject: [PATCH 2/2] Fix White Smoke affecting Shell Smash's def drop --- data/battle_scripts_1.s | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index e3b34fdda..5243fe341 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -1242,13 +1242,13 @@ BattleScript_ShellSmashTryDef:: setbyte sSTAT_ANIM_PLAYED, FALSE playstatchangeanimation BS_ATTACKER, BIT_DEF | BIT_SPDEF, STAT_CHANGE_NEGATIVE | STAT_CHANGE_CANT_PREVENT setstatchanger STAT_DEF, 1, TRUE - statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_BUFF_ALLOW_PTR, BattleScript_ShellSmashTrySpDef + statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_BUFF_ALLOW_PTR | MOVE_EFFECT_CERTAIN, BattleScript_ShellSmashTrySpDef jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_ShellSmashTrySpDef printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_ShellSmashTrySpDef: setstatchanger STAT_SPDEF, 1, TRUE - statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_BUFF_ALLOW_PTR, BattleScript_ShellSmashTryAttack + statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_BUFF_ALLOW_PTR | MOVE_EFFECT_CERTAIN, BattleScript_ShellSmashTryAttack jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_ShellSmashTryAttack printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG