diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/battle_ai_script_commands.c | 2 | ||||
-rw-r--r-- | src/battle_util.c | 1230 | ||||
-rw-r--r-- | src/pokemon.c | 2 |
3 files changed, 1206 insertions, 28 deletions
diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c index 0d389aa7f..913068aed 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_script_commands.c @@ -479,7 +479,7 @@ void sub_80C71A8(u8 a) BATTLE_HISTORY->usedMoves[a / 2][i] = 0; } -void sub_80C71D0(u8 a, u8 b) +void RecordAbilityBattle(u8 a, u8 b) { if (GetBattlerSide(a) == 0) BATTLE_HISTORY->abilities[GetBattlerPosition(a) & 1] = b; diff --git a/src/battle_util.c b/src/battle_util.c index 8b0383929..55f674215 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -7,16 +7,20 @@ #include "random.h" #include "pokemon.h" #include "string_util.h" +#include "field_weather.h" #include "battle.h" #include "battle_anim.h" #include "battle_scripts.h" #include "battle_message.h" #include "battle_controllers.h" +#include "battle_ai_script_commands.h" #include "constants/battle.h" #include "constants/moves.h" #include "constants/items.h" #include "constants/species.h" +#include "constants/weather.h" #include "constants/abilities.h" +#include "constants/pokemon.h" #include "constants/battle_anim.h" #include "constants/hold_effects.h" #include "constants/battle_move_effects.h" @@ -82,7 +86,7 @@ void PressurePPLose(u8 target, u8 attacker, u16 move) if (gBattleMons[attacker].pp[i]) --gBattleMons[attacker].pp[i]; if (!(gBattleMons[attacker].status2 & STATUS2_TRANSFORMED) - && !(gDisableStructs[attacker].mimickedMoves & gBitTable[i])) + && !(gDisableStructs[attacker].mimickedMoves & gBitTable[i])) { gActiveBattler = attacker; BtlController_EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + i, 0, 1, &gBattleMons[gActiveBattler].pp[i]); @@ -112,8 +116,8 @@ void PressurePPLoseOnUsingImprison(u8 attacker) } } if (imprisonPos != 4 - && !(gBattleMons[attacker].status2 & STATUS2_TRANSFORMED) - && !(gDisableStructs[attacker].mimickedMoves & gBitTable[imprisonPos])) + && !(gBattleMons[attacker].status2 & STATUS2_TRANSFORMED) + && !(gDisableStructs[attacker].mimickedMoves & gBitTable[imprisonPos])) { gActiveBattler = attacker; BtlController_EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + imprisonPos, 0, 1, &gBattleMons[gActiveBattler].pp[imprisonPos]); @@ -140,8 +144,8 @@ void PressurePPLoseOnUsingPerishSong(u8 attacker) } } if (perishSongPos != MAX_MON_MOVES - && !(gBattleMons[attacker].status2 & STATUS2_TRANSFORMED) - && !(gDisableStructs[attacker].mimickedMoves & gBitTable[perishSongPos])) + && !(gBattleMons[attacker].status2 & STATUS2_TRANSFORMED) + && !(gDisableStructs[attacker].mimickedMoves & gBitTable[perishSongPos])) { gActiveBattler = attacker; BtlController_EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + perishSongPos, 0, 1, &gBattleMons[gActiveBattler].pp[perishSongPos]); @@ -192,14 +196,14 @@ void CancelMultiTurnMoves(u8 battler) bool8 WasUnableToUseMove(u8 battler) { if (gProtectStructs[battler].prlzImmobility - || gProtectStructs[battler].targetNotAffected - || gProtectStructs[battler].usedImprisonedMove - || gProtectStructs[battler].loveImmobility - || gProtectStructs[battler].usedDisabledMove - || gProtectStructs[battler].usedTauntedMove - || gProtectStructs[battler].flag2Unknown - || gProtectStructs[battler].flinchImmobility - || gProtectStructs[battler].confusionSelfDmg) + || gProtectStructs[battler].targetNotAffected + || gProtectStructs[battler].usedImprisonedMove + || gProtectStructs[battler].loveImmobility + || gProtectStructs[battler].usedDisabledMove + || gProtectStructs[battler].usedTauntedMove + || gProtectStructs[battler].flag2Unknown + || gProtectStructs[battler].flinchImmobility + || gProtectStructs[battler].confusionSelfDmg) return TRUE; else return FALSE; @@ -545,8 +549,8 @@ u8 DoFieldEndTurnEffects(void) { gActiveBattler = gBattlerByTurnOrder[gBattleStruct->turnSideTracker]; if (gWishFutureKnock.wishCounter[gActiveBattler] != 0 - && --gWishFutureKnock.wishCounter[gActiveBattler] == 0 - && gBattleMons[gActiveBattler].hp != 0) + && --gWishFutureKnock.wishCounter[gActiveBattler] == 0 + && gBattleMons[gActiveBattler].hp != 0) { gBattlerTarget = gActiveBattler; BattleScriptExecute(BattleScript_WishComesTrue); @@ -693,8 +697,8 @@ u8 DoBattlerEndTurnEffects(void) { case ENDTURN_INGRAIN: // ingrain if ((gStatuses3[gActiveBattler] & STATUS3_ROOTED) - && gBattleMons[gActiveBattler].hp != gBattleMons[gActiveBattler].maxHP - && gBattleMons[gActiveBattler].hp != 0) + && gBattleMons[gActiveBattler].hp != gBattleMons[gActiveBattler].maxHP + && gBattleMons[gActiveBattler].hp != 0) { gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 16; if (gBattleMoveDamage == 0) @@ -722,8 +726,8 @@ u8 DoBattlerEndTurnEffects(void) break; case ENDTURN_LEECH_SEED: // leech seed if ((gStatuses3[gActiveBattler] & STATUS3_LEECHSEED) - && gBattleMons[gStatuses3[gActiveBattler] & STATUS3_LEECHSEED_BATTLER].hp != 0 - && gBattleMons[gActiveBattler].hp != 0) + && gBattleMons[gStatuses3[gActiveBattler] & STATUS3_LEECHSEED_BATTLER].hp != 0 + && gBattleMons[gActiveBattler].hp != 0) { gBattlerTarget = gStatuses3[gActiveBattler] & STATUS3_LEECHSEED_BATTLER; // Notice gBattlerTarget is actually the HP receiver. gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 8; @@ -891,7 +895,7 @@ u8 DoBattlerEndTurnEffects(void) if (WasUnableToUseMove(gActiveBattler)) CancelMultiTurnMoves(gActiveBattler); else if (!(gBattleMons[gActiveBattler].status2 & STATUS2_LOCK_CONFUSE) - && (gBattleMons[gActiveBattler].status2 & STATUS2_MULTIPLETURNS)) + && (gBattleMons[gActiveBattler].status2 & STATUS2_MULTIPLETURNS)) { gBattleMons[gActiveBattler].status2 &= ~(STATUS2_MULTIPLETURNS); if (!(gBattleMons[gActiveBattler].status2 & STATUS2_CONFUSION)) @@ -938,7 +942,7 @@ u8 DoBattlerEndTurnEffects(void) gDisableStructs[gActiveBattler].encoreTimer = 0; } else if (--gDisableStructs[gActiveBattler].encoreTimer == 0 - || gBattleMons[gActiveBattler].pp[gDisableStructs[gActiveBattler].encoredMovePos] == 0) + || gBattleMons[gActiveBattler].pp[gDisableStructs[gActiveBattler].encoredMovePos] == 0) { gDisableStructs[gActiveBattler].encoredMove = 0; gDisableStructs[gActiveBattler].encoreTimer = 0; @@ -1011,8 +1015,8 @@ bool8 HandleWishPerishSongOnTurnEnd(void) } ++gBattleStruct->wishPerishSongBattlerId; if (gWishFutureKnock.futureSightCounter[gActiveBattler] != 0 - && --gWishFutureKnock.futureSightCounter[gActiveBattler] == 0 - && gBattleMons[gActiveBattler].hp != 0) + && --gWishFutureKnock.futureSightCounter[gActiveBattler] == 0 + && gBattleMons[gActiveBattler].hp != 0) { if (gWishFutureKnock.futureSightMove[gActiveBattler] == MOVE_FUTURE_SIGHT) gBattleCommunication[MULTISTRING_CHOOSER] = 0; @@ -1093,8 +1097,8 @@ bool8 HandleFaintedMonActions(void) { gBattlerFainted = gBattlerTarget = gBattleStruct->faintedActionsBattlerId; if (gBattleMons[gBattleStruct->faintedActionsBattlerId].hp == 0 - && !(gBattleStruct->givenExpMons & gBitTable[gBattlerPartyIndexes[gBattleStruct->faintedActionsBattlerId]]) - && !(gAbsentBattlerFlags & gBitTable[gBattleStruct->faintedActionsBattlerId])) + && !(gBattleStruct->givenExpMons & gBitTable[gBattlerPartyIndexes[gBattleStruct->faintedActionsBattlerId]]) + && !(gAbsentBattlerFlags & gBitTable[gBattleStruct->faintedActionsBattlerId])) { BattleScriptExecute(BattleScript_GiveExp); gBattleStruct->faintedActionsState = 2; @@ -1119,7 +1123,7 @@ bool8 HandleFaintedMonActions(void) { gBattlerFainted = gBattlerTarget = gBattleStruct->faintedActionsBattlerId; if (gBattleMons[gBattleStruct->faintedActionsBattlerId].hp == 0 - && !(gAbsentBattlerFlags & gBitTable[gBattleStruct->faintedActionsBattlerId])) + && !(gAbsentBattlerFlags & gBitTable[gBattleStruct->faintedActionsBattlerId])) { BattleScriptExecute(BattleScript_HandleFaintedMon); gBattleStruct->faintedActionsState = 5; @@ -1145,3 +1149,1177 @@ bool8 HandleFaintedMonActions(void) } while (gBattleStruct->faintedActionsState != FAINTED_ACTIONS_MAX_CASE); return FALSE; } + +void TryClearRageStatuses(void) +{ + s32 i; + + for (i = 0; i < gBattlersCount; ++i) + if ((gBattleMons[i].status2 & STATUS2_RAGE) && gChosenMoveByBattler[i] != MOVE_RAGE) + gBattleMons[i].status2 &= ~(STATUS2_RAGE); +} + +enum +{ + CANCELLER_FLAGS, + CANCELLER_ASLEEP, + CANCELLER_FROZEN, + CANCELLER_TRUANT, + CANCELLER_RECHARGE, + CANCELLER_FLINCH, + CANCELLER_DISABLED, + CANCELLER_TAUNTED, + CANCELLER_IMPRISONED, + CANCELLER_CONFUSED, + CANCELLER_PARALYSED, + CANCELLER_GHOST, + CANCELLER_IN_LOVE, + CANCELLER_BIDE, + CANCELLER_THAW, + CANCELLER_END, +}; + +u8 AtkCanceller_UnableToUseMove(void) +{ + u8 effect = 0; + s32 *bideDmg = &gBattleScripting.bideDmg; + + do + { + switch (gBattleStruct->atkCancellerTracker) + { + case CANCELLER_FLAGS: // flags clear + gBattleMons[gBattlerAttacker].status2 &= ~(STATUS2_DESTINY_BOND); + gStatuses3[gBattlerAttacker] &= ~(STATUS3_GRUDGE); + ++gBattleStruct->atkCancellerTracker; + break; + case CANCELLER_ASLEEP: // check being asleep + if (gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP) + { + if (UproarWakeUpCheck(gBattlerAttacker)) + { + gBattleMons[gBattlerAttacker].status1 &= ~(STATUS1_SLEEP); + gBattleMons[gBattlerAttacker].status2 &= ~(STATUS2_NIGHTMARE); + BattleScriptPushCursor(); + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + gBattlescriptCurrInstr = BattleScript_MoveUsedWokeUp; + effect = 2; + } + else + { + u8 toSub; + + if (gBattleMons[gBattlerAttacker].ability == ABILITY_EARLY_BIRD) + toSub = 2; + else + toSub = 1; + if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP) < toSub) + gBattleMons[gBattlerAttacker].status1 &= ~(STATUS1_SLEEP); + else + gBattleMons[gBattlerAttacker].status1 -= toSub; + if (gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP) + { + if (gCurrentMove != MOVE_SNORE && gCurrentMove != MOVE_SLEEP_TALK) + { + gBattlescriptCurrInstr = BattleScript_MoveUsedIsAsleep; + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + effect = 2; + } + } + else + { + gBattleMons[gBattlerAttacker].status2 &= ~(STATUS2_NIGHTMARE); + BattleScriptPushCursor(); + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + gBattlescriptCurrInstr = BattleScript_MoveUsedWokeUp; + effect = 2; + } + } + } + ++gBattleStruct->atkCancellerTracker; + break; + case CANCELLER_FROZEN: // check being frozen + if (gBattleMons[gBattlerAttacker].status1 & STATUS1_FREEZE) + { + if (Random() % 5) + { + if (gBattleMoves[gCurrentMove].effect != EFFECT_THAW_HIT) // unfreezing via a move effect happens in case 13 + { + gBattlescriptCurrInstr = BattleScript_MoveUsedIsFrozen; + gHitMarker |= HITMARKER_NO_ATTACKSTRING; + } + else + { + ++gBattleStruct->atkCancellerTracker; + break; + } + } + else // unfreeze + { + gBattleMons[gBattlerAttacker].status1 &= ~(STATUS1_FREEZE); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_MoveUsedUnfroze; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + effect = 2; + } + ++gBattleStruct->atkCancellerTracker; + break; + case CANCELLER_TRUANT: // truant + if (gBattleMons[gBattlerAttacker].ability == ABILITY_TRUANT && gDisableStructs[gBattlerAttacker].truantCounter) + { + CancelMultiTurnMoves(gBattlerAttacker); + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + gBattlescriptCurrInstr = BattleScript_MoveUsedLoafingAround; + gMoveResultFlags |= MOVE_RESULT_MISSED; + effect = 1; + } + ++gBattleStruct->atkCancellerTracker; + break; + case CANCELLER_RECHARGE: // recharge + if (gBattleMons[gBattlerAttacker].status2 & STATUS2_RECHARGE) + { + gBattleMons[gBattlerAttacker].status2 &= ~(STATUS2_RECHARGE); + gDisableStructs[gBattlerAttacker].rechargeTimer = 0; + CancelMultiTurnMoves(gBattlerAttacker); + gBattlescriptCurrInstr = BattleScript_MoveUsedMustRecharge; + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + effect = 1; + } + ++gBattleStruct->atkCancellerTracker; + break; + case CANCELLER_FLINCH: // flinch + if (gBattleMons[gBattlerAttacker].status2 & STATUS2_FLINCHED) + { + gBattleMons[gBattlerAttacker].status2 &= ~(STATUS2_FLINCHED); + gProtectStructs[gBattlerAttacker].flinchImmobility = 1; + CancelMultiTurnMoves(gBattlerAttacker); + gBattlescriptCurrInstr = BattleScript_MoveUsedFlinched; + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + effect = 1; + } + ++gBattleStruct->atkCancellerTracker; + break; + case CANCELLER_DISABLED: // disabled move + if (gDisableStructs[gBattlerAttacker].disabledMove == gCurrentMove && gDisableStructs[gBattlerAttacker].disabledMove != 0) + { + gProtectStructs[gBattlerAttacker].usedDisabledMove = 1; + gBattleScripting.battler = gBattlerAttacker; + CancelMultiTurnMoves(gBattlerAttacker); + gBattlescriptCurrInstr = BattleScript_MoveUsedIsDisabled; + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + effect = 1; + } + ++gBattleStruct->atkCancellerTracker; + break; + case CANCELLER_TAUNTED: // taunt + if (gDisableStructs[gBattlerAttacker].tauntTimer && gBattleMoves[gCurrentMove].power == 0) + { + gProtectStructs[gBattlerAttacker].usedTauntedMove = 1; + CancelMultiTurnMoves(gBattlerAttacker); + gBattlescriptCurrInstr = BattleScript_MoveUsedIsTaunted; + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + effect = 1; + } + ++gBattleStruct->atkCancellerTracker; + break; + case CANCELLER_IMPRISONED: // imprisoned + if (GetImprisonedMovesCount(gBattlerAttacker, gCurrentMove)) + { + gProtectStructs[gBattlerAttacker].usedImprisonedMove = 1; + CancelMultiTurnMoves(gBattlerAttacker); + gBattlescriptCurrInstr = BattleScript_MoveUsedIsImprisoned; + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + effect = 1; + } + ++gBattleStruct->atkCancellerTracker; + break; + case CANCELLER_CONFUSED: // confusion + if (gBattleMons[gBattlerAttacker].status2 & STATUS2_CONFUSION) + { + --gBattleMons[gBattlerAttacker].status2; + if (gBattleMons[gBattlerAttacker].status2 & STATUS2_CONFUSION) + { + if (Random() & 1) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + BattleScriptPushCursor(); + } + else // confusion dmg + { + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + gBattlerTarget = gBattlerAttacker; + gBattleMoveDamage = CalculateBaseDamage(&gBattleMons[gBattlerAttacker], &gBattleMons[gBattlerAttacker], MOVE_POUND, 0, 40, 0, gBattlerAttacker, gBattlerAttacker); + gProtectStructs[gBattlerAttacker].confusionSelfDmg = 1; + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + } + gBattlescriptCurrInstr = BattleScript_MoveUsedIsConfused; + } + else // snapped out of confusion + { + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_MoveUsedIsConfusedNoMore; + } + effect = 1; + } + ++gBattleStruct->atkCancellerTracker; + break; + case CANCELLER_PARALYSED: // paralysis + if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_PARALYSIS) && (Random() % 4) == 0) + { + gProtectStructs[gBattlerAttacker].prlzImmobility = 1; + gBattlescriptCurrInstr = BattleScript_MoveUsedIsParalyzed; + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + effect = 1; + } + ++gBattleStruct->atkCancellerTracker; + break; + case CANCELLER_GHOST: // GHOST in pokemon tower + if ((gBattleTypeFlags & (BATTLE_TYPE_GHOST | BATTLE_TYPE_LEGENDARY)) == BATTLE_TYPE_GHOST) + { + if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) + gBattlescriptCurrInstr = gUnknown_81D9180; + else + gBattlescriptCurrInstr = gUnknown_81D9192; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + effect = 1; + } + ++gBattleStruct->atkCancellerTracker; + break; + case CANCELLER_IN_LOVE: // infatuation + if (gBattleMons[gBattlerAttacker].status2 & STATUS2_INFATUATION) + { + gBattleScripting.battler = CountTrailingZeroBits((gBattleMons[gBattlerAttacker].status2 & STATUS2_INFATUATION) >> 0x10); + if (Random() & 1) + { + BattleScriptPushCursor(); + } + else + { + BattleScriptPush(BattleScript_MoveUsedIsInLoveCantAttack); + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + gProtectStructs[gBattlerAttacker].loveImmobility = 1; + CancelMultiTurnMoves(gBattlerAttacker); + } + gBattlescriptCurrInstr = BattleScript_MoveUsedIsInLove; + effect = 1; + } + ++gBattleStruct->atkCancellerTracker; + break; + case CANCELLER_BIDE: // bide + if (gBattleMons[gBattlerAttacker].status2 & STATUS2_BIDE) + { + gBattleMons[gBattlerAttacker].status2 -= 0x100; + if (gBattleMons[gBattlerAttacker].status2 & STATUS2_BIDE) + { + gBattlescriptCurrInstr = BattleScript_BideStoringEnergy; + } + else + { + if (gTakenDmg[gBattlerAttacker]) + { + gCurrentMove = MOVE_BIDE; + *bideDmg = gTakenDmg[gBattlerAttacker] * 2; + gBattlerTarget = gTakenDmgByBattler[gBattlerAttacker]; + if (gAbsentBattlerFlags & gBitTable[gBattlerTarget]) + gBattlerTarget = GetMoveTarget(MOVE_BIDE, 1); + gBattlescriptCurrInstr = BattleScript_BideAttack; + } + else + { + gBattlescriptCurrInstr = BattleScript_BideNoEnergyToAttack; + } + } + effect = 1; + } + ++gBattleStruct->atkCancellerTracker; + break; + case CANCELLER_THAW: // move thawing + if (gBattleMons[gBattlerAttacker].status1 & STATUS1_FREEZE) + { + if (gBattleMoves[gCurrentMove].effect == EFFECT_THAW_HIT) + { + gBattleMons[gBattlerAttacker].status1 &= ~(STATUS1_FREEZE); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_MoveUsedUnfroze; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + effect = 2; + } + ++gBattleStruct->atkCancellerTracker; + break; + case CANCELLER_END: + break; + } + + } while (gBattleStruct->atkCancellerTracker != CANCELLER_END && !effect); + if (effect == 2) + { + gActiveBattler = gBattlerAttacker; + BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBattler].status1); + MarkBattlerForControllerExec(gActiveBattler); + } + return effect; +} + +bool8 HasNoMonsToSwitch(u8 battler, u8 partyIdBattlerOn1, u8 partyIdBattlerOn2) +{ + u8 playerId, flankId; + struct Pokemon *party; + s32 i; + + if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + { + return FALSE; + } + else + { + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + playerId = GetBankMultiplayerId(battler); + if (GetBattlerSide(battler) == B_SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + flankId = GetLinkTrainerFlankId(playerId); + for (i = flankId * 3; i < flankId * 3 + 3; ++i) + { + if (GetMonData(&party[i], MON_DATA_HP) != 0 + && GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_NONE + && GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_EGG) + break; + } + return (i == flankId * 3 + 3); + } + else + { + if (GetBattlerSide(battler) == B_SIDE_OPPONENT) + { + playerId = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + flankId = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); + party = gEnemyParty; + } + else + { + playerId = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); + flankId = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT); + party = gPlayerParty; + } + if (partyIdBattlerOn1 == PARTY_SIZE) + partyIdBattlerOn1 = gBattlerPartyIndexes[playerId]; + if (partyIdBattlerOn2 == PARTY_SIZE) + partyIdBattlerOn2 = gBattlerPartyIndexes[flankId]; + for (i = 0; i < PARTY_SIZE; ++i) + { + if (GetMonData(&party[i], MON_DATA_HP) != 0 + && GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_NONE + && GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_EGG + && i != partyIdBattlerOn1 + && i != partyIdBattlerOn2 + && i != *(gBattleStruct->monToSwitchIntoId + playerId) + && i != flankId[gBattleStruct->monToSwitchIntoId]) + break; + } + return (i == PARTY_SIZE); + } + } +} + +enum +{ + CASTFORM_NO_CHANGE, + CASTFORM_TO_NORMAL, + CASTFORM_TO_FIRE, + CASTFORM_TO_WATER, + CASTFORM_TO_ICE, +}; + +u8 CastformDataTypeChange(u8 battler) +{ + u8 formChange = 0; + if (gBattleMons[battler].species != SPECIES_CASTFORM || gBattleMons[battler].ability != ABILITY_FORECAST || gBattleMons[battler].hp == 0) + return CASTFORM_NO_CHANGE; + if (!WEATHER_HAS_EFFECT && !IS_BATTLER_OF_TYPE(battler, TYPE_NORMAL)) + { + SET_BATTLER_TYPE(battler, TYPE_NORMAL); + return CASTFORM_TO_NORMAL; + } + if (!WEATHER_HAS_EFFECT) + return CASTFORM_NO_CHANGE; + if (!(gBattleWeather & (WEATHER_RAIN_ANY | WEATHER_SUN_ANY | WEATHER_HAIL_ANY)) && !IS_BATTLER_OF_TYPE(battler, TYPE_NORMAL)) + { + SET_BATTLER_TYPE(battler, TYPE_NORMAL); + formChange = CASTFORM_TO_NORMAL; + } + if (gBattleWeather & WEATHER_SUN_ANY && !IS_BATTLER_OF_TYPE(battler, TYPE_FIRE)) + { + SET_BATTLER_TYPE(battler, TYPE_FIRE); + formChange = CASTFORM_TO_FIRE; + } + if (gBattleWeather & WEATHER_RAIN_ANY && !IS_BATTLER_OF_TYPE(battler, TYPE_WATER)) + { + SET_BATTLER_TYPE(battler, TYPE_WATER); + formChange = CASTFORM_TO_WATER; + } + if (gBattleWeather & WEATHER_HAIL_ANY && !IS_BATTLER_OF_TYPE(battler, TYPE_ICE)) + { + SET_BATTLER_TYPE(battler, TYPE_ICE); + formChange = CASTFORM_TO_ICE; + } + return formChange; +} + +u8 AbilityBattleEffects(u8 caseID, u8 battler, u8 ability, u8 special, u16 moveArg) +{ + u8 effect = 0; + struct Pokemon *pokeAtk; + struct Pokemon *pokeDef; + u16 speciesAtk; + u16 speciesDef; + u32 pidAtk; + u32 pidDef; + + if (gBattlerAttacker >= gBattlersCount) + gBattlerAttacker = battler; + + if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) + pokeAtk = &gPlayerParty[gBattlerPartyIndexes[gBattlerAttacker]]; + else + pokeAtk = &gEnemyParty[gBattlerPartyIndexes[gBattlerAttacker]]; + if (gBattlerTarget >= gBattlersCount) + gBattlerTarget = battler; + if (GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER) + pokeDef = &gPlayerParty[gBattlerPartyIndexes[gBattlerTarget]]; + else + pokeDef = &gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]]; + speciesAtk = GetMonData(pokeAtk, MON_DATA_SPECIES); + pidAtk = GetMonData(pokeAtk, MON_DATA_PERSONALITY); + speciesDef = GetMonData(pokeDef, MON_DATA_SPECIES); + pidDef = GetMonData(pokeDef, MON_DATA_PERSONALITY); + if (!(gBattleTypeFlags & BATTLE_TYPE_SAFARI)) // Why isn't that check done at the beginning? + { + u8 moveType; + s32 i; + u8 side; + u8 target1; + + if (special) + gLastUsedAbility = special; + else + gLastUsedAbility = gBattleMons[battler].ability; + if (!moveArg) + moveArg = gCurrentMove; + GET_MOVE_TYPE(moveArg, moveType); + if ((gBattleTypeFlags & (BATTLE_TYPE_GHOST | BATTLE_TYPE_LEGENDARY)) == BATTLE_TYPE_GHOST + && (gLastUsedAbility == ABILITY_INTIMIDATE || gLastUsedAbility == ABILITY_TRACE)) + return effect; + switch (caseID) + { + case ABILITYEFFECT_ON_SWITCHIN: // 0 + if (gBattlerAttacker >= gBattlersCount) + gBattlerAttacker = battler; + switch (gLastUsedAbility) + { + case ABILITYEFFECT_SWITCH_IN_WEATHER: + switch (GetCurrentWeather()) + { + case WEATHER_RAIN: + case WEATHER_RAIN_THUNDERSTORM: + case WEATHER_DOWNPOUR: + if (!(gBattleWeather & WEATHER_RAIN_ANY)) + { + gBattleWeather = (WEATHER_RAIN_TEMPORARY | WEATHER_RAIN_PERMANENT); + gBattleScripting.animArg1 = B_ANIM_RAIN_CONTINUES; + gBattleScripting.battler = battler; + ++effect; + } + break; + case WEATHER_SANDSTORM: + if (!(gBattleWeather & WEATHER_SANDSTORM_ANY)) + { + gBattleWeather = (WEATHER_SANDSTORM_PERMANENT | WEATHER_SANDSTORM_TEMPORARY); + gBattleScripting.animArg1 = B_ANIM_SANDSTORM_CONTINUES; + gBattleScripting.battler = battler; + ++effect; + } + break; + case WEATHER_DROUGHT: + if (!(gBattleWeather & WEATHER_SUN_ANY)) + { + gBattleWeather = (WEATHER_SUN_PERMANENT | WEATHER_SUN_TEMPORARY); + gBattleScripting.animArg1 = B_ANIM_SUN_CONTINUES; + gBattleScripting.battler = battler; + ++effect; + } + break; + } + if (effect) + { + gBattleCommunication[MULTISTRING_CHOOSER] = GetCurrentWeather(); + BattleScriptPushCursorAndCallback(BattleScript_OverworldWeatherStarts); + } + break; + case ABILITY_DRIZZLE: + if (!(gBattleWeather & WEATHER_RAIN_PERMANENT)) + { + gBattleWeather = (WEATHER_RAIN_PERMANENT | WEATHER_RAIN_TEMPORARY); + BattleScriptPushCursorAndCallback(BattleScript_DrizzleActivates); + gBattleScripting.battler = battler; + ++effect; + } + break; + case ABILITY_SAND_STREAM: + if (!(gBattleWeather & WEATHER_SANDSTORM_PERMANENT)) + { + gBattleWeather = (WEATHER_SANDSTORM_PERMANENT | WEATHER_SANDSTORM_TEMPORARY); + BattleScriptPushCursorAndCallback(BattleScript_SandstreamActivates); + gBattleScripting.battler = battler; + ++effect; + } + break; + case ABILITY_DROUGHT: + if (!(gBattleWeather & WEATHER_SUN_PERMANENT)) + { + gBattleWeather = (WEATHER_SUN_PERMANENT | WEATHER_SUN_TEMPORARY); + BattleScriptPushCursorAndCallback(BattleScript_DroughtActivates); + gBattleScripting.battler = battler; + ++effect; + } + break; + case ABILITY_INTIMIDATE: + if (!(gSpecialStatuses[battler].intimidatedMon)) + { + gStatuses3[battler] |= STATUS3_INTIMIDATE_POKES; + gSpecialStatuses[battler].intimidatedMon = 1; + } + break; + case ABILITY_FORECAST: + effect = CastformDataTypeChange(battler); + if (effect != 0) + { + BattleScriptPushCursorAndCallback(BattleScript_CastformChange); + gBattleScripting.battler = battler; + *(&gBattleStruct->formToChangeInto) = effect - 1; + } + break; + case ABILITY_TRACE: + if (!(gSpecialStatuses[battler].traced)) + { + gStatuses3[battler] |= STATUS3_TRACE; + gSpecialStatuses[battler].traced = 1; + } + break; + case ABILITY_CLOUD_NINE: + case ABILITY_AIR_LOCK: + { + for (target1 = 0; target1 < gBattlersCount; ++target1) + { + effect = CastformDataTypeChange(target1); + if (effect != 0) + { + BattleScriptPushCursorAndCallback(BattleScript_CastformChange); + gBattleScripting.battler = target1; + *(&gBattleStruct->formToChangeInto) = effect - 1; + break; + } + } + } + break; + } + break; + case ABILITYEFFECT_ENDTURN: // 1 + if (gBattleMons[battler].hp != 0) + { + gBattlerAttacker = battler; + switch (gLastUsedAbility) + { + case ABILITY_RAIN_DISH: + if (WEATHER_HAS_EFFECT && (gBattleWeather & WEATHER_RAIN_ANY) + && gBattleMons[battler].maxHP > gBattleMons[battler].hp) + { + gLastUsedAbility = ABILITY_RAIN_DISH; // why + BattleScriptPushCursorAndCallback(BattleScript_RainDishActivates); + gBattleMoveDamage = gBattleMons[battler].maxHP / 16; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + gBattleMoveDamage *= -1; + ++effect; + } + break; + case ABILITY_SHED_SKIN: + if ((gBattleMons[battler].status1 & STATUS1_ANY) && (Random() % 3) == 0) + { + if (gBattleMons[battler].status1 & (STATUS1_POISON | STATUS1_TOXIC_POISON)) + StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn); + if (gBattleMons[battler].status1 & STATUS1_SLEEP) + StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn); + if (gBattleMons[battler].status1 & STATUS1_PARALYSIS) + StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn); + if (gBattleMons[battler].status1 & STATUS1_BURN) + StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn); + if (gBattleMons[battler].status1 & STATUS1_FREEZE) + StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn); + gBattleMons[battler].status1 = 0; + gBattleMons[battler].status2 &= ~(STATUS2_NIGHTMARE); // fix nightmare glitch + gBattleScripting.battler = gActiveBattler = battler; + BattleScriptPushCursorAndCallback(BattleScript_ShedSkinActivates); + BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battler].status1); + MarkBattlerForControllerExec(gActiveBattler); + ++effect; + } + break; + case ABILITY_SPEED_BOOST: + if (gBattleMons[battler].statStages[STAT_SPEED] < 0xC && gDisableStructs[battler].isFirstTurn != 2) + { + ++gBattleMons[battler].statStages[STAT_SPEED]; + gBattleScripting.animArg1 = 0x11; + gBattleScripting.animArg2 = 0; + BattleScriptPushCursorAndCallback(BattleScript_SpeedBoostActivates); + gBattleScripting.battler = battler; + ++effect; + } + break; + case ABILITY_TRUANT: + gDisableStructs[gBattlerAttacker].truantCounter ^= 1; + break; + } + } + break; + case ABILITYEFFECT_MOVES_BLOCK: // 2 + if (gLastUsedAbility == ABILITY_SOUNDPROOF) + { + for (i = 0; sSoundMovesTable[i] != 0xFFFF; ++i) + if (sSoundMovesTable[i] == moveArg) + break; + if (sSoundMovesTable[i] != 0xFFFF) + { + if (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS) + gHitMarker |= HITMARKER_NO_PPDEDUCT; + gBattlescriptCurrInstr = BattleScript_SoundproofProtected; + effect = 1; + } + } + break; + case ABILITYEFFECT_ABSORBING: // 3 + if (moveArg) + { + switch (gLastUsedAbility) + { + case ABILITY_VOLT_ABSORB: + if (moveType == TYPE_ELECTRIC && gBattleMoves[moveArg].power != 0) + { + if (gProtectStructs[gBattlerAttacker].notFirstStrike) + gBattlescriptCurrInstr = BattleScript_MoveHPDrain; + else + gBattlescriptCurrInstr = BattleScript_MoveHPDrain_PPLoss; + effect = 1; + } + break; + case ABILITY_WATER_ABSORB: + if (moveType == TYPE_WATER && gBattleMoves[moveArg].power != 0) + { + if (gProtectStructs[gBattlerAttacker].notFirstStrike) + gBattlescriptCurrInstr = BattleScript_MoveHPDrain; + else + gBattlescriptCurrInstr = BattleScript_MoveHPDrain_PPLoss; + effect = 1; + } + break; + case ABILITY_FLASH_FIRE: + if (moveType == TYPE_FIRE && !(gBattleMons[battler].status1 & STATUS1_FREEZE)) + { + if (!(gBattleResources->flags->flags[battler] & RESOURCE_FLAG_FLASH_FIRE)) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + if (gProtectStructs[gBattlerAttacker].notFirstStrike) + gBattlescriptCurrInstr = BattleScript_FlashFireBoost; + else + gBattlescriptCurrInstr = BattleScript_FlashFireBoost_PPLoss; + gBattleResources->flags->flags[battler] |= RESOURCE_FLAG_FLASH_FIRE; + effect = 2; + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + if (gProtectStructs[gBattlerAttacker].notFirstStrike) + gBattlescriptCurrInstr = BattleScript_FlashFireBoost; + else + gBattlescriptCurrInstr = BattleScript_FlashFireBoost_PPLoss; + effect = 2; + } + } + break; + } + if (effect == 1) + { + if (gBattleMons[battler].maxHP == gBattleMons[battler].hp) + { + if ((gProtectStructs[gBattlerAttacker].notFirstStrike)) + gBattlescriptCurrInstr = BattleScript_MonMadeMoveUseless; + else + gBattlescriptCurrInstr = BattleScript_MonMadeMoveUseless_PPLoss; + } + else + { + gBattleMoveDamage = gBattleMons[battler].maxHP / 4; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + gBattleMoveDamage *= -1; + } + } + } + break; + case ABILITYEFFECT_MOVE_END: // Think contact abilities. + switch (gLastUsedAbility) + { + case ABILITY_COLOR_CHANGE: + if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + && moveArg != MOVE_STRUGGLE + && gBattleMoves[moveArg].power != 0 + && TARGET_TURN_DAMAGED + && !IS_BATTLER_OF_TYPE(battler, moveType) + && gBattleMons[battler].hp != 0) + { + SET_BATTLER_TYPE(battler, moveType); + PREPARE_TYPE_BUFFER(gBattleTextBuff1, moveType); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_ColorChangeActivates; + ++effect; + } + break; + case ABILITY_ROUGH_SKIN: + if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + && gBattleMons[gBattlerAttacker].hp != 0 + && !gProtectStructs[gBattlerAttacker].confusionSelfDmg + && TARGET_TURN_DAMAGED + && (gBattleMoves[moveArg].flags & FLAG_MAKES_CONTACT)) + { + gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 16; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_RoughSkinActivates; + ++effect; + } + break; + case ABILITY_EFFECT_SPORE: + if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + && gBattleMons[gBattlerAttacker].hp != 0 + && !gProtectStructs[gBattlerAttacker].confusionSelfDmg + && TARGET_TURN_DAMAGED + && (gBattleMoves[moveArg].flags & FLAG_MAKES_CONTACT) + && (Random() % 10) == 0) + { + do + gBattleCommunication[MOVE_EFFECT_BYTE] = Random() & 3; + while (gBattleCommunication[MOVE_EFFECT_BYTE] == 0); + + if (gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_BURN) + gBattleCommunication[MOVE_EFFECT_BYTE] += 2; // 5 MOVE_EFFECT_PARALYSIS + gBattleCommunication[MOVE_EFFECT_BYTE] += MOVE_EFFECT_AFFECTS_USER; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_ApplySecondaryEffect; + gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; + ++effect; + } + break; + case ABILITY_POISON_POINT: + if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + && gBattleMons[gBattlerAttacker].hp != 0 + && !gProtectStructs[gBattlerAttacker].confusionSelfDmg + && TARGET_TURN_DAMAGED + && (gBattleMoves[moveArg].flags & FLAG_MAKES_CONTACT) + && (Random() % 3) == 0) + { + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_POISON; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_ApplySecondaryEffect; + gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; + ++effect; + } + break; + case ABILITY_STATIC: + if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + && gBattleMons[gBattlerAttacker].hp != 0 + && !gProtectStructs[gBattlerAttacker].confusionSelfDmg + && TARGET_TURN_DAMAGED + && (gBattleMoves[moveArg].flags & FLAG_MAKES_CONTACT) + && (Random() % 3) == 0) + { + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_PARALYSIS; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_ApplySecondaryEffect; + gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; + ++effect; + } + break; + case ABILITY_FLAME_BODY: + if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + && gBattleMons[gBattlerAttacker].hp != 0 + && !gProtectStructs[gBattlerAttacker].confusionSelfDmg + && (gBattleMoves[moveArg].flags & FLAG_MAKES_CONTACT) + && TARGET_TURN_DAMAGED + && (Random() % 3) == 0) + { + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_BURN; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_ApplySecondaryEffect; + gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; + ++effect; + } + break; + case ABILITY_CUTE_CHARM: + if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + && gBattleMons[gBattlerAttacker].hp != 0 + && !gProtectStructs[gBattlerAttacker].confusionSelfDmg + && (gBattleMoves[moveArg].flags & FLAG_MAKES_CONTACT) + && TARGET_TURN_DAMAGED + && gBattleMons[gBattlerTarget].hp != 0 + && (Random() % 3) == 0 + && gBattleMons[gBattlerAttacker].ability != ABILITY_OBLIVIOUS + && GetGenderFromSpeciesAndPersonality(speciesAtk, pidAtk) != GetGenderFromSpeciesAndPersonality(speciesDef, pidDef) + && !(gBattleMons[gBattlerAttacker].status2 & STATUS2_INFATUATION) + && GetGenderFromSpeciesAndPersonality(speciesAtk, pidAtk) != MON_GENDERLESS + && GetGenderFromSpeciesAndPersonality(speciesDef, pidDef) != MON_GENDERLESS) + { + gBattleMons[gBattlerAttacker].status2 |= STATUS2_INFATUATED_WITH(gBattlerTarget); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_CuteCharmActivates; + ++effect; + } + break; + } + break; + case ABILITYEFFECT_IMMUNITY: // 5 + for (battler = 0; battler < gBattlersCount; battler++) + { + switch (gBattleMons[battler].ability) + { + case ABILITY_IMMUNITY: + if (gBattleMons[battler].status1 & (STATUS1_POISON | STATUS1_TOXIC_POISON | STATUS1_TOXIC_COUNTER)) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn); + effect = 1; + } + break; + case ABILITY_OWN_TEMPO: + if (gBattleMons[battler].status2 & STATUS2_CONFUSION) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_ConfusionJpn); + effect = 2; + } + break; + case ABILITY_LIMBER: + if (gBattleMons[battler].status1 & STATUS1_PARALYSIS) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn); + effect = 1; + } + break; + case ABILITY_INSOMNIA: + case ABILITY_VITAL_SPIRIT: + if (gBattleMons[battler].status1 & STATUS1_SLEEP) + { + gBattleMons[battler].status2 &= ~(STATUS2_NIGHTMARE); + StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn); + effect = 1; + } + break; + case ABILITY_WATER_VEIL: + if (gBattleMons[battler].status1 & STATUS1_BURN) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn); + effect = 1; + } + break; + case ABILITY_MAGMA_ARMOR: + if (gBattleMons[battler].status1 & STATUS1_FREEZE) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn); + effect = 1; + } + break; + case ABILITY_OBLIVIOUS: + if (gBattleMons[battler].status2 & STATUS2_INFATUATION) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_LoveJpn); + effect = 3; + } + break; + } + if (effect) + { + switch (effect) + { + case 1: // status cleared + gBattleMons[battler].status1 = 0; + break; + case 2: // get rid of confusion + gBattleMons[battler].status2 &= ~(STATUS2_CONFUSION); + break; + case 3: // get rid of infatuation + gBattleMons[battler].status2 &= ~(STATUS2_INFATUATION); + break; + } + + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_AbilityCuredStatus; + gBattleScripting.battler = battler; + gActiveBattler = battler; + BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBattler].status1); + MarkBattlerForControllerExec(gActiveBattler); + return effect; + } + } + break; + case ABILITYEFFECT_FORECAST: // 6 + for (battler = 0; battler < gBattlersCount; ++battler) + { + if (gBattleMons[battler].ability == ABILITY_FORECAST) + { + effect = CastformDataTypeChange(battler); + if (effect) + { + BattleScriptPushCursorAndCallback(BattleScript_CastformChange); + gBattleScripting.battler = battler; + *(&gBattleStruct->formToChangeInto) = effect - 1; + return effect; + } + } + } + break; + case ABILITYEFFECT_SYNCHRONIZE: // 7 + if (gLastUsedAbility == ABILITY_SYNCHRONIZE && (gHitMarker & HITMARKER_SYNCHRONISE_EFFECT)) + { + gHitMarker &= ~(HITMARKER_SYNCHRONISE_EFFECT); + gBattleStruct->synchronizeMoveEffect &= ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); + if (gBattleStruct->synchronizeMoveEffect == MOVE_EFFECT_TOXIC) + gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_POISON; + gBattleCommunication[MOVE_EFFECT_BYTE] = gBattleStruct->synchronizeMoveEffect + MOVE_EFFECT_AFFECTS_USER; + gBattleScripting.battler = gBattlerTarget; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_SynchronizeActivates; + gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; + ++effect; + } + break; + case ABILITYEFFECT_ATK_SYNCHRONIZE: // 8 + if (gLastUsedAbility == ABILITY_SYNCHRONIZE && (gHitMarker & HITMARKER_SYNCHRONISE_EFFECT)) + { + gHitMarker &= ~(HITMARKER_SYNCHRONISE_EFFECT); + gBattleStruct->synchronizeMoveEffect &= ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); + if (gBattleStruct->synchronizeMoveEffect == MOVE_EFFECT_TOXIC) + gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_POISON; + gBattleCommunication[MOVE_EFFECT_BYTE] = gBattleStruct->synchronizeMoveEffect; + gBattleScripting.battler = gBattlerAttacker; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_SynchronizeActivates; + gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; + ++effect; + } + break; + case ABILITYEFFECT_INTIMIDATE1: // 9 + for (i = 0; i < gBattlersCount; ++i) + { + if (gBattleMons[i].ability == ABILITY_INTIMIDATE && gStatuses3[i] & STATUS3_INTIMIDATE_POKES) + { + gLastUsedAbility = ABILITY_INTIMIDATE; + gStatuses3[i] &= ~(STATUS3_INTIMIDATE_POKES); + BattleScriptPushCursorAndCallback(BattleScript_IntimidateActivatesEnd3); + gBattleStruct->intimidateBattler = i; + ++effect; + break; + } + } + break; + case ABILITYEFFECT_TRACE: // 11 + for (i = 0; i < gBattlersCount; ++i) + { + if (gBattleMons[i].ability == ABILITY_TRACE && (gStatuses3[i] & STATUS3_TRACE)) + { + u8 target2; + + side = (GetBattlerPosition(i) ^ BIT_SIDE) & BIT_SIDE; // side of the opposing pokemon + target1 = GetBattlerAtPosition(side); + target2 = GetBattlerAtPosition(side + BIT_FLANK); + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + if (gBattleMons[target1].ability != 0 && gBattleMons[target1].hp != 0 + && gBattleMons[target2].ability != 0 && gBattleMons[target2].hp != 0) + { + gActiveBattler = GetBattlerAtPosition(((Random() & 1) * 2) | side); + gBattleMons[i].ability = gBattleMons[gActiveBattler].ability; + gLastUsedAbility = gBattleMons[gActiveBattler].ability; + ++effect; + } + else if (gBattleMons[target1].ability != 0 && gBattleMons[target1].hp != 0) + { + gActiveBattler = target1; + gBattleMons[i].ability = gBattleMons[gActiveBattler].ability; + gLastUsedAbility = gBattleMons[gActiveBattler].ability; + ++effect; + } + else if (gBattleMons[target2].ability != 0 && gBattleMons[target2].hp != 0) + { + gActiveBattler = target2; + gBattleMons[i].ability = gBattleMons[gActiveBattler].ability; + gLastUsedAbility = gBattleMons[gActiveBattler].ability; + ++effect; + } + } + else + { + gActiveBattler = target1; + if (gBattleMons[target1].ability && gBattleMons[target1].hp) + { + gBattleMons[i].ability = gBattleMons[target1].ability; + gLastUsedAbility = gBattleMons[target1].ability; + ++effect; + } + } + if (effect) + { + BattleScriptPushCursorAndCallback(BattleScript_TraceActivates); + gStatuses3[i] &= ~(STATUS3_TRACE); + gBattleScripting.battler = i; + PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gActiveBattler, gBattlerPartyIndexes[gActiveBattler]) + PREPARE_ABILITY_BUFFER(gBattleTextBuff2, gLastUsedAbility) + break; + } + } + } + break; + case ABILITYEFFECT_INTIMIDATE2: // 10 + for (i = 0; i < gBattlersCount; ++i) + { + if (gBattleMons[i].ability == ABILITY_INTIMIDATE && (gStatuses3[i] & STATUS3_INTIMIDATE_POKES)) + { + gLastUsedAbility = ABILITY_INTIMIDATE; + gStatuses3[i] &= ~(STATUS3_INTIMIDATE_POKES); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_IntimidateActivates; + gBattleStruct->intimidateBattler = i; + ++effect; + break; + } + } + break; + case ABILITYEFFECT_CHECK_OTHER_SIDE: // 12 + side = GetBattlerSide(battler); + for (i = 0; i < gBattlersCount; ++i) + { + if (GetBattlerSide(i) != side && gBattleMons[i].ability == ability) + { + gLastUsedAbility = ability; + effect = i + 1; + } + } + break; + case ABILITYEFFECT_CHECK_BATTLER_SIDE: // 13 + side = GetBattlerSide(battler); + for (i = 0; i < gBattlersCount; ++i) + { + if (GetBattlerSide(i) == side && gBattleMons[i].ability == ability) + { + gLastUsedAbility = ability; + effect = i + 1; + } + } + break; + case ABILITYEFFECT_FIELD_SPORT: // 14 + switch (gLastUsedAbility) + { + case 0xFD: + for (i = 0; i < gBattlersCount; ++i) + if (gStatuses3[i] & STATUS3_MUDSPORT) + effect = i + 1; + break; + case 0xFE: + for (i = 0; i < gBattlersCount; ++i) + if (gStatuses3[i] & STATUS3_WATERSPORT) + effect = i + 1; + break; + default: + for (i = 0; i < gBattlersCount; ++i) + { + if (gBattleMons[i].ability == ability) + { + gLastUsedAbility = ability; + effect = i + 1; + } + } + break; + } + break; + case ABILITYEFFECT_CHECK_ON_FIELD: // 19 + for (i = 0; i < gBattlersCount; ++i) + { + if (gBattleMons[i].ability == ability && gBattleMons[i].hp != 0) + { + gLastUsedAbility = ability; + effect = i + 1; + } + } + break; + case ABILITYEFFECT_CHECK_FIELD_EXCEPT_BATTLER: // 15 + side = GetBattlerSide(battler); + for (i = 0; i < gBattlersCount; ++i) + { + if (GetBattlerSide(i) != side && gBattleMons[i].ability == ability) + { + gLastUsedAbility = ability; + effect = i + 1; + break; + } + } + if (!effect) + { + for (i = 0; i < gBattlersCount; ++i) + { + if (gBattleMons[i].ability == ability && GetBattlerSide(i) == side && i != battler) + { + gLastUsedAbility = ability; + effect = i + 1; + } + } + } + break; + case ABILITYEFFECT_COUNT_OTHER_SIDE: // 16 + side = GetBattlerSide(battler); + for (i = 0; i < gBattlersCount; ++i) + { + if (GetBattlerSide(i) != side && gBattleMons[i].ability == ability) + { + gLastUsedAbility = ability; + ++effect; + } + } + break; + case ABILITYEFFECT_COUNT_BATTLER_SIDE: // 17 + side = GetBattlerSide(battler); + for (i = 0; i < gBattlersCount; ++i) + { + if (GetBattlerSide(i) == side && gBattleMons[i].ability == ability) + { + gLastUsedAbility = ability; + ++effect; + } + } + break; + case ABILITYEFFECT_COUNT_ON_FIELD: // 18 + for (i = 0; i < gBattlersCount; ++i) + { + if (gBattleMons[i].ability == ability && i != battler) + { + gLastUsedAbility = ability; + ++effect; + } + } + break; + } + if (effect && caseID < ABILITYEFFECT_CHECK_OTHER_SIDE && gLastUsedAbility != 0xFF) + RecordAbilityBattle(battler, gLastUsedAbility); + } + return effect; +} diff --git a/src/pokemon.c b/src/pokemon.c index 615bf55f1..ec90f6cd4 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -2567,7 +2567,7 @@ s32 CalculateBaseDamage(struct BattlePokemon *attacker, struct BattlePokemon *de } // flash fire triggered - if ((gBattleResources->flags->flags[battlerIdAtk] & UNKNOWN_FLAG_FLASH_FIRE) && type == TYPE_FIRE) + if ((gBattleResources->flags->flags[battlerIdAtk] & RESOURCE_FLAG_FLASH_FIRE) && type == TYPE_FIRE) damage = (15 * damage) / 10; } |