diff options
Diffstat (limited to 'src/battle_main.c')
-rw-r--r-- | src/battle_main.c | 858 |
1 files changed, 788 insertions, 70 deletions
diff --git a/src/battle_main.c b/src/battle_main.c index bf0fdc1aa..0c3e84c1e 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -11,7 +11,6 @@ #include "battle_scripts.h" #include "battle_setup.h" #include "battle_tower.h" -#include "battle_util.h" #include "berry.h" #include "bg.h" #include "data.h" @@ -67,6 +66,11 @@ extern struct MusicPlayerInfo gMPlayInfo_SE2; extern const struct BgTemplate gBattleBgTemplates[]; extern const struct WindowTemplate *const gBattleWindowTemplates[]; +extern const u8 *const gBattleScriptsForMoveEffects[]; +extern const u8 *const gBattlescriptsForBallThrow[]; +extern const u8 *const gBattlescriptsForRunningByItem[]; +extern const u8 *const gBattlescriptsForUsingItem[]; +extern const u8 *const gBattlescriptsForSafariActions[]; // this file's functions #if !defined(NONMATCHING) && MODERN @@ -95,6 +99,7 @@ static void SpriteCB_AnimFaintOpponent(struct Sprite *sprite); static void SpriteCb_BlinkVisible(struct Sprite *sprite); static void SpriteCallbackDummy_3(struct Sprite *sprite); static void oac_poke_ally_(struct Sprite *sprite); +static void SpecialStatusesClear(void); static void TurnValuesCleanUp(bool8 var0); static void SpriteCB_BounceEffect(struct Sprite *sprite); static void BattleStartClearSetData(void); @@ -127,7 +132,19 @@ static void HandleEndTurn_BattleLost(void); static void HandleEndTurn_RanFromBattle(void); static void HandleEndTurn_MonFled(void); static void HandleEndTurn_FinishBattle(void); - +static void HandleAction_UseMove(void); +static void HandleAction_Switch(void); +static void HandleAction_UseItem(void); +static void HandleAction_Run(void); +static void HandleAction_WatchesCarefully(void); +static void HandleAction_SafariZoneBallThrow(void); +static void HandleAction_ThrowPokeblock(void); +static void HandleAction_GoNear(void); +static void HandleAction_SafariZoneRun(void); +static void HandleAction_WallyBallThrow(void); +static void HandleAction_TryFinish(void); +static void HandleAction_NothingIsFainted(void); +static void HandleAction_ActionFinished(void); // EWRAM vars EWRAM_DATA u16 gBattle_BG0_X = 0; @@ -574,6 +591,10 @@ const u8 * const gStatusConditionStringsTable[7][2] = {gStatusConditionString_LoveJpn, gText_Love} }; +static const u8 sPkblToEscapeFactor[][3] = {{0, 0, 0}, {3, 5, 0}, {2, 3, 0}, {1, 2, 0}, {1, 1, 0}}; +static const u8 sGoNearCounterToCatchFactor[] = {4, 3, 2, 1}; +static const u8 sGoNearCounterToEscapeFactor[] = {4, 4, 4, 4}; + // code void CB2_InitBattle(void) { @@ -634,16 +655,19 @@ static void CB2_InitBattleInternal(void) gBattle_WIN0V = 0x5051; ScanlineEffect_Clear(); - for (i = 0; i < 80; i++) + i = 0; + while (i < 80) { gScanlineEffectRegBuffers[0][i] = 0xF0; gScanlineEffectRegBuffers[1][i] = 0xF0; + i++; } - for (; i < 160; i++) + while (i < 160) { gScanlineEffectRegBuffers[0][i] = 0xFF10; gScanlineEffectRegBuffers[1][i] = 0xFF10; + i++; } ScanlineEffect_SetParams(sIntroScanlineParams16Bit); @@ -770,7 +794,8 @@ static void SetPlayerBerryDataInBattleStruct(void) static void SetAllPlayersBerryData(void) { - s32 i, j; + s32 i; + s32 j; if (!(gBattleTypeFlags & BATTLE_TYPE_LINK)) { @@ -1829,7 +1854,7 @@ void BattleMainCB2(void) UpdatePaletteFade(); RunTasks(); - if (JOY_HELD(B_BUTTON) && gBattleTypeFlags & BATTLE_TYPE_RECORDED && sub_8186450()) + if (gMain.heldKeys & B_BUTTON && gBattleTypeFlags & BATTLE_TYPE_RECORDED && sub_8186450()) { gSpecialVar_Result = gBattleOutcome = B_OUTCOME_PLAYER_TELEPORTED; ResetPaletteFadeControl(); @@ -2485,7 +2510,7 @@ static void sub_803939C(void) } break; case 5: - if (JOY_NEW(DPAD_UP)) + if (gMain.newKeys & DPAD_UP) { if (gBattleCommunication[CURSOR_POSITION] != 0) { @@ -2495,7 +2520,7 @@ static void sub_803939C(void) BattleCreateYesNoCursorAt(0); } } - else if (JOY_NEW(DPAD_DOWN)) + else if (gMain.newKeys & DPAD_DOWN) { if (gBattleCommunication[CURSOR_POSITION] == 0) { @@ -2505,7 +2530,7 @@ static void sub_803939C(void) BattleCreateYesNoCursorAt(1); } } - else if (JOY_NEW(A_BUTTON)) + else if (gMain.newKeys & A_BUTTON) { PlaySE(SE_SELECT); if (gBattleCommunication[CURSOR_POSITION] == 0) @@ -2519,7 +2544,7 @@ static void sub_803939C(void) gBattleCommunication[MULTIUSE_STATE]++; } } - else if (JOY_NEW(B_BUTTON)) + else if (gMain.newKeys & B_BUTTON) { PlaySE(SE_SELECT); gBattleCommunication[MULTIUSE_STATE]++; @@ -2686,7 +2711,8 @@ static void sub_80398BC(struct Sprite *sprite) // unused? static void sub_80398D0(struct Sprite *sprite) { - if (--sprite->data[4] == 0) + sprite->data[4]--; + if (sprite->data[4] == 0) { sprite->data[4] = 8; sprite->invisible ^= 1; @@ -3417,13 +3443,17 @@ static void BattleIntroDrawTrainersOrMonsSprites(void) } } - if ((gBattleTypeFlags & BATTLE_TYPE_MULTI) && (GetBattlerPosition(gActiveBattler) == B_POSITION_PLAYER_RIGHT || GetBattlerPosition(gActiveBattler) == B_POSITION_OPPONENT_RIGHT)) + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) { - BtlController_EmitDrawTrainerPic(0); - MarkBattlerForControllerExec(gActiveBattler); + if (GetBattlerPosition(gActiveBattler) == B_POSITION_PLAYER_RIGHT + || GetBattlerPosition(gActiveBattler) == B_POSITION_OPPONENT_RIGHT) + { + BtlController_EmitDrawTrainerPic(0); + MarkBattlerForControllerExec(gActiveBattler); + } } - if ((gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) && (GetBattlerPosition(gActiveBattler) == B_POSITION_OPPONENT_RIGHT)) + if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS && GetBattlerPosition(gActiveBattler) == B_POSITION_OPPONENT_RIGHT) { BtlController_EmitDrawTrainerPic(0); MarkBattlerForControllerExec(gActiveBattler); @@ -3530,7 +3560,7 @@ static void BattleIntroPrintWildMonAttacked(void) static void BattleIntroPrintOpponentSendsOut(void) { - u8 position; + u32 position; if (gBattleControllerExecFlags) return; @@ -3553,7 +3583,7 @@ static void BattleIntroPrintOpponentSendsOut(void) static void BattleIntroOpponent2SendsOutMonAnimation(void) { - u8 position; + u32 position; if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED)) position = B_POSITION_OPPONENT_RIGHT; @@ -3579,26 +3609,22 @@ static void BattleIntroOpponent2SendsOutMonAnimation(void) gBattleMainFunc = BattleIntroRecordMonsToDex; } +#ifdef NONMATCHING static void BattleIntroOpponent1SendsOutMonAnimation(void) { - u8 position; + u32 position; - if (gBattleTypeFlags & BATTLE_TYPE_RECORDED) + if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED)) + position = B_POSITION_OPPONENT_LEFT; + else if (gBattleTypeFlags & BATTLE_TYPE_x2000000) { - if (gBattleTypeFlags & BATTLE_TYPE_x2000000) - { - if (gBattleTypeFlags & BATTLE_TYPE_x80000000) - position = B_POSITION_OPPONENT_LEFT; - else - position = B_POSITION_PLAYER_LEFT; - } - else + if (gBattleTypeFlags & BATTLE_TYPE_x80000000) position = B_POSITION_OPPONENT_LEFT; + else + position = B_POSITION_PLAYER_LEFT; } else - { position = B_POSITION_OPPONENT_LEFT; - } if (gBattleControllerExecFlags) return; @@ -3619,6 +3645,92 @@ static void BattleIntroOpponent1SendsOutMonAnimation(void) gBattleMainFunc = BattleIntroRecordMonsToDex; } +#else +NAKED +static void BattleIntroOpponent1SendsOutMonAnimation(void) +{ + asm_unified( + "push {r4-r6,lr}\n\ + ldr r0, =gBattleTypeFlags\n\ + ldr r2, [r0]\n\ + movs r0, 0x80\n\ + lsls r0, 17\n\ + ands r0, r2\n\ + cmp r0, 0\n\ + beq _0803B298\n\ + movs r0, 0x80\n\ + lsls r0, 18\n\ + ands r0, r2\n\ + cmp r0, 0\n\ + beq _0803B298\n\ + movs r1, 0x80\n\ + lsls r1, 24\n\ + ands r1, r2\n\ + negs r0, r1\n\ + orrs r0, r1\n\ + lsrs r5, r0, 31\n\ + b _0803B29A\n\ + .pool\n\ +_0803B288:\n\ + ldr r1, =gBattleMainFunc\n\ + ldr r0, =BattleIntroOpponent2SendsOutMonAnimation\n\ + b _0803B2F0\n\ + .pool\n\ +_0803B298:\n\ + movs r5, 0x1\n\ +_0803B29A:\n\ + ldr r0, =gBattleControllerExecFlags\n\ + ldr r2, [r0]\n\ + cmp r2, 0\n\ + bne _0803B2F2\n\ + ldr r0, =gActiveBattler\n\ + strb r2, [r0]\n\ + ldr r1, =gBattlersCount\n\ + adds r4, r0, 0\n\ + ldrb r1, [r1]\n\ + cmp r2, r1\n\ + bcs _0803B2EC\n\ + adds r6, r4, 0\n\ +_0803B2B2:\n\ + ldrb r0, [r4]\n\ + bl GetBattlerPosition\n\ + lsls r0, 24\n\ + lsrs r0, 24\n\ + cmp r0, r5\n\ + bne _0803B2D8\n\ + movs r0, 0\n\ + bl BtlController_EmitIntroTrainerBallThrow\n\ + ldrb r0, [r4]\n\ + bl MarkBattlerForControllerExec\n\ + ldr r0, =gBattleTypeFlags\n\ + ldr r0, [r0]\n\ + ldr r1, =0x00008040\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + bne _0803B288\n\ +_0803B2D8:\n\ + ldrb r0, [r6]\n\ + adds r0, 0x1\n\ + strb r0, [r6]\n\ + ldr r1, =gBattlersCount\n\ + lsls r0, 24\n\ + lsrs r0, 24\n\ + ldr r4, =gActiveBattler\n\ + ldrb r1, [r1]\n\ + cmp r0, r1\n\ + bcc _0803B2B2\n\ +_0803B2EC:\n\ + ldr r1, =gBattleMainFunc\n\ + ldr r0, =BattleIntroRecordMonsToDex\n\ +_0803B2F0:\n\ + str r0, [r1]\n\ +_0803B2F2:\n\ + pop {r4-r6}\n\ + pop {r0}\n\ + bx r0\n\ + .pool"); +} +#endif // NONMATCHING static void BattleIntroRecordMonsToDex(void) { @@ -3640,7 +3752,7 @@ static void BattleIntroRecordMonsToDex(void) } } -static void sub_803B3AC(void) // unused +void sub_803B3AC(void) // unused { if (gBattleControllerExecFlags == 0) gBattleMainFunc = BattleIntroPrintPlayerSendsOut; @@ -3673,7 +3785,7 @@ static void BattleIntroPrintPlayerSendsOut(void) static void BattleIntroPlayer2SendsOutMonAnimation(void) { - u8 position; + u32 position; if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED)) position = B_POSITION_PLAYER_RIGHT; @@ -3705,7 +3817,7 @@ static void BattleIntroPlayer2SendsOutMonAnimation(void) static void BattleIntroPlayer1SendsOutMonAnimation(void) { - u8 position; + u32 position; if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED)) position = B_POSITION_PLAYER_LEFT; @@ -3743,7 +3855,7 @@ static void BattleIntroPlayer1SendsOutMonAnimation(void) gBattleMainFunc = TryDoEventsBeforeFirstTurn; } -static void sub_803B598(void) // unused +void sub_803B598(void) // unused { if (gBattleControllerExecFlags == 0) { @@ -3766,7 +3878,8 @@ static void sub_803B598(void) // unused static void TryDoEventsBeforeFirstTurn(void) { - s32 i, j; + s32 i; + s32 j; u8 effect = 0; if (gBattleControllerExecFlags) @@ -3956,7 +4069,11 @@ u8 IsRunningFromBattleImpossible(void) gPotentialItemEffectBattler = gActiveBattler; - if ((holdEffect == HOLD_EFFECT_CAN_ALWAYS_RUN) || (gBattleTypeFlags & BATTLE_TYPE_LINK) || (gBattleMons[gActiveBattler].ability == ABILITY_RUN_AWAY)) + if (holdEffect == HOLD_EFFECT_CAN_ALWAYS_RUN) + return 0; + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + return 0; + if (gBattleMons[gActiveBattler].ability == ABILITY_RUN_AWAY) return 0; side = GetBattlerSide(gActiveBattler); @@ -4733,38 +4850,40 @@ static void SetActionsAndBattlersTurnOrder(void) gBattleStruct->focusPunchBattlerId = 0; return; } - for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++) + else { - if (gChosenActionByBattler[gActiveBattler] == B_ACTION_USE_ITEM || gChosenActionByBattler[gActiveBattler] == B_ACTION_SWITCH) + for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++) { - gActionsByTurnOrder[turnOrderId] = gChosenActionByBattler[gActiveBattler]; - gBattlerByTurnOrder[turnOrderId] = gActiveBattler; - turnOrderId++; + if (gChosenActionByBattler[gActiveBattler] == B_ACTION_USE_ITEM || gChosenActionByBattler[gActiveBattler] == B_ACTION_SWITCH) + { + gActionsByTurnOrder[turnOrderId] = gChosenActionByBattler[gActiveBattler]; + gBattlerByTurnOrder[turnOrderId] = gActiveBattler; + turnOrderId++; + } } - } - for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++) - { - if (gChosenActionByBattler[gActiveBattler] != B_ACTION_USE_ITEM && gChosenActionByBattler[gActiveBattler] != B_ACTION_SWITCH) + for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++) { - gActionsByTurnOrder[turnOrderId] = gChosenActionByBattler[gActiveBattler]; - gBattlerByTurnOrder[turnOrderId] = gActiveBattler; - turnOrderId++; + if (gChosenActionByBattler[gActiveBattler] != B_ACTION_USE_ITEM && gChosenActionByBattler[gActiveBattler] != B_ACTION_SWITCH) + { + gActionsByTurnOrder[turnOrderId] = gChosenActionByBattler[gActiveBattler]; + gBattlerByTurnOrder[turnOrderId] = gActiveBattler; + turnOrderId++; + } } - } - for (i = 0; i < gBattlersCount - 1; i++) - { - for (j = i + 1; j < gBattlersCount; j++) + for (i = 0; i < gBattlersCount - 1; i++) { - u8 battler1 = gBattlerByTurnOrder[i]; - u8 battler2 = gBattlerByTurnOrder[j]; - - if (gActionsByTurnOrder[i] != B_ACTION_USE_ITEM - && gActionsByTurnOrder[j] != B_ACTION_USE_ITEM - && gActionsByTurnOrder[i] != B_ACTION_SWITCH - && gActionsByTurnOrder[j] != B_ACTION_SWITCH) + for (j = i + 1; j < gBattlersCount; j++) { - if (GetWhoStrikesFirst(battler1, battler2, FALSE)) - SwapTurnOrder(i, j); + u8 battler1 = gBattlerByTurnOrder[i]; + u8 battler2 = gBattlerByTurnOrder[j]; + if (gActionsByTurnOrder[i] != B_ACTION_USE_ITEM + && gActionsByTurnOrder[j] != B_ACTION_USE_ITEM + && gActionsByTurnOrder[i] != B_ACTION_SWITCH + && gActionsByTurnOrder[j] != B_ACTION_SWITCH) + { + if (GetWhoStrikesFirst(battler1, battler2, FALSE)) + SwapTurnOrder(i, j); + } } } } @@ -4810,7 +4929,7 @@ static void TurnValuesCleanUp(bool8 var0) gSideTimers[1].followmeTimer = 0; } -void SpecialStatusesClear(void) +static void SpecialStatusesClear(void) { for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++) { @@ -4842,8 +4961,12 @@ static void CheckFocusPunch_ClearVarsBeforeTurnStarts(void) } TryClearRageStatuses(); - gCurrentTurnActionNumber = 0; //See comment underneath - gCurrentActionFuncId = gActionsByTurnOrder[gCurrentTurnActionNumber]; //Should be gActionsByTurnOrder[(gCurrentTurnActionNumber = 0)], but that doesn't match + gCurrentTurnActionNumber = 0; +{ + // something stupid needed to match + u8 zero; + gCurrentActionFuncId = gActionsByTurnOrder[(zero = 0)]; +} gDynamicBasePower = 0; gBattleStruct->dynamicMoveType = 0; gBattleMainFunc = RunTurnActionsFunctions; @@ -4866,10 +4989,13 @@ static void RunTurnActionsFunctions(void) gHitMarker &= ~(HITMARKER_x100000); gBattleMainFunc = sEndTurnFuncsTable[gBattleOutcome & 0x7F]; } - else if (gBattleStruct->savedTurnActionNumber != gCurrentTurnActionNumber) // action turn has been done, clear hitmarker bits for another battlerId + else { - gHitMarker &= ~(HITMARKER_NO_ATTACKSTRING); - gHitMarker &= ~(HITMARKER_UNABLE_TO_USE_MOVE); + if (gBattleStruct->savedTurnActionNumber != gCurrentTurnActionNumber) // action turn has been done, clear hitmarker bits for another battlerId + { + gHitMarker &= ~(HITMARKER_NO_ATTACKSTRING); + gHitMarker &= ~(HITMARKER_UNABLE_TO_USE_MOVE); + } } } @@ -4986,15 +5112,15 @@ static void HandleEndTurn_RanFromBattle(void) { switch (gProtectStructs[gBattlerAttacker].fleeFlag) { + default: + gBattlescriptCurrInstr = BattleScript_GotAwaySafely; + break; case 1: gBattlescriptCurrInstr = BattleScript_SmokeBallEscape; break; case 2: gBattlescriptCurrInstr = BattleScript_RanAwayUsingMonAbility; break; - default: - gBattlescriptCurrInstr = BattleScript_GotAwaySafely; - break; } } @@ -5078,7 +5204,10 @@ static void FreeResetData_ReturnToOvOrDoEvolutions(void) gBattleMainFunc = ReturnFromBattleToOverworld; return; } - gBattleMainFunc = TryEvolvePokemon; + else + { + gBattleMainFunc = TryEvolvePokemon; + } } FreeAllWindowBuffers(); @@ -5174,3 +5303,592 @@ void RunBattleScriptCommands(void) gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]](); } +static void HandleAction_UseMove(void) +{ + u8 side; + u8 var = 4; + + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + + if (*(&gBattleStruct->field_91) & gBitTable[gBattlerAttacker]) + { + gCurrentActionFuncId = B_ACTION_FINISHED; + return; + } + + gCritMultiplier = 1; + gBattleScripting.dmgMultiplier = 1; + gBattleStruct->atkCancellerTracker = 0; + gMoveResultFlags = 0; + gMultiHitCounter = 0; + gBattleCommunication[6] = 0; + gCurrMovePos = gChosenMovePos = *(gBattleStruct->chosenMovePositions + gBattlerAttacker); + + // choose move + if (gProtectStructs[gBattlerAttacker].noValidMoves) + { + gProtectStructs[gBattlerAttacker].noValidMoves = 0; + gCurrentMove = gChosenMove = MOVE_STRUGGLE; + gHitMarker |= HITMARKER_NO_PPDEDUCT; + *(gBattleStruct->moveTarget + gBattlerAttacker) = GetMoveTarget(MOVE_STRUGGLE, 0); + } + else if (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS || gBattleMons[gBattlerAttacker].status2 & STATUS2_RECHARGE) + { + gCurrentMove = gChosenMove = gLockedMoves[gBattlerAttacker]; + } + // encore forces you to use the same move + else if (gDisableStructs[gBattlerAttacker].encoredMove != MOVE_NONE + && gDisableStructs[gBattlerAttacker].encoredMove == gBattleMons[gBattlerAttacker].moves[gDisableStructs[gBattlerAttacker].encoredMovePos]) + { + gCurrentMove = gChosenMove = gDisableStructs[gBattlerAttacker].encoredMove; + gCurrMovePos = gChosenMovePos = gDisableStructs[gBattlerAttacker].encoredMovePos; + *(gBattleStruct->moveTarget + gBattlerAttacker) = GetMoveTarget(gCurrentMove, 0); + } + // check if the encored move wasn't overwritten + else if (gDisableStructs[gBattlerAttacker].encoredMove != MOVE_NONE + && gDisableStructs[gBattlerAttacker].encoredMove != gBattleMons[gBattlerAttacker].moves[gDisableStructs[gBattlerAttacker].encoredMovePos]) + { + gCurrMovePos = gChosenMovePos = gDisableStructs[gBattlerAttacker].encoredMovePos; + gCurrentMove = gChosenMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos]; + gDisableStructs[gBattlerAttacker].encoredMove = MOVE_NONE; + gDisableStructs[gBattlerAttacker].encoredMovePos = 0; + gDisableStructs[gBattlerAttacker].encoreTimer = 0; + *(gBattleStruct->moveTarget + gBattlerAttacker) = GetMoveTarget(gCurrentMove, 0); + } + else if (gBattleMons[gBattlerAttacker].moves[gCurrMovePos] != gChosenMoveByBattler[gBattlerAttacker]) + { + gCurrentMove = gChosenMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos]; + *(gBattleStruct->moveTarget + gBattlerAttacker) = GetMoveTarget(gCurrentMove, 0); + } + else + { + gCurrentMove = gChosenMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos]; + } + + if (gBattleMons[gBattlerAttacker].hp != 0) + { + if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) + gBattleResults.lastUsedMovePlayer = gCurrentMove; + else + gBattleResults.lastUsedMoveOpponent = gCurrentMove; + } + + // choose target + side = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE; + if (gSideTimers[side].followmeTimer != 0 + && gBattleMoves[gCurrentMove].target == MOVE_TARGET_SELECTED + && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gSideTimers[side].followmeTarget) + && gBattleMons[gSideTimers[side].followmeTarget].hp != 0) + { + gBattlerTarget = gSideTimers[side].followmeTarget; + } + else if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + && gSideTimers[side].followmeTimer == 0 + && (gBattleMoves[gCurrentMove].power != 0 + || gBattleMoves[gCurrentMove].target != MOVE_TARGET_USER) + && gBattleMons[*(gBattleStruct->moveTarget + gBattlerAttacker)].ability != ABILITY_LIGHTNING_ROD + && gBattleMoves[gCurrentMove].type == TYPE_ELECTRIC) + { + side = GetBattlerSide(gBattlerAttacker); + for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++) + { + if (side != GetBattlerSide(gActiveBattler) + && *(gBattleStruct->moveTarget + gBattlerAttacker) != gActiveBattler + && gBattleMons[gActiveBattler].ability == ABILITY_LIGHTNING_ROD + && GetBattlerTurnOrderNum(gActiveBattler) < var) + { + var = GetBattlerTurnOrderNum(gActiveBattler); + } + } + if (var == 4) + { + if (gBattleMoves[gChosenMove].target & MOVE_TARGET_RANDOM) + { + if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) + { + if (Random() & 1) + gBattlerTarget = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + else + gBattlerTarget = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); + } + else + { + if (Random() & 1) + gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); + else + gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT); + } + } + else + { + gBattlerTarget = *(gBattleStruct->moveTarget + gBattlerAttacker); + } + + if (gAbsentBattlerFlags & gBitTable[gBattlerTarget]) + { + if (GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget)) + { + gBattlerTarget = GetBattlerAtPosition(GetBattlerPosition(gBattlerTarget) ^ BIT_FLANK); + } + else + { + gBattlerTarget = GetBattlerAtPosition(GetBattlerPosition(gBattlerAttacker) ^ BIT_SIDE); + if (gAbsentBattlerFlags & gBitTable[gBattlerTarget]) + gBattlerTarget = GetBattlerAtPosition(GetBattlerPosition(gBattlerTarget) ^ BIT_FLANK); + } + } + } + else + { + gActiveBattler = gBattlerByTurnOrder[var]; + RecordAbilityBattle(gActiveBattler, gBattleMons[gActiveBattler].ability); + gSpecialStatuses[gActiveBattler].lightningRodRedirected = 1; + gBattlerTarget = gActiveBattler; + } + } + else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && gBattleMoves[gChosenMove].target & MOVE_TARGET_RANDOM) + { + if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) + { + if (Random() & 1) + gBattlerTarget = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + else + gBattlerTarget = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); + } + else + { + if (Random() & 1) + gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); + else + gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT); + } + + if (gAbsentBattlerFlags & gBitTable[gBattlerTarget] + && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget)) + { + gBattlerTarget = GetBattlerAtPosition(GetBattlerPosition(gBattlerTarget) ^ BIT_FLANK); + } + } + else + { + gBattlerTarget = *(gBattleStruct->moveTarget + gBattlerAttacker); + if (gAbsentBattlerFlags & gBitTable[gBattlerTarget]) + { + if (GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget)) + { + gBattlerTarget = GetBattlerAtPosition(GetBattlerPosition(gBattlerTarget) ^ BIT_FLANK); + } + else + { + gBattlerTarget = GetBattlerAtPosition(GetBattlerPosition(gBattlerAttacker) ^ BIT_SIDE); + if (gAbsentBattlerFlags & gBitTable[gBattlerTarget]) + gBattlerTarget = GetBattlerAtPosition(GetBattlerPosition(gBattlerTarget) ^ BIT_FLANK); + } + } + } + + // choose battlescript + if (gBattleTypeFlags & BATTLE_TYPE_PALACE + && gProtectStructs[gBattlerAttacker].palaceUnableToUseMove) + { + if (gBattleMons[gBattlerAttacker].hp == 0) + { + gCurrentActionFuncId = B_ACTION_FINISHED; + return; + } + else if (gPalaceSelectionBattleScripts[gBattlerAttacker] != NULL) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 4; + gBattlescriptCurrInstr = gPalaceSelectionBattleScripts[gBattlerAttacker]; + gPalaceSelectionBattleScripts[gBattlerAttacker] = NULL; + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = 4; + gBattlescriptCurrInstr = BattleScript_MoveUsedLoafingAround; + } + } + else + { + gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]; + } + + if (gBattleTypeFlags & BATTLE_TYPE_ARENA) + BattleArena_AddMindPoints(gBattlerAttacker); + + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; +} + +static void HandleAction_Switch(void) +{ + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + gActionSelectionCursor[gBattlerAttacker] = 0; + gMoveSelectionCursor[gBattlerAttacker] = 0; + + PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, gBattlerAttacker, *(gBattleStruct->field_58 + gBattlerAttacker)) + + gBattleScripting.battler = gBattlerAttacker; + gBattlescriptCurrInstr = BattleScript_ActionSwitch; + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; + + if (gBattleResults.playerSwitchesCounter < 255) + gBattleResults.playerSwitchesCounter++; +} + +static void HandleAction_UseItem(void) +{ + gBattlerAttacker = gBattlerTarget = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + ClearFuryCutterDestinyBondGrudge(gBattlerAttacker); + gLastUsedItem = gBattleBufferB[gBattlerAttacker][1] | (gBattleBufferB[gBattlerAttacker][2] << 8); + + if (gLastUsedItem <= LAST_BALL) // is ball + { + gBattlescriptCurrInstr = gBattlescriptsForBallThrow[gLastUsedItem]; + } + else if (gLastUsedItem == ITEM_POKE_DOLL || gLastUsedItem == ITEM_FLUFFY_TAIL) + { + gBattlescriptCurrInstr = gBattlescriptsForRunningByItem[0]; + } + else if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) + { + gBattlescriptCurrInstr = gBattlescriptsForUsingItem[0]; + } + else + { + gBattleScripting.battler = gBattlerAttacker; + + switch (*(gBattleStruct->AI_itemType + (gBattlerAttacker >> 1))) + { + case AI_ITEM_FULL_RESTORE: + case AI_ITEM_HEAL_HP: + break; + case AI_ITEM_CURE_CONDITION: + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + if (*(gBattleStruct->AI_itemFlags + gBattlerAttacker / 2) & 1) + { + if (*(gBattleStruct->AI_itemFlags + gBattlerAttacker / 2) & 0x3E) + gBattleCommunication[MULTISTRING_CHOOSER] = 5; + } + else + { + while (!(*(gBattleStruct->AI_itemFlags + gBattlerAttacker / 2) & 1)) + { + *(gBattleStruct->AI_itemFlags + gBattlerAttacker / 2) >>= 1; + gBattleCommunication[MULTISTRING_CHOOSER]++; + } + } + break; + case AI_ITEM_X_STAT: + gBattleCommunication[MULTISTRING_CHOOSER] = 4; + if (*(gBattleStruct->AI_itemFlags + (gBattlerAttacker >> 1)) & 0x80) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 5; + } + else + { + PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_ATK) + PREPARE_STRING_BUFFER(gBattleTextBuff2, CHAR_X) + + while (!((*(gBattleStruct->AI_itemFlags + (gBattlerAttacker >> 1))) & 1)) + { + *(gBattleStruct->AI_itemFlags + gBattlerAttacker / 2) >>= 1; + gBattleTextBuff1[2]++; + } + + gBattleScripting.animArg1 = gBattleTextBuff1[2] + 14; + gBattleScripting.animArg2 = 0; + } + break; + case AI_ITEM_GUARD_SPECS: + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + break; + } + + gBattlescriptCurrInstr = gBattlescriptsForUsingItem[*(gBattleStruct->AI_itemType + gBattlerAttacker / 2)]; + } + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; +} + +bool8 TryRunFromBattle(u8 battler) +{ + bool8 effect = FALSE; + u8 holdEffect; + u8 pyramidMultiplier; + u8 speedVar; + + if (gBattleMons[battler].item == ITEM_ENIGMA_BERRY) + holdEffect = gEnigmaBerries[battler].holdEffect; + else + holdEffect = ItemId_GetHoldEffect(gBattleMons[battler].item); + + gPotentialItemEffectBattler = battler; + + if (holdEffect == HOLD_EFFECT_CAN_ALWAYS_RUN) + { + gLastUsedItem = gBattleMons[battler].item; + gProtectStructs[battler].fleeFlag = 1; + effect++; + } + else if (gBattleMons[battler].ability == ABILITY_RUN_AWAY) + { + if (InBattlePyramid()) + { + gBattleStruct->runTries++; + pyramidMultiplier = GetPyramidRunMultiplier(); + speedVar = (gBattleMons[battler].speed * pyramidMultiplier) / (gBattleMons[BATTLE_OPPOSITE(battler)].speed) + (gBattleStruct->runTries * 30); + if (speedVar > (Random() & 0xFF)) + { + gLastUsedAbility = ABILITY_RUN_AWAY; + gProtectStructs[battler].fleeFlag = 2; + effect++; + } + } + else + { + gLastUsedAbility = ABILITY_RUN_AWAY; + gProtectStructs[battler].fleeFlag = 2; + effect++; + } + } + else if (gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_TRAINER_HILL) && gBattleTypeFlags & BATTLE_TYPE_TRAINER) + { + effect++; + } + else + { + if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + { + if (InBattlePyramid()) + { + pyramidMultiplier = GetPyramidRunMultiplier(); + speedVar = (gBattleMons[battler].speed * pyramidMultiplier) / (gBattleMons[BATTLE_OPPOSITE(battler)].speed) + (gBattleStruct->runTries * 30); + if (speedVar > (Random() & 0xFF)) + effect++; + } + else if (gBattleMons[battler].speed < gBattleMons[BATTLE_OPPOSITE(battler)].speed) + { + speedVar = (gBattleMons[battler].speed * 128) / (gBattleMons[BATTLE_OPPOSITE(battler)].speed) + (gBattleStruct->runTries * 30); + if (speedVar > (Random() & 0xFF)) + effect++; + } + else // same speed or faster + { + effect++; + } + } + + gBattleStruct->runTries++; + } + + if (effect) + { + gCurrentTurnActionNumber = gBattlersCount; + gBattleOutcome = B_OUTCOME_RAN; + } + + return effect; +} + +static void HandleAction_Run(void) +{ + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + + if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000)) + { + gCurrentTurnActionNumber = gBattlersCount; + + for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++) + { + if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER) + { + if (gChosenActionByBattler[gActiveBattler] == B_ACTION_RUN) + gBattleOutcome |= B_OUTCOME_LOST; + } + else + { + if (gChosenActionByBattler[gActiveBattler] == B_ACTION_RUN) + gBattleOutcome |= B_OUTCOME_WON; + } + } + + gBattleOutcome |= B_OUTCOME_LINK_BATTLE_RAN; + gSaveBlock2Ptr->frontier.disableRecordBattle = TRUE; + } + else + { + if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) + { + if (!TryRunFromBattle(gBattlerAttacker)) // failed to run away + { + ClearFuryCutterDestinyBondGrudge(gBattlerAttacker); + gBattleCommunication[MULTISTRING_CHOOSER] = 3; + gBattlescriptCurrInstr = BattleScript_PrintFailedToRunString; + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; + } + } + else + { + if (gBattleMons[gBattlerAttacker].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION)) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 4; + gBattlescriptCurrInstr = BattleScript_PrintFailedToRunString; + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; + } + else + { + gCurrentTurnActionNumber = gBattlersCount; + gBattleOutcome = B_OUTCOME_MON_FLED; + } + } + } +} + +static void HandleAction_WatchesCarefully(void) +{ + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + gBattlescriptCurrInstr = gBattlescriptsForSafariActions[0]; + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; +} + +static void HandleAction_SafariZoneBallThrow(void) +{ + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + gNumSafariBalls--; + gLastUsedItem = ITEM_SAFARI_BALL; + gBattlescriptCurrInstr = gBattlescriptsForBallThrow[ITEM_SAFARI_BALL]; + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; +} + +static void HandleAction_ThrowPokeblock(void) +{ + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + gBattleCommunication[MULTISTRING_CHOOSER] = gBattleBufferB[gBattlerAttacker][1] - 1; + gLastUsedItem = gBattleBufferB[gBattlerAttacker][2]; + + if (gBattleResults.pokeblockThrows < 0xFF) + gBattleResults.pokeblockThrows++; + if (gBattleStruct->safariPkblThrowCounter < 3) + gBattleStruct->safariPkblThrowCounter++; + if (gBattleStruct->safariEscapeFactor > 1) + { + if (gBattleStruct->safariEscapeFactor < sPkblToEscapeFactor[gBattleStruct->safariPkblThrowCounter][gBattleCommunication[MULTISTRING_CHOOSER]]) + gBattleStruct->safariEscapeFactor = 1; + else + gBattleStruct->safariEscapeFactor -= sPkblToEscapeFactor[gBattleStruct->safariPkblThrowCounter][gBattleCommunication[MULTISTRING_CHOOSER]]; + } + + gBattlescriptCurrInstr = gBattlescriptsForSafariActions[2]; + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; +} + +static void HandleAction_GoNear(void) +{ + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + + gBattleStruct->safariCatchFactor += sGoNearCounterToCatchFactor[gBattleStruct->safariGoNearCounter]; + if (gBattleStruct->safariCatchFactor > 20) + gBattleStruct->safariCatchFactor = 20; + + gBattleStruct->safariEscapeFactor += sGoNearCounterToEscapeFactor[gBattleStruct->safariGoNearCounter]; + if (gBattleStruct->safariEscapeFactor > 20) + gBattleStruct->safariEscapeFactor = 20; + + if (gBattleStruct->safariGoNearCounter < 3) + { + gBattleStruct->safariGoNearCounter++; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = 1; // Can't get closer. + } + gBattlescriptCurrInstr = gBattlescriptsForSafariActions[1]; + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; +} + +static void HandleAction_SafariZoneRun(void) +{ + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + PlaySE(SE_FLEE); + gCurrentTurnActionNumber = gBattlersCount; + gBattleOutcome = B_OUTCOME_RAN; +} + +static void HandleAction_WallyBallThrow(void) +{ + gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + gBattle_BG0_X = 0; + gBattle_BG0_Y = 0; + + PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, gBattlerAttacker, gBattlerPartyIndexes[gBattlerAttacker]) + + gBattlescriptCurrInstr = gBattlescriptsForSafariActions[3]; + gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; + gActionsByTurnOrder[1] = B_ACTION_FINISHED; +} + +static void HandleAction_TryFinish(void) +{ + if (!HandleFaintedMonActions()) + { + gBattleStruct->faintedActionsState = 0; + gCurrentActionFuncId = B_ACTION_FINISHED; + } +} + +static void HandleAction_NothingIsFainted(void) +{ + gCurrentTurnActionNumber++; + gCurrentActionFuncId = gActionsByTurnOrder[gCurrentTurnActionNumber]; + gHitMarker &= ~(HITMARKER_DESTINYBOND | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_ATTACKSTRING_PRINTED + | HITMARKER_NO_PPDEDUCT | HITMARKER_IGNORE_SAFEGUARD | HITMARKER_IGNORE_ON_AIR + | HITMARKER_IGNORE_UNDERGROUND | HITMARKER_IGNORE_UNDERWATER | HITMARKER_x100000 + | HITMARKER_OBEYS | HITMARKER_x10 | HITMARKER_SYNCHRONISE_EFFECT + | HITMARKER_CHARGING | HITMARKER_x4000000); +} + +static void HandleAction_ActionFinished(void) +{ + *(gBattleStruct->monToSwitchIntoId + gBattlerByTurnOrder[gCurrentTurnActionNumber]) = 6; + gCurrentTurnActionNumber++; + gCurrentActionFuncId = gActionsByTurnOrder[gCurrentTurnActionNumber]; + SpecialStatusesClear(); + gHitMarker &= ~(HITMARKER_DESTINYBOND | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_ATTACKSTRING_PRINTED + | HITMARKER_NO_PPDEDUCT | HITMARKER_IGNORE_SAFEGUARD | HITMARKER_IGNORE_ON_AIR + | HITMARKER_IGNORE_UNDERGROUND | HITMARKER_IGNORE_UNDERWATER | HITMARKER_x100000 + | HITMARKER_OBEYS | HITMARKER_x10 | HITMARKER_SYNCHRONISE_EFFECT + | HITMARKER_CHARGING | HITMARKER_x4000000); + + gCurrentMove = 0; + gBattleMoveDamage = 0; + gMoveResultFlags = 0; + gBattleScripting.animTurn = 0; + gBattleScripting.animTargetsHit = 0; + gLastLandedMoves[gBattlerAttacker] = 0; + gLastHitByType[gBattlerAttacker] = 0; + gBattleStruct->dynamicMoveType = 0; + gDynamicBasePower = 0; + gBattleScripting.moveendState = 0; + gBattleCommunication[3] = 0; + gBattleCommunication[4] = 0; + gBattleScripting.multihitMoveEffect = 0; + gBattleResources->battleScriptsStack->size = 0; +} + + |