summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/battle_ai_script_commands.c13
-rw-r--r--src/battle_util.c1147
-rw-r--r--src/battle_util2.c5
-rw-r--r--src/pokemon.c18
4 files changed, 1163 insertions, 20 deletions
diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c
index 1c281e853..0d389aa7f 100644
--- a/src/battle_ai_script_commands.c
+++ b/src/battle_ai_script_commands.c
@@ -34,7 +34,6 @@ enum
extern const u8 *gAIScriptPtr;
extern u8 *BattleAIs[];
-extern u16 gLastUsedMove[];
static void BattleAICmd_if_random_less_than(void);
static void BattleAICmd_if_random_greater_than(void);
@@ -466,7 +465,7 @@ void sub_80C7164(void)
{
if (BATTLE_HISTORY->usedMoves[gBattlerTarget >> 1][i] == 0)
{
- BATTLE_HISTORY->usedMoves[gBattlerTarget >> 1][i] = gLastUsedMove[gBattlerTarget];
+ BATTLE_HISTORY->usedMoves[gBattlerTarget >> 1][i] = gLastMoves[gBattlerTarget];
return;
}
}
@@ -1035,9 +1034,9 @@ static void BattleAICmd_is_most_powerful_move(void)
static void BattleAICmd_get_move(void)
{
if (gAIScriptPtr[1] == USER)
- AI_THINKING_STRUCT->funcResult = gLastUsedMove[gBattlerAttacker];
+ AI_THINKING_STRUCT->funcResult = gLastMoves[gBattlerAttacker];
else
- AI_THINKING_STRUCT->funcResult = gLastUsedMove[gBattlerTarget];
+ AI_THINKING_STRUCT->funcResult = gLastMoves[gBattlerTarget];
gAIScriptPtr += 2;
}
@@ -1373,7 +1372,7 @@ static void BattleAICmd_get_weather(void)
AI_THINKING_STRUCT->funcResult = WEATHER_TYPE_RAIN;
if (gBattleWeather & WEATHER_SANDSTORM_ANY)
AI_THINKING_STRUCT->funcResult = WEATHER_TYPE_SANDSTORM;
- if (gBattleWeather & WEATHER_SUNNY_ANY)
+ if (gBattleWeather & WEATHER_SUN_ANY)
AI_THINKING_STRUCT->funcResult = WEATHER_TYPE_SUNNY;
if (gBattleWeather & WEATHER_HAIL)
AI_THINKING_STRUCT->funcResult = WEATHER_TYPE_HAIL;
@@ -1931,7 +1930,7 @@ static void BattleAICmd_if_level_compare(void)
static void BattleAICmd_if_taunted(void)
{
- if (gDisableStructs[gBattlerTarget].tauntTimer1 != 0)
+ if (gDisableStructs[gBattlerTarget].tauntTimer != 0)
gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
else
gAIScriptPtr += 5;
@@ -1939,7 +1938,7 @@ static void BattleAICmd_if_taunted(void)
static void BattleAICmd_if_not_taunted(void)
{
- if (gDisableStructs[gBattlerTarget].tauntTimer1 == 0)
+ if (gDisableStructs[gBattlerTarget].tauntTimer == 0)
gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
else
gAIScriptPtr += 5;
diff --git a/src/battle_util.c b/src/battle_util.c
new file mode 100644
index 000000000..8b0383929
--- /dev/null
+++ b/src/battle_util.c
@@ -0,0 +1,1147 @@
+#include "global.h"
+#include "item.h"
+#include "text.h"
+#include "util.h"
+#include "link.h"
+#include "berry.h"
+#include "random.h"
+#include "pokemon.h"
+#include "string_util.h"
+#include "battle.h"
+#include "battle_anim.h"
+#include "battle_scripts.h"
+#include "battle_message.h"
+#include "battle_controllers.h"
+#include "constants/battle.h"
+#include "constants/moves.h"
+#include "constants/items.h"
+#include "constants/species.h"
+#include "constants/abilities.h"
+#include "constants/battle_anim.h"
+#include "constants/hold_effects.h"
+#include "constants/battle_move_effects.h"
+#include "constants/battle_script_commands.h"
+
+const u16 sSoundMovesTable[] =
+{
+ MOVE_GROWL, MOVE_ROAR, MOVE_SING, MOVE_SUPERSONIC, MOVE_SCREECH, MOVE_SNORE,
+ MOVE_UPROAR, MOVE_METAL_SOUND, MOVE_GRASS_WHISTLE, MOVE_HYPER_VOICE, 0xFFFF
+};
+
+u8 GetBattlerForBattleScript(u8 caseId)
+{
+ u32 ret = 0;
+
+ switch (caseId)
+ {
+ case BS_TARGET:
+ ret = gBattlerTarget;
+ break;
+ case BS_ATTACKER:
+ ret = gBattlerAttacker;
+ break;
+ case BS_EFFECT_BATTLER:
+ ret = gEffectBattler;
+ break;
+ case BS_BATTLER_0:
+ ret = 0;
+ break;
+ case BS_SCRIPTING:
+ ret = gBattleScripting.battler;
+ break;
+ case BS_FAINTED:
+ ret = gBattlerFainted;
+ break;
+ case 5:
+ ret = gBattlerFainted;
+ break;
+ case BS_PLAYER1:
+ ret = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
+ break;
+ case BS_OPPONENT1:
+ ret = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
+ break;
+ case 4:
+ case 6:
+ case 8:
+ case 9:
+ break;
+ }
+ return ret;
+}
+
+void PressurePPLose(u8 target, u8 attacker, u16 move)
+{
+ s32 i;
+
+ if (gBattleMons[target].ability == ABILITY_PRESSURE)
+ {
+ for (i = 0; i < MAX_MON_MOVES && gBattleMons[attacker].moves[i] != move; ++i);
+ if (i != MAX_MON_MOVES)
+ {
+ if (gBattleMons[attacker].pp[i])
+ --gBattleMons[attacker].pp[i];
+ if (!(gBattleMons[attacker].status2 & STATUS2_TRANSFORMED)
+ && !(gDisableStructs[attacker].mimickedMoves & gBitTable[i]))
+ {
+ gActiveBattler = attacker;
+ BtlController_EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + i, 0, 1, &gBattleMons[gActiveBattler].pp[i]);
+ MarkBattlerForControllerExec(gActiveBattler);
+ }
+ }
+ }
+}
+
+void PressurePPLoseOnUsingImprison(u8 attacker)
+{
+ s32 i, j;
+ s32 imprisonPos = 4;
+ u8 atkSide = GetBattlerSide(attacker);
+
+ for (i = 0; i < gBattlersCount; ++i)
+ {
+ if (atkSide != GetBattlerSide(i) && gBattleMons[i].ability == ABILITY_PRESSURE)
+ {
+ for (j = 0; j < MAX_MON_MOVES && gBattleMons[attacker].moves[j] != MOVE_IMPRISON; ++j);
+ if (j != MAX_MON_MOVES)
+ {
+ imprisonPos = j;
+ if (gBattleMons[attacker].pp[j])
+ --gBattleMons[attacker].pp[j];
+ }
+ }
+ }
+ if (imprisonPos != 4
+ && !(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]);
+ MarkBattlerForControllerExec(gActiveBattler);
+ }
+}
+
+void PressurePPLoseOnUsingPerishSong(u8 attacker)
+{
+ s32 i, j;
+ s32 perishSongPos = 4;
+
+ for (i = 0; i < gBattlersCount; ++i)
+ {
+ if (gBattleMons[i].ability == ABILITY_PRESSURE && i != attacker)
+ {
+ for (j = 0; j < MAX_MON_MOVES && gBattleMons[attacker].moves[j] != MOVE_PERISH_SONG; ++j);
+ if (j != MAX_MON_MOVES)
+ {
+ perishSongPos = j;
+ if (gBattleMons[attacker].pp[j])
+ --gBattleMons[attacker].pp[j];
+ }
+ }
+ }
+ if (perishSongPos != MAX_MON_MOVES
+ && !(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]);
+ MarkBattlerForControllerExec(gActiveBattler);
+ }
+}
+
+void MarkAllBattlersForControllerExec(void)
+{
+ s32 i;
+
+ if (gBattleTypeFlags & BATTLE_TYPE_LINK)
+ for (i = 0; i < gBattlersCount; ++i)
+ gBattleControllerExecFlags |= gBitTable[i] << 0x1C;
+ else
+ for (i = 0; i < gBattlersCount; ++i)
+ gBattleControllerExecFlags |= gBitTable[i];
+}
+
+void MarkBattlerForControllerExec(u8 battlerId)
+{
+ if (gBattleTypeFlags & BATTLE_TYPE_LINK)
+ gBattleControllerExecFlags |= gBitTable[battlerId] << 0x1C;
+ else
+ gBattleControllerExecFlags |= gBitTable[battlerId];
+}
+
+void sub_8017298(u8 arg0)
+{
+ s32 i;
+
+ for (i = 0; i < GetLinkPlayerCount(); ++i)
+ gBattleControllerExecFlags |= gBitTable[arg0] << (i << 2);
+ gBattleControllerExecFlags &= ~(0x10000000 << arg0);
+}
+
+void CancelMultiTurnMoves(u8 battler)
+{
+ gBattleMons[battler].status2 &= ~(STATUS2_MULTIPLETURNS);
+ gBattleMons[battler].status2 &= ~(STATUS2_LOCK_CONFUSE);
+ gBattleMons[battler].status2 &= ~(STATUS2_UPROAR);
+ gBattleMons[battler].status2 &= ~(STATUS2_BIDE);
+ gStatuses3[battler] &= ~(STATUS3_SEMI_INVULNERABLE);
+ gDisableStructs[battler].rolloutTimer = 0;
+ gDisableStructs[battler].furyCutterCounter = 0;
+}
+
+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)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+void PrepareStringBattle(u16 stringId, u8 battler)
+{
+ gActiveBattler = battler;
+ BtlController_EmitPrintString(0, stringId);
+ MarkBattlerForControllerExec(gActiveBattler);
+}
+
+void ResetSentPokesToOpponentValue(void)
+{
+ s32 i;
+ u32 bits = 0;
+
+ gSentPokesToOpponent[0] = 0;
+ gSentPokesToOpponent[1] = 0;
+ for (i = 0; i < gBattlersCount; i += 2)
+ bits |= gBitTable[gBattlerPartyIndexes[i]];
+ for (i = 1; i < gBattlersCount; i += 2)
+ gSentPokesToOpponent[(i & BIT_FLANK) >> 1] = bits;
+}
+
+void sub_8017434(u8 battler)
+{
+ s32 i = 0;
+ u32 bits = 0;
+
+ if (GetBattlerSide(battler) == B_SIDE_OPPONENT)
+ {
+ u8 flank = ((battler & BIT_FLANK) >> 1);
+ gSentPokesToOpponent[flank] = 0;
+ for (i = 0; i < gBattlersCount; i += 2)
+ if (!(gAbsentBattlerFlags & gBitTable[i]))
+ bits |= gBitTable[gBattlerPartyIndexes[i]];
+ gSentPokesToOpponent[flank] = bits;
+ }
+}
+
+void sub_80174B8(u8 battler)
+{
+ if (GetBattlerSide(battler) == B_SIDE_OPPONENT)
+ {
+ sub_8017434(battler);
+ }
+ else
+ {
+ s32 i;
+
+ for (i = 1; i < gBattlersCount; ++i)
+ gSentPokesToOpponent[(i & BIT_FLANK) >> 1] |= gBitTable[gBattlerPartyIndexes[battler]];
+ }
+}
+
+void BattleScriptPush(const u8 *bsPtr)
+{
+ gBattleResources->battleScriptsStack->ptr[gBattleResources->battleScriptsStack->size++] = bsPtr;
+}
+
+void BattleScriptPushCursor(void)
+{
+ gBattleResources->battleScriptsStack->ptr[gBattleResources->battleScriptsStack->size++] = gBattlescriptCurrInstr;
+}
+
+void BattleScriptPop(void)
+{
+ gBattlescriptCurrInstr = gBattleResources->battleScriptsStack->ptr[--gBattleResources->battleScriptsStack->size];
+}
+
+u8 TrySetCantSelectMoveBattleScript(void)
+{
+ u8 holdEffect;
+ u8 limitations = 0;
+ u16 move = gBattleMons[gActiveBattler].moves[gBattleBufferB[gActiveBattler][2]];
+ u16* choicedMove = &gBattleStruct->choicedMove[gActiveBattler];
+
+ if (gDisableStructs[gActiveBattler].disabledMove == move && move != MOVE_NONE)
+ {
+ gBattleScripting.battler = gActiveBattler;
+ gCurrentMove = move;
+ gSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingDisabledMove;
+ limitations = 1;
+ }
+ if (move == gLastMoves[gActiveBattler] && move != MOVE_STRUGGLE && (gBattleMons[gActiveBattler].status2 & STATUS2_TORMENT))
+ {
+ CancelMultiTurnMoves(gActiveBattler);
+ gSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingTormentedMove;
+ ++limitations;
+ }
+ if (gDisableStructs[gActiveBattler].tauntTimer && !gBattleMoves[move].power)
+ {
+ gCurrentMove = move;
+ gSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingNotAllowedMoveTaunt;
+ ++limitations;
+ }
+ if (GetImprisonedMovesCount(gActiveBattler, move))
+ {
+ gCurrentMove = move;
+ gSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingImprisonedMove;
+ ++limitations;
+ }
+ if (gBattleMons[gActiveBattler].item == ITEM_ENIGMA_BERRY)
+ holdEffect = gEnigmaBerries[gActiveBattler].holdEffect;
+ else
+ holdEffect = ItemId_GetHoldEffect(gBattleMons[gActiveBattler].item);
+ gPotentialItemEffectBattler = gActiveBattler;
+ if (holdEffect == HOLD_EFFECT_CHOICE_BAND && *choicedMove && *choicedMove != 0xFFFF && *choicedMove != move)
+ {
+ gCurrentMove = *choicedMove;
+ gLastUsedItem = gBattleMons[gActiveBattler].item;
+ gSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingNotAllowedMoveChoiceItem;
+ ++limitations;
+ }
+ if (!gBattleMons[gActiveBattler].pp[gBattleBufferB[gActiveBattler][2]])
+ {
+ gSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingMoveWithNoPP;
+ ++limitations;
+ }
+ return limitations;
+}
+
+u8 CheckMoveLimitations(u8 battlerId, u8 unusableMoves, u8 check)
+{
+ u8 holdEffect;
+ u16 *choicedMove = &gBattleStruct->choicedMove[battlerId];
+ s32 i;
+
+ if (gBattleMons[battlerId].item == ITEM_ENIGMA_BERRY)
+ holdEffect = gEnigmaBerries[battlerId].holdEffect;
+ else
+ holdEffect = ItemId_GetHoldEffect(gBattleMons[battlerId].item);
+ gPotentialItemEffectBattler = battlerId;
+
+ for (i = 0; i < MAX_MON_MOVES; ++i)
+ {
+ if (gBattleMons[battlerId].moves[i] == 0 && check & MOVE_LIMITATION_ZEROMOVE)
+ unusableMoves |= gBitTable[i];
+ if (gBattleMons[battlerId].pp[i] == 0 && check & MOVE_LIMITATION_PP)
+ unusableMoves |= gBitTable[i];
+ if (gBattleMons[battlerId].moves[i] == gDisableStructs[battlerId].disabledMove && check & MOVE_LIMITATION_DISABLED)
+ unusableMoves |= gBitTable[i];
+ if (gBattleMons[battlerId].moves[i] == gLastMoves[battlerId] && check & MOVE_LIMITATION_TORMENTED && gBattleMons[battlerId].status2 & STATUS2_TORMENT)
+ unusableMoves |= gBitTable[i];
+ if (gDisableStructs[battlerId].tauntTimer && check & MOVE_LIMITATION_TAUNT && gBattleMoves[gBattleMons[battlerId].moves[i]].power == 0)
+ unusableMoves |= gBitTable[i];
+ if (GetImprisonedMovesCount(battlerId, gBattleMons[battlerId].moves[i]) && check & MOVE_LIMITATION_IMPRISON)
+ unusableMoves |= gBitTable[i];
+ if (gDisableStructs[battlerId].encoreTimer && gDisableStructs[battlerId].encoredMove != gBattleMons[battlerId].moves[i])
+ unusableMoves |= gBitTable[i];
+ if (holdEffect == HOLD_EFFECT_CHOICE_BAND && *choicedMove != 0 && *choicedMove != 0xFFFF && *choicedMove != gBattleMons[battlerId].moves[i])
+ unusableMoves |= gBitTable[i];
+ }
+ return unusableMoves;
+}
+
+bool8 AreAllMovesUnusable(void)
+{
+ u8 unusable = CheckMoveLimitations(gActiveBattler, 0, 0xFF);
+
+ if (unusable == 0xF) // All moves are unusable.
+ {
+ gProtectStructs[gActiveBattler].noValidMoves = 1;
+ gSelectionBattleScripts[gActiveBattler] = BattleScript_NoMovesLeft;
+ if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
+ gBattleBufferB[gActiveBattler][3] = GetBattlerAtPosition((BATTLE_OPPOSITE(GetBattlerPosition(gActiveBattler))) | (Random() & 2));
+ else
+ gBattleBufferB[gActiveBattler][3] = GetBattlerAtPosition(BATTLE_OPPOSITE(GetBattlerPosition(gActiveBattler)));
+ }
+ else
+ {
+ gProtectStructs[gActiveBattler].noValidMoves = 0;
+ }
+ return (unusable == 0xF);
+}
+
+u8 GetImprisonedMovesCount(u8 battlerId, u16 move)
+{
+ s32 i;
+ u8 imprisonedMoves = 0;
+ u8 battlerSide = GetBattlerSide(battlerId);
+
+ for (i = 0; i < gBattlersCount; ++i)
+ {
+ if (battlerSide != GetBattlerSide(i) && gStatuses3[i] & STATUS3_IMPRISONED_OTHERS)
+ {
+ s32 j;
+ for (j = 0; j < MAX_MON_MOVES && move != gBattleMons[i].moves[j]; ++j);
+ if (j < MAX_MON_MOVES)
+ ++imprisonedMoves;
+ }
+ }
+ return imprisonedMoves;
+}
+
+enum
+{
+ ENDTURN_ORDER,
+ ENDTURN_REFLECT,
+ ENDTURN_LIGHT_SCREEN,
+ ENDTURN_MIST,
+ ENDTURN_SAFEGUARD,
+ ENDTURN_WISH,
+ ENDTURN_RAIN,
+ ENDTURN_SANDSTORM,
+ ENDTURN_SUN,
+ ENDTURN_HAIL,
+ ENDTURN_FIELD_COUNT,
+};
+
+u8 DoFieldEndTurnEffects(void)
+{
+ u8 effect = 0;
+ s32 i;
+
+ for (gBattlerAttacker = 0; gBattlerAttacker < gBattlersCount && gAbsentBattlerFlags & gBitTable[gBattlerAttacker]; ++gBattlerAttacker);
+ for (gBattlerTarget = 0; gBattlerTarget < gBattlersCount && gAbsentBattlerFlags & gBitTable[gBattlerTarget]; ++gBattlerTarget);
+ do
+ {
+ u8 side;
+
+ switch (gBattleStruct->turnCountersTracker)
+ {
+ case ENDTURN_ORDER:
+ for (i = 0; i < gBattlersCount; ++i)
+ gBattlerByTurnOrder[i] = i;
+ for (i = 0; i < gBattlersCount - 1; ++i)
+ {
+ s32 j;
+
+ for (j = i + 1; j < gBattlersCount; ++j)
+ if (GetWhoStrikesFirst(gBattlerByTurnOrder[i], gBattlerByTurnOrder[j], 0))
+ SwapTurnOrder(i, j);
+ }
+ {
+ u8* var = &gBattleStruct->turnCountersTracker;
+
+ ++*var;
+ gBattleStruct->turnSideTracker = 0;
+ }
+ // fall through
+ case ENDTURN_REFLECT:
+ while (gBattleStruct->turnSideTracker < 2)
+ {
+ side = gBattleStruct->turnSideTracker;
+ gActiveBattler = gBattlerAttacker = gSideTimers[side].reflectBattlerId;
+ if (gSideStatuses[side] & SIDE_STATUS_REFLECT)
+ {
+ if (--gSideTimers[side].reflectTimer == 0)
+ {
+ gSideStatuses[side] &= ~SIDE_STATUS_REFLECT;
+ BattleScriptExecute(BattleScript_SideStatusWoreOff);
+ PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_REFLECT);
+ ++effect;
+ }
+ }
+ ++gBattleStruct->turnSideTracker;
+ if (effect)
+ break;
+ }
+ if (!effect)
+ {
+ ++gBattleStruct->turnCountersTracker;
+ gBattleStruct->turnSideTracker = 0;
+ }
+ break;
+ case ENDTURN_LIGHT_SCREEN:
+ while (gBattleStruct->turnSideTracker < 2)
+ {
+ side = gBattleStruct->turnSideTracker;
+ gActiveBattler = gBattlerAttacker = gSideTimers[side].lightscreenBattlerId;
+ if (gSideStatuses[side] & SIDE_STATUS_LIGHTSCREEN)
+ {
+ if (--gSideTimers[side].lightscreenTimer == 0)
+ {
+ gSideStatuses[side] &= ~SIDE_STATUS_LIGHTSCREEN;
+ BattleScriptExecute(BattleScript_SideStatusWoreOff);
+ gBattleCommunication[MULTISTRING_CHOOSER] = side;
+ PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_LIGHT_SCREEN);
+ ++effect;
+ }
+ }
+ ++gBattleStruct->turnSideTracker;
+ if (effect)
+ break;
+ }
+ if (!effect)
+ {
+ ++gBattleStruct->turnCountersTracker;
+ gBattleStruct->turnSideTracker = 0;
+ }
+ break;
+ case ENDTURN_MIST:
+ while (gBattleStruct->turnSideTracker < 2)
+ {
+ side = gBattleStruct->turnSideTracker;
+ gActiveBattler = gBattlerAttacker = gSideTimers[side].mistBattlerId;
+ if (gSideTimers[side].mistTimer != 0 && --gSideTimers[side].mistTimer == 0)
+ {
+ gSideStatuses[side] &= ~SIDE_STATUS_MIST;
+ BattleScriptExecute(BattleScript_SideStatusWoreOff);
+ gBattleCommunication[MULTISTRING_CHOOSER] = side;
+ PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_MIST);
+ ++effect;
+ }
+ ++gBattleStruct->turnSideTracker;
+ if (effect)
+ break;
+ }
+ if (!effect)
+ {
+ ++gBattleStruct->turnCountersTracker;
+ gBattleStruct->turnSideTracker = 0;
+ }
+ break;
+ case ENDTURN_SAFEGUARD:
+ while (gBattleStruct->turnSideTracker < 2)
+ {
+ side = gBattleStruct->turnSideTracker;
+ gActiveBattler = gBattlerAttacker = gSideTimers[side].safeguardBattlerId;
+ if (gSideStatuses[side] & SIDE_STATUS_SAFEGUARD)
+ {
+ if (--gSideTimers[side].safeguardTimer == 0)
+ {
+ gSideStatuses[side] &= ~SIDE_STATUS_SAFEGUARD;
+ BattleScriptExecute(BattleScript_SafeguardEnds);
+ ++effect;
+ }
+ }
+ ++gBattleStruct->turnSideTracker;
+ if (effect)
+ break;
+ }
+ if (!effect)
+ {
+ ++gBattleStruct->turnCountersTracker;
+ gBattleStruct->turnSideTracker = 0;
+ }
+ break;
+ case ENDTURN_WISH:
+ while (gBattleStruct->turnSideTracker < gBattlersCount)
+ {
+ gActiveBattler = gBattlerByTurnOrder[gBattleStruct->turnSideTracker];
+ if (gWishFutureKnock.wishCounter[gActiveBattler] != 0
+ && --gWishFutureKnock.wishCounter[gActiveBattler] == 0
+ && gBattleMons[gActiveBattler].hp != 0)
+ {
+ gBattlerTarget = gActiveBattler;
+ BattleScriptExecute(BattleScript_WishComesTrue);
+ ++effect;
+ }
+ ++gBattleStruct->turnSideTracker;
+ if (effect)
+ break;
+ }
+ if (!effect)
+ ++gBattleStruct->turnCountersTracker;
+ break;
+ case ENDTURN_RAIN:
+ if (gBattleWeather & WEATHER_RAIN_ANY)
+ {
+ if (!(gBattleWeather & WEATHER_RAIN_PERMANENT))
+ {
+ if (--gWishFutureKnock.weatherDuration == 0)
+ {
+ gBattleWeather &= ~WEATHER_RAIN_TEMPORARY;
+ gBattleWeather &= ~WEATHER_RAIN_DOWNPOUR;
+ gBattleCommunication[MULTISTRING_CHOOSER] = 2;
+ }
+ else if (gBattleWeather & WEATHER_RAIN_DOWNPOUR)
+ gBattleCommunication[MULTISTRING_CHOOSER] = 1;
+ else
+ gBattleCommunication[MULTISTRING_CHOOSER] = 0;
+ }
+ else if (gBattleWeather & WEATHER_RAIN_DOWNPOUR)
+ {
+ gBattleCommunication[MULTISTRING_CHOOSER] = 1;
+ }
+ else
+ {
+ gBattleCommunication[MULTISTRING_CHOOSER] = 0;
+ }
+ BattleScriptExecute(BattleScript_RainContinuesOrEnds);
+ ++effect;
+ }
+ ++gBattleStruct->turnCountersTracker;
+ break;
+ case ENDTURN_SANDSTORM:
+ if (gBattleWeather & WEATHER_SANDSTORM_ANY)
+ {
+ if (!(gBattleWeather & WEATHER_SANDSTORM_PERMANENT) && --gWishFutureKnock.weatherDuration == 0)
+ {
+ gBattleWeather &= ~WEATHER_SANDSTORM_TEMPORARY;
+ gBattlescriptCurrInstr = BattleScript_SandStormHailEnds;
+ }
+ else
+ {
+ gBattlescriptCurrInstr = BattleScript_DamagingWeatherContinues;
+ }
+ gBattleScripting.animArg1 = B_ANIM_SANDSTORM_CONTINUES;
+ gBattleCommunication[MULTISTRING_CHOOSER] = 0;
+ BattleScriptExecute(gBattlescriptCurrInstr);
+ ++effect;
+ }
+ ++gBattleStruct->turnCountersTracker;
+ break;
+ case ENDTURN_SUN:
+ if (gBattleWeather & WEATHER_SUN_ANY)
+ {
+ if (!(gBattleWeather & WEATHER_SUN_PERMANENT) && --gWishFutureKnock.weatherDuration == 0)
+ {
+ gBattleWeather &= ~WEATHER_SUN_TEMPORARY;
+ gBattlescriptCurrInstr = BattleScript_SunlightFaded;
+ }
+ else
+ {
+ gBattlescriptCurrInstr = BattleScript_SunlightContinues;
+ }
+ BattleScriptExecute(gBattlescriptCurrInstr);
+ ++effect;
+ }
+ ++gBattleStruct->turnCountersTracker;
+ break;
+ case ENDTURN_HAIL:
+ if (gBattleWeather & WEATHER_HAIL_ANY)
+ {
+ if (--gWishFutureKnock.weatherDuration == 0)
+ {
+ gBattleWeather &= ~WEATHER_HAIL;
+ gBattlescriptCurrInstr = BattleScript_SandStormHailEnds;
+ }
+ else
+ {
+ gBattlescriptCurrInstr = BattleScript_DamagingWeatherContinues;
+ }
+ gBattleScripting.animArg1 = B_ANIM_HAIL_CONTINUES;
+ gBattleCommunication[MULTISTRING_CHOOSER] = 1;
+ BattleScriptExecute(gBattlescriptCurrInstr);
+ ++effect;
+ }
+ ++gBattleStruct->turnCountersTracker;
+ break;
+ case ENDTURN_FIELD_COUNT:
+ ++effect;
+ break;
+ }
+ } while (!effect);
+ return (gBattleMainFunc != BattleTurnPassed);
+}
+
+enum
+{
+ ENDTURN_INGRAIN,
+ ENDTURN_ABILITIES,
+ ENDTURN_ITEMS1,
+ ENDTURN_LEECH_SEED,
+ ENDTURN_POISON,
+ ENDTURN_BAD_POISON,
+ ENDTURN_BURN,
+ ENDTURN_NIGHTMARES,
+ ENDTURN_CURSE,
+ ENDTURN_WRAP,
+ ENDTURN_UPROAR,
+ ENDTURN_THRASH,
+ ENDTURN_DISABLE,
+ ENDTURN_ENCORE,
+ ENDTURN_LOCK_ON,
+ ENDTURN_CHARGE,
+ ENDTURN_TAUNT,
+ ENDTURN_YAWN,
+ ENDTURN_ITEMS2,
+ ENDTURN_BATTLER_COUNT
+};
+
+u8 DoBattlerEndTurnEffects(void)
+{
+ u8 effect = 0;
+
+ gHitMarker |= (HITMARKER_GRUDGE | HITMARKER_x20);
+ while (gBattleStruct->turnEffectsBattlerId < gBattlersCount && gBattleStruct->turnEffectsTracker <= ENDTURN_BATTLER_COUNT)
+ {
+ gActiveBattler = gBattlerAttacker = gBattlerByTurnOrder[gBattleStruct->turnEffectsBattlerId];
+ if (gAbsentBattlerFlags & gBitTable[gActiveBattler])
+ {
+ ++gBattleStruct->turnEffectsBattlerId;
+ }
+ else
+ {
+ switch (gBattleStruct->turnEffectsTracker)
+ {
+ case ENDTURN_INGRAIN: // ingrain
+ if ((gStatuses3[gActiveBattler] & STATUS3_ROOTED)
+ && gBattleMons[gActiveBattler].hp != gBattleMons[gActiveBattler].maxHP
+ && gBattleMons[gActiveBattler].hp != 0)
+ {
+ gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 16;
+ if (gBattleMoveDamage == 0)
+ gBattleMoveDamage = 1;
+ gBattleMoveDamage *= -1;
+ BattleScriptExecute(BattleScript_IngrainTurnHeal);
+ ++effect;
+ }
+ ++gBattleStruct->turnEffectsTracker;
+ break;
+ case ENDTURN_ABILITIES: // end turn abilities
+ if (AbilityBattleEffects(ABILITYEFFECT_ENDTURN, gActiveBattler, 0, 0, 0))
+ ++effect;
+ ++gBattleStruct->turnEffectsTracker;
+ break;
+ case ENDTURN_ITEMS1: // item effects
+ if (ItemBattleEffects(1, gActiveBattler, FALSE))
+ ++effect;
+ ++gBattleStruct->turnEffectsTracker;
+ break;
+ case ENDTURN_ITEMS2: // item effects again
+ if (ItemBattleEffects(1, gActiveBattler, TRUE))
+ ++effect;
+ ++gBattleStruct->turnEffectsTracker;
+ break;
+ case ENDTURN_LEECH_SEED: // leech seed
+ if ((gStatuses3[gActiveBattler] & STATUS3_LEECHSEED)
+ && 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;
+ if (gBattleMoveDamage == 0)
+ gBattleMoveDamage = 1;
+ gBattleScripting.animArg1 = gBattlerTarget;
+ gBattleScripting.animArg2 = gBattlerAttacker;
+ BattleScriptExecute(BattleScript_LeechSeedTurnDrain);
+ ++effect;
+ }
+ ++gBattleStruct->turnEffectsTracker;
+ break;
+ case ENDTURN_POISON: // poison
+ if ((gBattleMons[gActiveBattler].status1 & STATUS1_POISON) && gBattleMons[gActiveBattler].hp != 0)
+ {
+ gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 8;
+ if (gBattleMoveDamage == 0)
+ gBattleMoveDamage = 1;
+ BattleScriptExecute(BattleScript_PoisonTurnDmg);
+ ++effect;
+ }
+ ++gBattleStruct->turnEffectsTracker;
+ break;
+ case ENDTURN_BAD_POISON: // toxic poison
+ if ((gBattleMons[gActiveBattler].status1 & STATUS1_TOXIC_POISON) && gBattleMons[gActiveBattler].hp != 0)
+ {
+ gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 16;
+ if (gBattleMoveDamage == 0)
+ gBattleMoveDamage = 1;
+ if ((gBattleMons[gActiveBattler].status1 & 0xF00) != 0xF00) // not 16 turns
+ gBattleMons[gActiveBattler].status1 += 0x100;
+ gBattleMoveDamage *= (gBattleMons[gActiveBattler].status1 & 0xF00) >> 8;
+ BattleScriptExecute(BattleScript_PoisonTurnDmg);
+ ++effect;
+ }
+ ++gBattleStruct->turnEffectsTracker;
+ break;
+ case ENDTURN_BURN: // burn
+ if ((gBattleMons[gActiveBattler].status1 & STATUS1_BURN) && gBattleMons[gActiveBattler].hp != 0)
+ {
+ gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 8;
+ if (gBattleMoveDamage == 0)
+ gBattleMoveDamage = 1;
+ BattleScriptExecute(BattleScript_BurnTurnDmg);
+ ++effect;
+ }
+ ++gBattleStruct->turnEffectsTracker;
+ break;
+ case ENDTURN_NIGHTMARES: // spooky nightmares
+ if ((gBattleMons[gActiveBattler].status2 & STATUS2_NIGHTMARE) && gBattleMons[gActiveBattler].hp != 0)
+ {
+ // R/S does not perform this sleep check, which causes the nightmare effect to
+ // persist even after the affected Pokemon has been awakened by Shed Skin.
+ if (gBattleMons[gActiveBattler].status1 & STATUS1_SLEEP)
+ {
+ gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 4;
+ if (gBattleMoveDamage == 0)
+ gBattleMoveDamage = 1;
+ BattleScriptExecute(BattleScript_NightmareTurnDmg);
+ ++effect;
+ }
+ else
+ {
+ gBattleMons[gActiveBattler].status2 &= ~STATUS2_NIGHTMARE;
+ }
+ }
+ ++gBattleStruct->turnEffectsTracker;
+ break;
+ case ENDTURN_CURSE: // curse
+ if ((gBattleMons[gActiveBattler].status2 & STATUS2_CURSED) && gBattleMons[gActiveBattler].hp != 0)
+ {
+ gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 4;
+ if (gBattleMoveDamage == 0)
+ gBattleMoveDamage = 1;
+ BattleScriptExecute(BattleScript_CurseTurnDmg);
+ ++effect;
+ }
+ ++gBattleStruct->turnEffectsTracker;
+ break;
+ case ENDTURN_WRAP: // wrap
+ if ((gBattleMons[gActiveBattler].status2 & STATUS2_WRAPPED) && gBattleMons[gActiveBattler].hp != 0)
+ {
+ gBattleMons[gActiveBattler].status2 -= 0x2000;
+ if (gBattleMons[gActiveBattler].status2 & STATUS2_WRAPPED) // damaged by wrap
+ {
+ gBattleScripting.animArg1 = *(gBattleStruct->wrappedMove + gActiveBattler * 2 + 0);
+ gBattleScripting.animArg2 = *(gBattleStruct->wrappedMove + gActiveBattler * 2 + 1);
+ gBattleTextBuff1[0] = B_BUFF_PLACEHOLDER_BEGIN;
+ gBattleTextBuff1[1] = B_BUFF_MOVE;
+ gBattleTextBuff1[2] = *(gBattleStruct->wrappedMove + gActiveBattler * 2 + 0);
+ gBattleTextBuff1[3] = *(gBattleStruct->wrappedMove + gActiveBattler * 2 + 1);
+ gBattleTextBuff1[4] = EOS;
+ gBattlescriptCurrInstr = BattleScript_WrapTurnDmg;
+ gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 16;
+ if (gBattleMoveDamage == 0)
+ gBattleMoveDamage = 1;
+ }
+ else // broke free
+ {
+ gBattleTextBuff1[0] = B_BUFF_PLACEHOLDER_BEGIN;
+ gBattleTextBuff1[1] = B_BUFF_MOVE;
+ gBattleTextBuff1[2] = *(gBattleStruct->wrappedMove + gActiveBattler * 2 + 0);
+ gBattleTextBuff1[3] = *(gBattleStruct->wrappedMove + gActiveBattler * 2 + 1);
+ gBattleTextBuff1[4] = EOS;
+ gBattlescriptCurrInstr = BattleScript_WrapEnds;
+ }
+ BattleScriptExecute(gBattlescriptCurrInstr);
+ ++effect;
+ }
+ ++gBattleStruct->turnEffectsTracker;
+ break;
+ case ENDTURN_UPROAR: // uproar
+ if (gBattleMons[gActiveBattler].status2 & STATUS2_UPROAR)
+ {
+ for (gBattlerAttacker = 0; gBattlerAttacker < gBattlersCount; ++gBattlerAttacker)
+ {
+ if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP)
+ && gBattleMons[gBattlerAttacker].ability != ABILITY_SOUNDPROOF)
+ {
+ gBattleMons[gBattlerAttacker].status1 &= ~(STATUS1_SLEEP);
+ gBattleMons[gBattlerAttacker].status2 &= ~(STATUS2_NIGHTMARE);
+ gBattleCommunication[MULTISTRING_CHOOSER] = 1;
+ BattleScriptExecute(BattleScript_MonWokeUpInUproar);
+ gActiveBattler = gBattlerAttacker;
+ BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBattler].status1);
+ MarkBattlerForControllerExec(gActiveBattler);
+ break;
+ }
+ }
+ if (gBattlerAttacker != gBattlersCount)
+ {
+ effect = 2; // a pokemon was awaken
+ break;
+ }
+ else
+ {
+ gBattlerAttacker = gActiveBattler;
+ gBattleMons[gActiveBattler].status2 -= 0x10; // uproar timer goes down
+ if (WasUnableToUseMove(gActiveBattler))
+ {
+ CancelMultiTurnMoves(gActiveBattler);
+ gBattleCommunication[MULTISTRING_CHOOSER] = 1;
+ }
+ else if (gBattleMons[gActiveBattler].status2 & STATUS2_UPROAR)
+ {
+ gBattleCommunication[MULTISTRING_CHOOSER] = 0;
+ gBattleMons[gActiveBattler].status2 |= STATUS2_MULTIPLETURNS;
+ }
+ else
+ {
+ gBattleCommunication[MULTISTRING_CHOOSER] = 1;
+ CancelMultiTurnMoves(gActiveBattler);
+ }
+ BattleScriptExecute(BattleScript_PrintUproarOverTurns);
+ effect = 1;
+ }
+ }
+ if (effect != 2)
+ ++gBattleStruct->turnEffectsTracker;
+ break;
+ case ENDTURN_THRASH: // thrash
+ if (gBattleMons[gActiveBattler].status2 & STATUS2_LOCK_CONFUSE)
+ {
+ gBattleMons[gActiveBattler].status2 -= 0x400;
+ if (WasUnableToUseMove(gActiveBattler))
+ CancelMultiTurnMoves(gActiveBattler);
+ else if (!(gBattleMons[gActiveBattler].status2 & STATUS2_LOCK_CONFUSE)
+ && (gBattleMons[gActiveBattler].status2 & STATUS2_MULTIPLETURNS))
+ {
+ gBattleMons[gActiveBattler].status2 &= ~(STATUS2_MULTIPLETURNS);
+ if (!(gBattleMons[gActiveBattler].status2 & STATUS2_CONFUSION))
+ {
+ gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_CONFUSION | MOVE_EFFECT_AFFECTS_USER;
+ SetMoveEffect(1, 0);
+ if (gBattleMons[gActiveBattler].status2 & STATUS2_CONFUSION)
+ BattleScriptExecute(BattleScript_ThrashConfuses);
+ ++effect;
+ }
+ }
+ }
+ ++gBattleStruct->turnEffectsTracker;
+ break;
+ case ENDTURN_DISABLE: // disable
+ if (gDisableStructs[gActiveBattler].disableTimer != 0)
+ {
+ s32 i;
+ for (i = 0; i < MAX_MON_MOVES; ++i)
+ {
+ if (gDisableStructs[gActiveBattler].disabledMove == gBattleMons[gActiveBattler].moves[i])
+ break;
+ }
+ if (i == MAX_MON_MOVES) // pokemon does not have the disabled move anymore
+ {
+ gDisableStructs[gActiveBattler].disabledMove = 0;
+ gDisableStructs[gActiveBattler].disableTimer = 0;
+ }
+ else if (--gDisableStructs[gActiveBattler].disableTimer == 0) // disable ends
+ {
+ gDisableStructs[gActiveBattler].disabledMove = 0;
+ BattleScriptExecute(BattleScript_DisabledNoMore);
+ ++effect;
+ }
+ }
+ ++gBattleStruct->turnEffectsTracker;
+ break;
+ case ENDTURN_ENCORE: // encore
+ if (gDisableStructs[gActiveBattler].encoreTimer != 0)
+ {
+ if (gBattleMons[gActiveBattler].moves[gDisableStructs[gActiveBattler].encoredMovePos] != gDisableStructs[gActiveBattler].encoredMove) // pokemon does not have the encored move anymore
+ {
+ gDisableStructs[gActiveBattler].encoredMove = 0;
+ gDisableStructs[gActiveBattler].encoreTimer = 0;
+ }
+ else if (--gDisableStructs[gActiveBattler].encoreTimer == 0
+ || gBattleMons[gActiveBattler].pp[gDisableStructs[gActiveBattler].encoredMovePos] == 0)
+ {
+ gDisableStructs[gActiveBattler].encoredMove = 0;
+ gDisableStructs[gActiveBattler].encoreTimer = 0;
+ BattleScriptExecute(BattleScript_EncoredNoMore);
+ ++effect;
+ }
+ }
+ ++gBattleStruct->turnEffectsTracker;
+ break;
+ case ENDTURN_LOCK_ON: // lock-on decrement
+ if (gStatuses3[gActiveBattler] & STATUS3_ALWAYS_HITS)
+ gStatuses3[gActiveBattler] -= 0x8;
+ ++gBattleStruct->turnEffectsTracker;
+ break;
+ case ENDTURN_CHARGE: // charge
+ if (gDisableStructs[gActiveBattler].chargeTimer && --gDisableStructs[gActiveBattler].chargeTimer == 0)
+ gStatuses3[gActiveBattler] &= ~STATUS3_CHARGED_UP;
+ ++gBattleStruct->turnEffectsTracker;
+ break;
+ case ENDTURN_TAUNT: // taunt
+ if (gDisableStructs[gActiveBattler].tauntTimer)
+ --gDisableStructs[gActiveBattler].tauntTimer;
+ ++gBattleStruct->turnEffectsTracker;
+ break;
+ case ENDTURN_YAWN: // yawn
+ if (gStatuses3[gActiveBattler] & STATUS3_YAWN)
+ {
+ gStatuses3[gActiveBattler] -= 0x800;
+ if (!(gStatuses3[gActiveBattler] & STATUS3_YAWN) && !(gBattleMons[gActiveBattler].status1 & STATUS1_ANY)
+ && gBattleMons[gActiveBattler].ability != ABILITY_VITAL_SPIRIT
+ && gBattleMons[gActiveBattler].ability != ABILITY_INSOMNIA && !UproarWakeUpCheck(gActiveBattler))
+ {
+ CancelMultiTurnMoves(gActiveBattler);
+ gBattleMons[gActiveBattler].status1 |= (Random() & 3) + 2;
+ BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBattler].status1);
+ MarkBattlerForControllerExec(gActiveBattler);
+ gEffectBattler = gActiveBattler;
+ BattleScriptExecute(BattleScript_YawnMakesAsleep);
+ ++effect;
+ }
+ }
+ ++gBattleStruct->turnEffectsTracker;
+ break;
+ case ENDTURN_BATTLER_COUNT: // done
+ gBattleStruct->turnEffectsTracker = 0;
+ ++gBattleStruct->turnEffectsBattlerId;
+ break;
+ }
+ if (effect)
+ return effect;
+ }
+ }
+ gHitMarker &= ~(HITMARKER_GRUDGE | HITMARKER_x20);
+ return 0;
+}
+
+bool8 HandleWishPerishSongOnTurnEnd(void)
+{
+ gHitMarker |= (HITMARKER_GRUDGE | HITMARKER_x20);
+ switch (gBattleStruct->wishPerishSongState)
+ {
+ case 0:
+ while (gBattleStruct->wishPerishSongBattlerId < gBattlersCount)
+ {
+ gActiveBattler = gBattleStruct->wishPerishSongBattlerId;
+ if (gAbsentBattlerFlags & gBitTable[gActiveBattler])
+ {
+ ++gBattleStruct->wishPerishSongBattlerId;
+ continue;
+ }
+ ++gBattleStruct->wishPerishSongBattlerId;
+ if (gWishFutureKnock.futureSightCounter[gActiveBattler] != 0
+ && --gWishFutureKnock.futureSightCounter[gActiveBattler] == 0
+ && gBattleMons[gActiveBattler].hp != 0)
+ {
+ if (gWishFutureKnock.futureSightMove[gActiveBattler] == MOVE_FUTURE_SIGHT)
+ gBattleCommunication[MULTISTRING_CHOOSER] = 0;
+ else
+ gBattleCommunication[MULTISTRING_CHOOSER] = 1;
+ PREPARE_MOVE_BUFFER(gBattleTextBuff1, gWishFutureKnock.futureSightMove[gActiveBattler]);
+ gBattlerTarget = gActiveBattler;
+ gBattlerAttacker = gWishFutureKnock.futureSightAttacker[gActiveBattler];
+ gBattleMoveDamage = gWishFutureKnock.futureSightDmg[gActiveBattler];
+ gSpecialStatuses[gBattlerTarget].dmg = 0xFFFF;
+ BattleScriptExecute(BattleScript_MonTookFutureAttack);
+ return TRUE;
+ }
+ }
+ {
+ u8 *state = &gBattleStruct->wishPerishSongState;
+
+ *state = 1;
+ gBattleStruct->wishPerishSongBattlerId = 0;
+ }
+ // fall through
+ case 1:
+ while (gBattleStruct->wishPerishSongBattlerId < gBattlersCount)
+ {
+ gActiveBattler = gBattlerAttacker = gBattlerByTurnOrder[gBattleStruct->wishPerishSongBattlerId];
+ if (gAbsentBattlerFlags & gBitTable[gActiveBattler])
+ {
+ ++gBattleStruct->wishPerishSongBattlerId;
+ continue;
+ }
+ ++gBattleStruct->wishPerishSongBattlerId;
+ if (gStatuses3[gActiveBattler] & STATUS3_PERISH_SONG)
+ {
+ PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff1, 1, gDisableStructs[gActiveBattler].perishSongTimer);
+ if (gDisableStructs[gActiveBattler].perishSongTimer == 0)
+ {
+ gStatuses3[gActiveBattler] &= ~STATUS3_PERISH_SONG;
+ gBattleMoveDamage = gBattleMons[gActiveBattler].hp;
+ gBattlescriptCurrInstr = BattleScript_PerishSongTakesLife;
+ }
+ else
+ {
+ --gDisableStructs[gActiveBattler].perishSongTimer;
+ gBattlescriptCurrInstr = BattleScript_PerishSongCountGoesDown;
+ }
+ BattleScriptExecute(gBattlescriptCurrInstr);
+ return TRUE;
+ }
+ }
+ break;
+ }
+ gHitMarker &= ~(HITMARKER_GRUDGE | HITMARKER_x20);
+ return FALSE;
+}
+
+#define FAINTED_ACTIONS_MAX_CASE 7
+
+bool8 HandleFaintedMonActions(void)
+{
+ if (gBattleTypeFlags & BATTLE_TYPE_SAFARI)
+ return FALSE;
+ do
+ {
+ s32 i;
+ switch (gBattleStruct->faintedActionsState)
+ {
+ case 0:
+ gBattleStruct->faintedActionsBattlerId = 0;
+ ++gBattleStruct->faintedActionsState;
+ for (i = 0; i < gBattlersCount; ++i)
+ {
+ if (gAbsentBattlerFlags & gBitTable[i] && !HasNoMonsToSwitch(i, 6, 6))
+ gAbsentBattlerFlags &= ~(gBitTable[i]);
+ }
+ // fall through
+ case 1:
+ do
+ {
+ gBattlerFainted = gBattlerTarget = gBattleStruct->faintedActionsBattlerId;
+ if (gBattleMons[gBattleStruct->faintedActionsBattlerId].hp == 0
+ && !(gBattleStruct->givenExpMons & gBitTable[gBattlerPartyIndexes[gBattleStruct->faintedActionsBattlerId]])
+ && !(gAbsentBattlerFlags & gBitTable[gBattleStruct->faintedActionsBattlerId]))
+ {
+ BattleScriptExecute(BattleScript_GiveExp);
+ gBattleStruct->faintedActionsState = 2;
+ return TRUE;
+ }
+ } while (++gBattleStruct->faintedActionsBattlerId != gBattlersCount);
+ gBattleStruct->faintedActionsState = 3;
+ break;
+ case 2:
+ sub_8017434(gBattlerFainted);
+ if (++gBattleStruct->faintedActionsBattlerId == gBattlersCount)
+ gBattleStruct->faintedActionsState = 3;
+ else
+ gBattleStruct->faintedActionsState = 1;
+ break;
+ case 3:
+ gBattleStruct->faintedActionsBattlerId = 0;
+ ++gBattleStruct->faintedActionsState;
+ // fall through
+ case 4:
+ do
+ {
+ gBattlerFainted = gBattlerTarget = gBattleStruct->faintedActionsBattlerId;
+ if (gBattleMons[gBattleStruct->faintedActionsBattlerId].hp == 0
+ && !(gAbsentBattlerFlags & gBitTable[gBattleStruct->faintedActionsBattlerId]))
+ {
+ BattleScriptExecute(BattleScript_HandleFaintedMon);
+ gBattleStruct->faintedActionsState = 5;
+ return TRUE;
+ }
+ } while (++gBattleStruct->faintedActionsBattlerId != gBattlersCount);
+ gBattleStruct->faintedActionsState = 6;
+ break;
+ case 5:
+ if (++gBattleStruct->faintedActionsBattlerId == gBattlersCount)
+ gBattleStruct->faintedActionsState = 6;
+ else
+ gBattleStruct->faintedActionsState = 4;
+ break;
+ case 6:
+ if (AbilityBattleEffects(ABILITYEFFECT_INTIMIDATE1, 0, 0, 0, 0) || AbilityBattleEffects(ABILITYEFFECT_TRACE, 0, 0, 0, 0) || ItemBattleEffects(1, 0, TRUE) || AbilityBattleEffects(ABILITYEFFECT_FORECAST, 0, 0, 0, 0))
+ return TRUE;
+ ++gBattleStruct->faintedActionsState;
+ break;
+ case FAINTED_ACTIONS_MAX_CASE:
+ break;
+ }
+ } while (gBattleStruct->faintedActionsState != FAINTED_ACTIONS_MAX_CASE);
+ return FALSE;
+}
diff --git a/src/battle_util2.c b/src/battle_util2.c
index 83014a83b..6a3f3525b 100644
--- a/src/battle_util2.c
+++ b/src/battle_util2.c
@@ -19,10 +19,7 @@ void AllocateBattleResources(void)
*ptr++ = AllocZeroed(8);
while (--i >= 0);
}
- // TODO: Figure out whether 0x200 is really the size of *gBattleStruct.
- // The following works in pokeem:
- // gBattleStruct = AllocZeroed(sizeof(*gBattleStruct));
- gBattleStruct = AllocZeroed(0x200);
+ gBattleStruct = AllocZeroed(sizeof(*gBattleStruct));
gBattleResources = AllocZeroed(sizeof(*gBattleResources));
gBattleResources->secretBase = AllocZeroed(sizeof(*gBattleResources->secretBase));
gBattleResources->flags = AllocZeroed(sizeof(*gBattleResources->flags));
diff --git a/src/pokemon.c b/src/pokemon.c
index d75650d91..615bf55f1 100644
--- a/src/pokemon.c
+++ b/src/pokemon.c
@@ -2552,7 +2552,7 @@ s32 CalculateBaseDamage(struct BattlePokemon *attacker, struct BattlePokemon *de
damage /= 2;
// sunny
- if (gBattleWeather & WEATHER_SUNNY_ANY)
+ if (gBattleWeather & WEATHER_SUN_ANY)
{
switch (type)
{
@@ -4117,14 +4117,14 @@ bool8 PokemonUseItemEffects(struct Pokemon *pkmn, u16 item, u8 partyIndex, u8 mo
{
gAbsentBattlerFlags &= ~gBitTable[sp34];
CopyPlayerPartyMonToBattleData(sp34, pokemon_order_func(gBattlerPartyIndexes[sp34]));
- if (GetBattlerSide(gActiveBattler) == 0 && gBattleResults.unk4 < 255)
- gBattleResults.unk4++;
+ if (GetBattlerSide(gActiveBattler) == 0 && gBattleResults.numRevivesUsed < 255)
+ gBattleResults.numRevivesUsed++;
}
else
{
gAbsentBattlerFlags &= ~gBitTable[gActiveBattler ^ 2];
- if (GetBattlerSide(gActiveBattler) == 0 && gBattleResults.unk4 < 255)
- gBattleResults.unk4++;
+ if (GetBattlerSide(gActiveBattler) == 0 && gBattleResults.numRevivesUsed < 255)
+ gBattleResults.numRevivesUsed++;
}
}
}
@@ -4164,8 +4164,8 @@ bool8 PokemonUseItemEffects(struct Pokemon *pkmn, u16 item, u8 partyIndex, u8 mo
gBattleMons[sp34].hp = data;
if (!(r10 & 0x10) && GetBattlerSide(gActiveBattler) == 0)
{
- if (gBattleResults.unk3 < 255)
- gBattleResults.unk3++;
+ if (gBattleResults.numHealingItemsUsed < 255)
+ gBattleResults.numHealingItemsUsed++;
// I have to re-use this variable to match.
r5 = gActiveBattler;
gActiveBattler = sp34;
@@ -4204,7 +4204,7 @@ bool8 PokemonUseItemEffects(struct Pokemon *pkmn, u16 item, u8 partyIndex, u8 mo
SetMonData(pkmn, MON_DATA_PP1 + r5, &data);
if (gMain.inBattle
&& sp34 != 4 && !(gBattleMons[sp34].status2 & 0x200000)
- && !(gDisableStructs[sp34].unk18_b & gBitTable[r5]))
+ && !(gDisableStructs[sp34].mimickedMoves & gBitTable[r5]))
gBattleMons[sp34].pp[r5] = data;
retVal = FALSE;
}
@@ -4229,7 +4229,7 @@ bool8 PokemonUseItemEffects(struct Pokemon *pkmn, u16 item, u8 partyIndex, u8 mo
SetMonData(pkmn, MON_DATA_PP1 + moveIndex, &data);
if (gMain.inBattle
&& sp34 != 4 && !(gBattleMons[sp34].status2 & 0x200000)
- && !(gDisableStructs[sp34].unk18_b & gBitTable[moveIndex]))
+ && !(gDisableStructs[sp34].mimickedMoves & gBitTable[moveIndex]))
gBattleMons[sp34].pp[moveIndex] = data;
retVal = FALSE;
}