mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-12-27 04:04:17 +01:00
3455 lines
140 KiB
C
3455 lines
140 KiB
C
#include "global.h"
|
|
#include "battle.h"
|
|
#include "constants/battle_script_commands.h"
|
|
#include "constants/abilities.h"
|
|
#include "constants/moves.h"
|
|
#include "constants/hold_effects.h"
|
|
#include "constants/battle_anim.h"
|
|
#include "pokemon.h"
|
|
#include "constants/species.h"
|
|
#include "item.h"
|
|
#include "constants/items.h"
|
|
#include "util.h"
|
|
#include "constants/battle_move_effects.h"
|
|
#include "battle_scripts.h"
|
|
#include "random.h"
|
|
#include "text.h"
|
|
#include "string_util.h"
|
|
#include "battle_message.h"
|
|
#include "constants/battle_string_ids.h"
|
|
#include "battle_ai_script_commands.h"
|
|
#include "battle_controllers.h"
|
|
#include "event_data.h"
|
|
#include "link.h"
|
|
#include "berry.h"
|
|
|
|
extern u8 weather_get_current(void);
|
|
|
|
// rom const data
|
|
static 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)
|
|
{
|
|
u8 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 4:
|
|
case 6:
|
|
case 8:
|
|
case 9:
|
|
case BS_PLAYER1:
|
|
ret = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
|
|
break;
|
|
case BS_OPPONENT1:
|
|
ret = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
|
|
break;
|
|
case BS_PLAYER2:
|
|
ret = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT);
|
|
break;
|
|
case BS_OPPONENT2:
|
|
ret = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT);
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void PressurePPLose(u8 defender, u8 attacker, u16 move)
|
|
{
|
|
s32 i;
|
|
|
|
if (gBattleMons[defender].ability != ABILITY_PRESSURE)
|
|
return;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if (gBattleMons[attacker].moves[i] == move)
|
|
break;
|
|
}
|
|
|
|
if (i == 4) // mons don't share any moves
|
|
return;
|
|
|
|
if (gBattleMons[attacker].pp[i] != 0)
|
|
gBattleMons[attacker].pp[i]--;
|
|
|
|
if (!(gBattleMons[attacker].status2 & STATUS2_TRANSFORMED)
|
|
&& !(gDisableStructs[attacker].unk18_b & gBitTable[i]))
|
|
{
|
|
gActiveBattler = attacker;
|
|
BtlController_EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + i, 0, 1, &gBattleMons[gActiveBattler].pp[i]);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
}
|
|
|
|
void PressurePPLoseOnUsingImprision(u8 attacker)
|
|
{
|
|
s32 i, j;
|
|
s32 imprisionPos = 4;
|
|
u8 atkSide = GetBattlerSide(attacker);
|
|
|
|
for (i = 0; i < gBattlersCount; i++)
|
|
{
|
|
if (atkSide != GetBattlerSide(i) && gBattleMons[i].ability == ABILITY_PRESSURE)
|
|
{
|
|
for (j = 0; j < 4; j++)
|
|
{
|
|
if (gBattleMons[attacker].moves[j] == MOVE_IMPRISON)
|
|
break;
|
|
}
|
|
if (j != 4)
|
|
{
|
|
imprisionPos = j;
|
|
if (gBattleMons[attacker].pp[j] != 0)
|
|
gBattleMons[attacker].pp[j]--;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (imprisionPos != 4
|
|
&& !(gBattleMons[attacker].status2 & STATUS2_TRANSFORMED)
|
|
&& !(gDisableStructs[attacker].unk18_b & gBitTable[imprisionPos]))
|
|
{
|
|
gActiveBattler = attacker;
|
|
BtlController_EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + imprisionPos, 0, 1, &gBattleMons[gActiveBattler].pp[imprisionPos]);
|
|
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 < 4; j++)
|
|
{
|
|
if (gBattleMons[attacker].moves[j] == MOVE_PERISH_SONG)
|
|
break;
|
|
}
|
|
if (j != 4)
|
|
{
|
|
perishSongPos = j;
|
|
if (gBattleMons[attacker].pp[j] != 0)
|
|
gBattleMons[attacker].pp[j]--;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (perishSongPos != 4
|
|
&& !(gBattleMons[attacker].status2 & STATUS2_TRANSFORMED)
|
|
&& !(gDisableStructs[attacker].unk18_b & gBitTable[perishSongPos]))
|
|
{
|
|
gActiveBattler = attacker;
|
|
BtlController_EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + perishSongPos, 0, 1, &gBattleMons[gActiveBattler].pp[perishSongPos]);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
}
|
|
}
|
|
|
|
void MarkAllBattlersForControllerExec(void) // unused
|
|
{
|
|
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_803F850(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].rolloutCounter1 = 0;
|
|
gDisableStructs[battler].furyCutterCounter = 0;
|
|
}
|
|
|
|
bool8 WasUnableToUseMove(u8 battler)
|
|
{
|
|
if (gProtectStructs[battler].prlzImmobility
|
|
|| gProtectStructs[battler].targetNotAffected
|
|
|| gProtectStructs[battler].usedImprisionedMove
|
|
|| 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_803F9EC(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_803FA70(u8 battler)
|
|
{
|
|
if (GetBattlerSide(battler) == B_SIDE_OPPONENT)
|
|
{
|
|
sub_803F9EC(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 limitations = 0;
|
|
u16 move = gBattleMons[gActiveBattler].moves[gBattleBufferB[gActiveBattler][2]];
|
|
u8 holdEffect;
|
|
u16* choicedMove = &gBattleStruct->choicedMove[gActiveBattler];
|
|
|
|
if (gDisableStructs[gActiveBattler].disabledMove == move && move != 0)
|
|
{
|
|
gBattleScripting.battler = gActiveBattler;
|
|
gCurrentMove = move;
|
|
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
|
|
{
|
|
gPalaceSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingDisabledMoveInPalace;
|
|
gProtectStructs[gActiveBattler].flag_x10 = 1;
|
|
}
|
|
else
|
|
{
|
|
gSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingDisabledMove;
|
|
limitations = 1;
|
|
}
|
|
}
|
|
|
|
if (move == gLastMoves[gActiveBattler] && move != MOVE_STRUGGLE && (gBattleMons[gActiveBattler].status2 & STATUS2_TORMENT))
|
|
{
|
|
CancelMultiTurnMoves(gActiveBattler);
|
|
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
|
|
{
|
|
gPalaceSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingTormentedMoveInPalace;
|
|
gProtectStructs[gActiveBattler].flag_x10 = 1;
|
|
}
|
|
else
|
|
{
|
|
gSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingTormentedMove;
|
|
limitations++;
|
|
}
|
|
}
|
|
|
|
if (gDisableStructs[gActiveBattler].tauntTimer1 != 0 && gBattleMoves[move].power == 0)
|
|
{
|
|
gCurrentMove = move;
|
|
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
|
|
{
|
|
gPalaceSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingNotAllowedMoveTauntInPalace;
|
|
gProtectStructs[gActiveBattler].flag_x10 = 1;
|
|
}
|
|
else
|
|
{
|
|
gSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingNotAllowedMoveTaunt;
|
|
limitations++;
|
|
}
|
|
}
|
|
|
|
if (GetImprisonedMovesCount(gActiveBattler, move))
|
|
{
|
|
gCurrentMove = move;
|
|
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
|
|
{
|
|
gPalaceSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingImprisionedMoveInPalace;
|
|
gProtectStructs[gActiveBattler].flag_x10 = 1;
|
|
}
|
|
else
|
|
{
|
|
gSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingImprisionedMove;
|
|
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 != 0 && *choicedMove != 0xFFFF && *choicedMove != move)
|
|
{
|
|
gCurrentMove = *choicedMove;
|
|
gLastUsedItem = gBattleMons[gActiveBattler].item;
|
|
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
|
|
{
|
|
gProtectStructs[gActiveBattler].flag_x10 = 1;
|
|
}
|
|
else
|
|
{
|
|
gSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingNotAllowedMoveChoiceItem;
|
|
limitations++;
|
|
}
|
|
}
|
|
|
|
if (gBattleMons[gActiveBattler].pp[gBattleBufferB[gActiveBattler][2]] == 0)
|
|
{
|
|
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
|
|
{
|
|
gProtectStructs[gActiveBattler].flag_x10 = 1;
|
|
}
|
|
else
|
|
{
|
|
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 < 4; 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].tauntTimer1 && check & MOVE_LIMITATION_TAUNT && gBattleMoves[gBattleMons[battlerId].moves[i]].power == 0)
|
|
unusableMoves |= gBitTable[i];
|
|
if (GetImprisonedMovesCount(battlerId, gBattleMons[battlerId].moves[i]) && check & MOVE_LIMITATION_IMPRISION)
|
|
unusableMoves |= gBitTable[i];
|
|
if (gDisableStructs[battlerId].encoreTimer1 && 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;
|
|
unusable = CheckMoveLimitations(gActiveBattler, 0, 0xFF);
|
|
|
|
if (unusable == 0xF) // All moves are unusable.
|
|
{
|
|
gProtectStructs[gActiveBattler].noValidMoves = 1;
|
|
gSelectionBattleScripts[gActiveBattler] = BattleScript_NoMovesLeft;
|
|
}
|
|
else
|
|
{
|
|
gProtectStructs[gActiveBattler].noValidMoves = 0;
|
|
}
|
|
|
|
return (unusable == 0xF);
|
|
}
|
|
|
|
u8 GetImprisonedMovesCount(u8 battlerId, u16 move)
|
|
{
|
|
s32 i;
|
|
u8 imprisionedMoves = 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 < 4; j++)
|
|
{
|
|
if (move == gBattleMons[i].moves[j])
|
|
break;
|
|
}
|
|
if (j < 4)
|
|
imprisionedMoves++;
|
|
}
|
|
}
|
|
|
|
return imprisionedMoves;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
// It's stupid, but won't match without it
|
|
{
|
|
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 == 0);
|
|
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
|
|
{
|
|
// This is the only way I could get this array access to match.
|
|
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].disableTimer1 != 0)
|
|
{
|
|
s32 i;
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if (gDisableStructs[gActiveBattler].disabledMove == gBattleMons[gActiveBattler].moves[i])
|
|
break;
|
|
}
|
|
if (i == 4) // pokemon does not have the disabled move anymore
|
|
{
|
|
gDisableStructs[gActiveBattler].disabledMove = 0;
|
|
gDisableStructs[gActiveBattler].disableTimer1 = 0;
|
|
}
|
|
else if (--gDisableStructs[gActiveBattler].disableTimer1 == 0) // disable ends
|
|
{
|
|
gDisableStructs[gActiveBattler].disabledMove = 0;
|
|
BattleScriptExecute(BattleScript_DisabledNoMore);
|
|
effect++;
|
|
}
|
|
}
|
|
gBattleStruct->turnEffectsTracker++;
|
|
break;
|
|
case ENDTURN_ENCORE: // encore
|
|
if (gDisableStructs[gActiveBattler].encoreTimer1 != 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].encoreTimer1 = 0;
|
|
}
|
|
else if (--gDisableStructs[gActiveBattler].encoreTimer1 == 0
|
|
|| gBattleMons[gActiveBattler].pp[gDisableStructs[gActiveBattler].encoredMovePos] == 0)
|
|
{
|
|
gDisableStructs[gActiveBattler].encoredMove = 0;
|
|
gDisableStructs[gActiveBattler].encoreTimer1 = 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].chargeTimer1 && --gDisableStructs[gActiveBattler].chargeTimer1 == 0)
|
|
gStatuses3[gActiveBattler] &= ~STATUS3_CHARGED_UP;
|
|
gBattleStruct->turnEffectsTracker++;
|
|
break;
|
|
case ENDTURN_TAUNT: // taunt
|
|
if (gDisableStructs[gActiveBattler].tauntTimer1)
|
|
gDisableStructs[gActiveBattler].tauntTimer1--;
|
|
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 != 0)
|
|
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);
|
|
|
|
if (gWishFutureKnock.futureSightCounter[gActiveBattler] == 0
|
|
&& gWishFutureKnock.futureSightCounter[gActiveBattler ^ BIT_FLANK] == 0)
|
|
{
|
|
gSideStatuses[GET_BATTLER_SIDE(gBattlerTarget)] &= ~(SIDE_STATUS_FUTUREATTACK);
|
|
}
|
|
return TRUE;
|
|
}
|
|
}
|
|
// Why do I have to keep doing this to match?
|
|
{
|
|
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].perishSongTimer1);
|
|
if (gDisableStructs[gActiveBattler].perishSongTimer1 == 0)
|
|
{
|
|
gStatuses3[gActiveBattler] &= ~STATUS3_PERISH_SONG;
|
|
gBattleMoveDamage = gBattleMons[gActiveBattler].hp;
|
|
gBattlescriptCurrInstr = BattleScript_PerishSongTakesLife;
|
|
}
|
|
else
|
|
{
|
|
gDisableStructs[gActiveBattler].perishSongTimer1--;
|
|
gBattlescriptCurrInstr = BattleScript_PerishSongCountGoesDown;
|
|
}
|
|
BattleScriptExecute(gBattlescriptCurrInstr);
|
|
return TRUE;
|
|
}
|
|
}
|
|
// Hm...
|
|
{
|
|
u8 *state = &gBattleStruct->wishPerishSongState;
|
|
*state = 2;
|
|
gBattleStruct->wishPerishSongBattlerId = 0;
|
|
}
|
|
// fall through
|
|
case 2:
|
|
if ((gBattleTypeFlags & BATTLE_TYPE_ARENA)
|
|
&& gBattleStruct->field_DA == 2
|
|
&& gBattleMons[0].hp != 0 && gBattleMons[1].hp != 0)
|
|
{
|
|
s32 i;
|
|
|
|
for (i = 0; i < 2; i++)
|
|
CancelMultiTurnMoves(i);
|
|
|
|
gBattlescriptCurrInstr = BattleScript_82DB8F3;
|
|
BattleScriptExecute(BattleScript_82DB8F3);
|
|
gBattleStruct->wishPerishSongState++;
|
|
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->field_DF & 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_803F9EC(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;
|
|
}
|
|
|
|
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_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].rechargeCounter = 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].tauntTimer1 && 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].usedImprisionedMove = 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;
|
|
// This is removed in Emerald for some reason
|
|
//CancelMultiTurnMoves(gBattlerAttacker);
|
|
gBattlescriptCurrInstr = BattleScript_MoveUsedIsParalyzed;
|
|
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
|
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_MoveUsedIsParalyzedCantAttack);
|
|
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
|
|
{
|
|
// This is removed in Emerald for some reason
|
|
//gBattleMons[gBattlerAttacker].status2 &= ~(STATUS2_MULTIPLETURNS);
|
|
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 == 0);
|
|
|
|
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)
|
|
{
|
|
struct Pokemon *party;
|
|
u8 id1, id2;
|
|
s32 i;
|
|
|
|
if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE))
|
|
return FALSE;
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
|
|
{
|
|
if (GetBattlerSide(battler) == B_SIDE_PLAYER)
|
|
party = gPlayerParty;
|
|
else
|
|
party = gEnemyParty;
|
|
|
|
id1 = ((battler & BIT_FLANK) / 2);
|
|
for (i = id1 * 3; i < id1 * 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 == id1 * 3 + 3);
|
|
}
|
|
else if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
|
|
{
|
|
if (gBattleTypeFlags & BATTLE_TYPE_x800000)
|
|
{
|
|
if (GetBattlerSide(battler) == B_SIDE_PLAYER)
|
|
{
|
|
party = gPlayerParty;
|
|
id2 = GetBattlerMultiplayerId(battler);
|
|
id1 = GetLinkTrainerFlankId(id2);
|
|
}
|
|
else
|
|
{
|
|
// FIXME: Compiler insists on moving r4 into r1 before doing the eor.
|
|
#ifndef NONMATCHING
|
|
register u32 var asm("r1");
|
|
#else
|
|
u32 var;
|
|
#endif // NONMATCHING
|
|
|
|
party = gEnemyParty;
|
|
var = battler ^ BIT_SIDE;
|
|
if (var == 0)
|
|
id1 = 0;
|
|
else
|
|
id1 = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
id2 = GetBattlerMultiplayerId(battler);
|
|
|
|
if (GetBattlerSide(battler) == B_SIDE_PLAYER)
|
|
party = gPlayerParty;
|
|
else
|
|
party = gEnemyParty;
|
|
|
|
id1 = GetLinkTrainerFlankId(id2);
|
|
}
|
|
|
|
for (i = id1 * 3; i < id1 * 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 == id1 * 3 + 3);
|
|
}
|
|
else if ((gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) && GetBattlerSide(battler) == B_SIDE_OPPONENT)
|
|
{
|
|
party = gEnemyParty;
|
|
|
|
if (battler == 1)
|
|
id1 = 0;
|
|
else
|
|
id1 = 3;
|
|
|
|
for (i = id1; i < id1 + 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 == id1 + 3);
|
|
}
|
|
else
|
|
{
|
|
if (GetBattlerSide(battler) == B_SIDE_OPPONENT)
|
|
{
|
|
id2 = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
|
|
id1 = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT);
|
|
party = gEnemyParty;
|
|
}
|
|
else
|
|
{
|
|
id2 = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
|
|
id1 = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT);
|
|
party = gPlayerParty;
|
|
}
|
|
|
|
if (partyIdBattlerOn1 == PARTY_SIZE)
|
|
partyIdBattlerOn1 = gBattlerPartyIndexes[id2];
|
|
if (partyIdBattlerOn2 == PARTY_SIZE)
|
|
partyIdBattlerOn2 = gBattlerPartyIndexes[id1];
|
|
|
|
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 + id2) && i != id1[gBattleStruct->monToSwitchIntoId])
|
|
break;
|
|
}
|
|
return (i == PARTY_SIZE);
|
|
}
|
|
}
|
|
|
|
enum
|
|
{
|
|
CASTFORM_NO_CHANGE, //0
|
|
CASTFORM_TO_NORMAL, //1
|
|
CASTFORM_TO_FIRE, //2
|
|
CASTFORM_TO_WATER, //3
|
|
CASTFORM_TO_ICE, //4
|
|
};
|
|
|
|
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;
|
|
}
|
|
|
|
// The largest function in the game, but even it could not save itself from decompiling.
|
|
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;
|
|
u16 move;
|
|
u8 side;
|
|
u8 target1;
|
|
|
|
if (special)
|
|
gLastUsedAbility = special;
|
|
else
|
|
gLastUsedAbility = gBattleMons[battler].ability;
|
|
|
|
if (moveArg)
|
|
move = moveArg;
|
|
else
|
|
move = gCurrentMove;
|
|
|
|
GET_MOVE_TYPE(move, moveType);
|
|
|
|
switch (caseID)
|
|
{
|
|
case ABILITYEFFECT_ON_SWITCHIN: // 0
|
|
if (gBattlerAttacker >= gBattlersCount)
|
|
gBattlerAttacker = battler;
|
|
switch (gLastUsedAbility)
|
|
{
|
|
case ABILITYEFFECT_SWITCH_IN_WEATHER:
|
|
if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED))
|
|
{
|
|
switch (weather_get_current())
|
|
{
|
|
case 3:
|
|
case 5:
|
|
case 13:
|
|
if (!(gBattleWeather & WEATHER_RAIN_ANY))
|
|
{
|
|
gBattleWeather = (WEATHER_RAIN_TEMPORARY | WEATHER_RAIN_PERMANENT);
|
|
gBattleScripting.animArg1 = B_ANIM_RAIN_CONTINUES;
|
|
gBattleScripting.battler = battler;
|
|
effect++;
|
|
}
|
|
break;
|
|
case 8:
|
|
if (!(gBattleWeather & WEATHER_SANDSTORM_ANY))
|
|
{
|
|
gBattleWeather = (WEATHER_SANDSTORM_PERMANENT | WEATHER_SANDSTORM_TEMPORARY);
|
|
gBattleScripting.animArg1 = B_ANIM_SANDSTORM_CONTINUES;
|
|
gBattleScripting.battler = battler;
|
|
effect++;
|
|
}
|
|
break;
|
|
case 12:
|
|
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] = weather_get_current();
|
|
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:
|
|
{
|
|
// that's a weird choice for a variable, why not use i or battler?
|
|
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] == move)
|
|
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 (move)
|
|
{
|
|
switch (gLastUsedAbility)
|
|
{
|
|
case ABILITY_VOLT_ABSORB:
|
|
if (moveType == TYPE_ELECTRIC && gBattleMoves[move].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[move].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] & UNKNOWN_FLAG_FLASH_FIRE))
|
|
{
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
if (gProtectStructs[gBattlerAttacker].notFirstStrike)
|
|
gBattlescriptCurrInstr = BattleScript_FlashFireBoost;
|
|
else
|
|
gBattlescriptCurrInstr = BattleScript_FlashFireBoost_PPLoss;
|
|
|
|
gBattleResources->flags->flags[battler] |= UNKNOWN_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)
|
|
&& move != MOVE_STRUGGLE
|
|
&& gBattleMoves[move].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[move].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[move].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[move].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[move].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[move].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[move].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
|
|
for (i = 0; i < gBattlersCount; i++)
|
|
{
|
|
if (gBattleMons[i].ability == ability && 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;
|
|
}
|
|
|
|
void BattleScriptExecute(const u8 *BS_ptr)
|
|
{
|
|
gBattlescriptCurrInstr = BS_ptr;
|
|
gBattleResources->battleCallbackStack->function[gBattleResources->battleCallbackStack->size++] = gBattleMainFunc;
|
|
gBattleMainFunc = RunBattleScriptCommands_PopCallbacksStack;
|
|
gCurrentActionFuncId = 0;
|
|
}
|
|
|
|
void BattleScriptPushCursorAndCallback(const u8 *BS_ptr)
|
|
{
|
|
BattleScriptPushCursor();
|
|
gBattlescriptCurrInstr = BS_ptr;
|
|
gBattleResources->battleCallbackStack->function[gBattleResources->battleCallbackStack->size++] = gBattleMainFunc;
|
|
gBattleMainFunc = RunBattleScriptCommands;
|
|
}
|
|
|
|
enum
|
|
{
|
|
ITEM_NO_EFFECT, // 0
|
|
ITEM_STATUS_CHANGE, // 1
|
|
ITEM_EFFECT_OTHER, // 2
|
|
ITEM_PP_CHANGE, // 3
|
|
ITEM_HP_CHANGE, // 4
|
|
ITEM_STATS_CHANGE, // 5
|
|
};
|
|
|
|
u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn)
|
|
{
|
|
int i = 0;
|
|
u8 effect = ITEM_NO_EFFECT;
|
|
u8 changedPP = 0;
|
|
u8 battlerHoldEffect, atkHoldEffect, defHoldEffect;
|
|
u8 battlerHoldEffectParam, atkHoldEffectParam, defHoldEffectParam;
|
|
u16 atkItem, defItem;
|
|
|
|
gLastUsedItem = gBattleMons[battlerId].item;
|
|
if (gLastUsedItem == ITEM_ENIGMA_BERRY)
|
|
{
|
|
battlerHoldEffect = gEnigmaBerries[battlerId].holdEffect;
|
|
battlerHoldEffectParam = gEnigmaBerries[battlerId].holdEffectParam;
|
|
}
|
|
else
|
|
{
|
|
battlerHoldEffect = ItemId_GetHoldEffect(gLastUsedItem);
|
|
battlerHoldEffectParam = ItemId_GetHoldEffectParam(gLastUsedItem);
|
|
}
|
|
|
|
atkItem = gBattleMons[gBattlerAttacker].item;
|
|
if (atkItem == ITEM_ENIGMA_BERRY)
|
|
{
|
|
atkHoldEffect = gEnigmaBerries[gBattlerAttacker].holdEffect;
|
|
atkHoldEffectParam = gEnigmaBerries[gBattlerAttacker].holdEffectParam;
|
|
}
|
|
else
|
|
{
|
|
atkHoldEffect = ItemId_GetHoldEffect(atkItem);
|
|
atkHoldEffectParam = ItemId_GetHoldEffectParam(atkItem);
|
|
}
|
|
|
|
// def variables are unused
|
|
defItem = gBattleMons[gBattlerTarget].item;
|
|
if (defItem == ITEM_ENIGMA_BERRY)
|
|
{
|
|
defHoldEffect = gEnigmaBerries[gBattlerTarget].holdEffect;
|
|
defHoldEffectParam = gEnigmaBerries[gBattlerTarget].holdEffectParam;
|
|
}
|
|
else
|
|
{
|
|
defHoldEffect = ItemId_GetHoldEffect(defItem);
|
|
defHoldEffectParam = ItemId_GetHoldEffectParam(defItem);
|
|
}
|
|
|
|
switch (caseID)
|
|
{
|
|
case ITEMEFFECT_ON_SWITCH_IN:
|
|
switch (battlerHoldEffect)
|
|
{
|
|
case HOLD_EFFECT_DOUBLE_PRIZE:
|
|
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
|
|
gBattleStruct->moneyMultiplier = 2;
|
|
break;
|
|
case HOLD_EFFECT_RESTORE_STATS:
|
|
for (i = 0; i < BATTLE_STATS_NO; i++)
|
|
{
|
|
if (gBattleMons[battlerId].statStages[i] < 6)
|
|
{
|
|
gBattleMons[battlerId].statStages[i] = 6;
|
|
effect = ITEM_STATS_CHANGE;
|
|
}
|
|
}
|
|
if (effect)
|
|
{
|
|
gBattleScripting.battler = battlerId;
|
|
gPotentialItemEffectBattler = battlerId;
|
|
gActiveBattler = gBattlerAttacker = battlerId;
|
|
BattleScriptExecute(BattleScript_WhiteHerbEnd2);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case 1:
|
|
if (gBattleMons[battlerId].hp)
|
|
{
|
|
switch (battlerHoldEffect)
|
|
{
|
|
case HOLD_EFFECT_RESTORE_HP:
|
|
if (gBattleMons[battlerId].hp <= gBattleMons[battlerId].maxHP / 2 && !moveTurn)
|
|
{
|
|
gBattleMoveDamage = battlerHoldEffectParam;
|
|
if (gBattleMons[battlerId].hp + battlerHoldEffectParam > gBattleMons[battlerId].maxHP)
|
|
gBattleMoveDamage = gBattleMons[battlerId].maxHP - gBattleMons[battlerId].hp;
|
|
gBattleMoveDamage *= -1;
|
|
BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem);
|
|
effect = 4;
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_RESTORE_PP:
|
|
if (!moveTurn)
|
|
{
|
|
struct Pokemon *mon;
|
|
u8 ppBonuses;
|
|
u16 move;
|
|
|
|
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
|
|
mon = &gPlayerParty[gBattlerPartyIndexes[battlerId]];
|
|
else
|
|
mon = &gEnemyParty[gBattlerPartyIndexes[battlerId]];
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
move = GetMonData(mon, MON_DATA_MOVE1 + i);
|
|
changedPP = GetMonData(mon, MON_DATA_PP1 + i);
|
|
ppBonuses = GetMonData(mon, MON_DATA_PP_BONUSES);
|
|
if (move && changedPP == 0)
|
|
break;
|
|
}
|
|
if (i != 4)
|
|
{
|
|
u8 maxPP = CalculatePPWithBonus(move, ppBonuses, i);
|
|
if (changedPP + battlerHoldEffectParam > maxPP)
|
|
changedPP = maxPP;
|
|
else
|
|
changedPP = changedPP + battlerHoldEffectParam;
|
|
|
|
PREPARE_MOVE_BUFFER(gBattleTextBuff1, move);
|
|
|
|
BattleScriptExecute(BattleScript_BerryPPHealEnd2);
|
|
BtlController_EmitSetMonData(0, i + REQUEST_PPMOVE1_BATTLE, 0, 1, &changedPP);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
effect = ITEM_PP_CHANGE;
|
|
}
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_RESTORE_STATS:
|
|
for (i = 0; i < BATTLE_STATS_NO; i++)
|
|
{
|
|
if (gBattleMons[battlerId].statStages[i] < 6)
|
|
{
|
|
gBattleMons[battlerId].statStages[i] = 6;
|
|
effect = ITEM_STATS_CHANGE;
|
|
}
|
|
}
|
|
if (effect)
|
|
{
|
|
gBattleScripting.battler = battlerId;
|
|
gPotentialItemEffectBattler = battlerId;
|
|
gActiveBattler = gBattlerAttacker = battlerId;
|
|
BattleScriptExecute(BattleScript_WhiteHerbEnd2);
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_LEFTOVERS:
|
|
if (gBattleMons[battlerId].hp < gBattleMons[battlerId].maxHP && !moveTurn)
|
|
{
|
|
gBattleMoveDamage = gBattleMons[battlerId].maxHP / 16;
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = 1;
|
|
if (gBattleMons[battlerId].hp + gBattleMoveDamage > gBattleMons[battlerId].maxHP)
|
|
gBattleMoveDamage = gBattleMons[battlerId].maxHP - gBattleMons[battlerId].hp;
|
|
gBattleMoveDamage *= -1;
|
|
BattleScriptExecute(BattleScript_ItemHealHP_End2);
|
|
effect = ITEM_HP_CHANGE;
|
|
RecordItemEffectBattle(battlerId, battlerHoldEffect);
|
|
}
|
|
break;
|
|
// nice copy/paste there gamefreak, making a function for confuse berries was too much eh?
|
|
case HOLD_EFFECT_CONFUSE_SPICY:
|
|
if (gBattleMons[battlerId].hp <= gBattleMons[battlerId].maxHP / 2 && !moveTurn)
|
|
{
|
|
PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, FLAVOR_SPICY);
|
|
|
|
gBattleMoveDamage = gBattleMons[battlerId].maxHP / battlerHoldEffectParam;
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = 1;
|
|
if (gBattleMons[battlerId].hp + gBattleMoveDamage > gBattleMons[battlerId].maxHP)
|
|
gBattleMoveDamage = gBattleMons[battlerId].maxHP - gBattleMons[battlerId].hp;
|
|
gBattleMoveDamage *= -1;
|
|
if (GetFlavorRelationByPersonality(gBattleMons[battlerId].personality, FLAVOR_SPICY) < 0)
|
|
BattleScriptExecute(BattleScript_BerryConfuseHealEnd2);
|
|
else
|
|
BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem);
|
|
effect = ITEM_HP_CHANGE;
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_CONFUSE_DRY:
|
|
if (gBattleMons[battlerId].hp <= gBattleMons[battlerId].maxHP / 2 && !moveTurn)
|
|
{
|
|
PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, FLAVOR_DRY);
|
|
|
|
gBattleMoveDamage = gBattleMons[battlerId].maxHP / battlerHoldEffectParam;
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = 1;
|
|
if (gBattleMons[battlerId].hp + gBattleMoveDamage > gBattleMons[battlerId].maxHP)
|
|
gBattleMoveDamage = gBattleMons[battlerId].maxHP - gBattleMons[battlerId].hp;
|
|
gBattleMoveDamage *= -1;
|
|
if (GetFlavorRelationByPersonality(gBattleMons[battlerId].personality, FLAVOR_DRY) < 0)
|
|
BattleScriptExecute(BattleScript_BerryConfuseHealEnd2);
|
|
else
|
|
BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem);
|
|
effect = ITEM_HP_CHANGE;
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_CONFUSE_SWEET:
|
|
if (gBattleMons[battlerId].hp <= gBattleMons[battlerId].maxHP / 2 && !moveTurn)
|
|
{
|
|
PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, FLAVOR_SWEET);
|
|
|
|
gBattleMoveDamage = gBattleMons[battlerId].maxHP / battlerHoldEffectParam;
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = 1;
|
|
if (gBattleMons[battlerId].hp + gBattleMoveDamage > gBattleMons[battlerId].maxHP)
|
|
gBattleMoveDamage = gBattleMons[battlerId].maxHP - gBattleMons[battlerId].hp;
|
|
gBattleMoveDamage *= -1;
|
|
if (GetFlavorRelationByPersonality(gBattleMons[battlerId].personality, FLAVOR_SWEET) < 0)
|
|
BattleScriptExecute(BattleScript_BerryConfuseHealEnd2);
|
|
else
|
|
BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem);
|
|
effect = ITEM_HP_CHANGE;
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_CONFUSE_BITTER:
|
|
if (gBattleMons[battlerId].hp <= gBattleMons[battlerId].maxHP / 2 && !moveTurn)
|
|
{
|
|
PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, FLAVOR_BITTER);
|
|
|
|
gBattleMoveDamage = gBattleMons[battlerId].maxHP / battlerHoldEffectParam;
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = 1;
|
|
if (gBattleMons[battlerId].hp + gBattleMoveDamage > gBattleMons[battlerId].maxHP)
|
|
gBattleMoveDamage = gBattleMons[battlerId].maxHP - gBattleMons[battlerId].hp;
|
|
gBattleMoveDamage *= -1;
|
|
if (GetFlavorRelationByPersonality(gBattleMons[battlerId].personality, FLAVOR_BITTER) < 0)
|
|
BattleScriptExecute(BattleScript_BerryConfuseHealEnd2);
|
|
else
|
|
BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem);
|
|
effect = ITEM_HP_CHANGE;
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_CONFUSE_SOUR:
|
|
if (gBattleMons[battlerId].hp <= gBattleMons[battlerId].maxHP / 2 && !moveTurn)
|
|
{
|
|
PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, FLAVOR_SOUR);
|
|
|
|
gBattleMoveDamage = gBattleMons[battlerId].maxHP / battlerHoldEffectParam;
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = 1;
|
|
if (gBattleMons[battlerId].hp + gBattleMoveDamage > gBattleMons[battlerId].maxHP)
|
|
gBattleMoveDamage = gBattleMons[battlerId].maxHP - gBattleMons[battlerId].hp;
|
|
gBattleMoveDamage *= -1;
|
|
if (GetFlavorRelationByPersonality(gBattleMons[battlerId].personality, FLAVOR_SOUR) < 0)
|
|
BattleScriptExecute(BattleScript_BerryConfuseHealEnd2);
|
|
else
|
|
BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem);
|
|
effect = ITEM_HP_CHANGE;
|
|
}
|
|
break;
|
|
// copy/paste again, smh
|
|
case HOLD_EFFECT_ATTACK_UP:
|
|
if (gBattleMons[battlerId].hp <= gBattleMons[battlerId].maxHP / battlerHoldEffectParam && !moveTurn && gBattleMons[battlerId].statStages[STAT_ATK] < 0xC)
|
|
{
|
|
PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_ATK);
|
|
PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_STATROSE);
|
|
|
|
gEffectBattler = battlerId;
|
|
SET_STATCHANGER(STAT_ATK, 1, FALSE);
|
|
gBattleScripting.animArg1 = 0xE + STAT_ATK;
|
|
gBattleScripting.animArg2 = 0;
|
|
BattleScriptExecute(BattleScript_BerryStatRaiseEnd2);
|
|
effect = ITEM_STATS_CHANGE;
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_DEFENSE_UP:
|
|
if (gBattleMons[battlerId].hp <= gBattleMons[battlerId].maxHP / battlerHoldEffectParam && !moveTurn && gBattleMons[battlerId].statStages[STAT_DEF] < 0xC)
|
|
{
|
|
PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_DEF);
|
|
|
|
gEffectBattler = battlerId;
|
|
SET_STATCHANGER(STAT_DEF, 1, FALSE);
|
|
gBattleScripting.animArg1 = 0xE + STAT_DEF;
|
|
gBattleScripting.animArg2 = 0;
|
|
BattleScriptExecute(BattleScript_BerryStatRaiseEnd2);
|
|
effect = ITEM_STATS_CHANGE;
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_SPEED_UP:
|
|
if (gBattleMons[battlerId].hp <= gBattleMons[battlerId].maxHP / battlerHoldEffectParam && !moveTurn && gBattleMons[battlerId].statStages[STAT_SPEED] < 0xC)
|
|
{
|
|
PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_SPEED);
|
|
|
|
gEffectBattler = battlerId;
|
|
SET_STATCHANGER(STAT_SPEED, 1, FALSE);
|
|
gBattleScripting.animArg1 = 0xE + STAT_SPEED;
|
|
gBattleScripting.animArg2 = 0;
|
|
BattleScriptExecute(BattleScript_BerryStatRaiseEnd2);
|
|
effect = ITEM_STATS_CHANGE;
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_SP_ATTACK_UP:
|
|
if (gBattleMons[battlerId].hp <= gBattleMons[battlerId].maxHP / battlerHoldEffectParam && !moveTurn && gBattleMons[battlerId].statStages[STAT_SPATK] < 0xC)
|
|
{
|
|
PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_SPATK);
|
|
|
|
gEffectBattler = battlerId;
|
|
SET_STATCHANGER(STAT_SPATK, 1, FALSE);
|
|
gBattleScripting.animArg1 = 0xE + STAT_SPATK;
|
|
gBattleScripting.animArg2 = 0;
|
|
BattleScriptExecute(BattleScript_BerryStatRaiseEnd2);
|
|
effect = ITEM_STATS_CHANGE;
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_SP_DEFENSE_UP:
|
|
if (gBattleMons[battlerId].hp <= gBattleMons[battlerId].maxHP / battlerHoldEffectParam && !moveTurn && gBattleMons[battlerId].statStages[STAT_SPDEF] < 0xC)
|
|
{
|
|
PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_SPDEF);
|
|
|
|
gEffectBattler = battlerId;
|
|
SET_STATCHANGER(STAT_SPDEF, 1, FALSE);
|
|
gBattleScripting.animArg1 = 0xE + STAT_SPDEF;
|
|
gBattleScripting.animArg2 = 0;
|
|
BattleScriptExecute(BattleScript_BerryStatRaiseEnd2);
|
|
effect = ITEM_STATS_CHANGE;
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_CRITICAL_UP:
|
|
if (gBattleMons[battlerId].hp <= gBattleMons[battlerId].maxHP / battlerHoldEffectParam && !moveTurn && !(gBattleMons[battlerId].status2 & STATUS2_FOCUS_ENERGY))
|
|
{
|
|
gBattleMons[battlerId].status2 |= STATUS2_FOCUS_ENERGY;
|
|
BattleScriptExecute(BattleScript_BerryFocusEnergyEnd2);
|
|
effect = ITEM_EFFECT_OTHER;
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_RANDOM_STAT_UP:
|
|
if (!moveTurn && gBattleMons[battlerId].hp <= gBattleMons[battlerId].maxHP / battlerHoldEffectParam)
|
|
{
|
|
for (i = 0; i < 5; i++)
|
|
{
|
|
if (gBattleMons[battlerId].statStages[STAT_ATK + i] < 0xC)
|
|
break;
|
|
}
|
|
if (i != 5)
|
|
{
|
|
do
|
|
{
|
|
i = Random() % 5;
|
|
} while (gBattleMons[battlerId].statStages[STAT_ATK + i] == 0xC);
|
|
|
|
PREPARE_STAT_BUFFER(gBattleTextBuff1, i + 1);
|
|
|
|
gBattleTextBuff2[0] = B_BUFF_PLACEHOLDER_BEGIN;
|
|
gBattleTextBuff2[1] = B_BUFF_STRING;
|
|
gBattleTextBuff2[2] = STRINGID_STATSHARPLY;
|
|
gBattleTextBuff2[3] = STRINGID_STATSHARPLY >> 8;
|
|
gBattleTextBuff2[4] = B_BUFF_STRING;
|
|
gBattleTextBuff2[5] = STRINGID_STATROSE;
|
|
gBattleTextBuff2[6] = STRINGID_STATROSE >> 8;
|
|
gBattleTextBuff2[7] = EOS;
|
|
|
|
gEffectBattler = battlerId;
|
|
SET_STATCHANGER(i + 1, 2, FALSE);
|
|
gBattleScripting.animArg1 = 0x21 + i + 6;
|
|
gBattleScripting.animArg2 = 0;
|
|
BattleScriptExecute(BattleScript_BerryStatRaiseEnd2);
|
|
effect = ITEM_STATS_CHANGE;
|
|
}
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_CURE_PAR:
|
|
if (gBattleMons[battlerId].status1 & STATUS1_PARALYSIS)
|
|
{
|
|
gBattleMons[battlerId].status1 &= ~(STATUS1_PARALYSIS);
|
|
BattleScriptExecute(BattleScript_BerryCurePrlzEnd2);
|
|
effect = ITEM_STATUS_CHANGE;
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_CURE_PSN:
|
|
if (gBattleMons[battlerId].status1 & STATUS1_PSN_ANY)
|
|
{
|
|
gBattleMons[battlerId].status1 &= ~(STATUS1_PSN_ANY | STATUS1_TOXIC_COUNTER);
|
|
BattleScriptExecute(BattleScript_BerryCurePsnEnd2);
|
|
effect = ITEM_STATUS_CHANGE;
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_CURE_BRN:
|
|
if (gBattleMons[battlerId].status1 & STATUS1_BURN)
|
|
{
|
|
gBattleMons[battlerId].status1 &= ~(STATUS1_BURN);
|
|
BattleScriptExecute(BattleScript_BerryCureBrnEnd2);
|
|
effect = ITEM_STATUS_CHANGE;
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_CURE_FRZ:
|
|
if (gBattleMons[battlerId].status1 & STATUS1_FREEZE)
|
|
{
|
|
gBattleMons[battlerId].status1 &= ~(STATUS1_FREEZE);
|
|
BattleScriptExecute(BattleScript_BerryCureFrzEnd2);
|
|
effect = ITEM_STATUS_CHANGE;
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_CURE_SLP:
|
|
if (gBattleMons[battlerId].status1 & STATUS1_SLEEP)
|
|
{
|
|
gBattleMons[battlerId].status1 &= ~(STATUS1_SLEEP);
|
|
gBattleMons[battlerId].status2 &= ~(STATUS2_NIGHTMARE);
|
|
BattleScriptExecute(BattleScript_BerryCureSlpEnd2);
|
|
effect = ITEM_STATUS_CHANGE;
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_CURE_CONFUSION:
|
|
if (gBattleMons[battlerId].status2 & STATUS2_CONFUSION)
|
|
{
|
|
gBattleMons[battlerId].status2 &= ~(STATUS2_CONFUSION);
|
|
BattleScriptExecute(BattleScript_BerryCureConfusionEnd2);
|
|
effect = ITEM_EFFECT_OTHER;
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_CURE_STATUS:
|
|
if (gBattleMons[battlerId].status1 & STATUS1_ANY || gBattleMons[battlerId].status2 & STATUS2_CONFUSION)
|
|
{
|
|
i = 0;
|
|
if (gBattleMons[battlerId].status1 & STATUS1_PSN_ANY)
|
|
{
|
|
StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn);
|
|
i++;
|
|
}
|
|
if (gBattleMons[battlerId].status1 & STATUS1_SLEEP)
|
|
{
|
|
gBattleMons[battlerId].status2 &= ~(STATUS2_NIGHTMARE);
|
|
StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn);
|
|
i++;
|
|
}
|
|
if (gBattleMons[battlerId].status1 & STATUS1_PARALYSIS)
|
|
{
|
|
StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn);
|
|
i++;
|
|
}
|
|
if (gBattleMons[battlerId].status1 & STATUS1_BURN)
|
|
{
|
|
StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn);
|
|
i++;
|
|
}
|
|
if (gBattleMons[battlerId].status1 & STATUS1_FREEZE)
|
|
{
|
|
StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn);
|
|
i++;
|
|
}
|
|
if (gBattleMons[battlerId].status2 & STATUS2_CONFUSION)
|
|
{
|
|
StringCopy(gBattleTextBuff1, gStatusConditionString_ConfusionJpn);
|
|
i++;
|
|
}
|
|
if (!(i > 1))
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
else
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
|
gBattleMons[battlerId].status1 = 0;
|
|
gBattleMons[battlerId].status2 &= ~(STATUS2_CONFUSION);
|
|
BattleScriptExecute(BattleScript_BerryCureChosenStatusEnd2);
|
|
effect = ITEM_STATUS_CHANGE;
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_CURE_ATTRACT:
|
|
if (gBattleMons[battlerId].status2 & STATUS2_INFATUATION)
|
|
{
|
|
gBattleMons[battlerId].status2 &= ~(STATUS2_INFATUATION);
|
|
StringCopy(gBattleTextBuff1, gStatusConditionString_LoveJpn);
|
|
BattleScriptExecute(BattleScript_BerryCureChosenStatusEnd2);
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
effect = ITEM_EFFECT_OTHER;
|
|
}
|
|
break;
|
|
}
|
|
if (effect)
|
|
{
|
|
gBattleScripting.battler = battlerId;
|
|
gPotentialItemEffectBattler = battlerId;
|
|
gActiveBattler = gBattlerAttacker = battlerId;
|
|
switch (effect)
|
|
{
|
|
case ITEM_STATUS_CHANGE:
|
|
BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battlerId].status1);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
break;
|
|
case ITEM_PP_CHANGE:
|
|
if (!(gBattleMons[battlerId].status2 & STATUS2_TRANSFORMED) && !(gDisableStructs[battlerId].unk18_b & gBitTable[i]))
|
|
gBattleMons[battlerId].pp[i] = changedPP;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 2:
|
|
break;
|
|
case ITEMEFFECT_MOVE_END:
|
|
for (battlerId = 0; battlerId < gBattlersCount; battlerId++)
|
|
{
|
|
gLastUsedItem = gBattleMons[battlerId].item;
|
|
if (gBattleMons[battlerId].item == ITEM_ENIGMA_BERRY)
|
|
{
|
|
battlerHoldEffect = gEnigmaBerries[battlerId].holdEffect;
|
|
battlerHoldEffectParam = gEnigmaBerries[battlerId].holdEffectParam;
|
|
}
|
|
else
|
|
{
|
|
battlerHoldEffect = ItemId_GetHoldEffect(gLastUsedItem);
|
|
battlerHoldEffectParam = ItemId_GetHoldEffectParam(gLastUsedItem);
|
|
}
|
|
switch (battlerHoldEffect)
|
|
{
|
|
case HOLD_EFFECT_CURE_PAR:
|
|
if (gBattleMons[battlerId].status1 & STATUS1_PARALYSIS)
|
|
{
|
|
gBattleMons[battlerId].status1 &= ~(STATUS1_PARALYSIS);
|
|
BattleScriptPushCursor();
|
|
gBattlescriptCurrInstr = BattleScript_BerryCureParRet;
|
|
effect = ITEM_STATUS_CHANGE;
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_CURE_PSN:
|
|
if (gBattleMons[battlerId].status1 & STATUS1_PSN_ANY)
|
|
{
|
|
gBattleMons[battlerId].status1 &= ~(STATUS1_PSN_ANY | STATUS1_TOXIC_COUNTER);
|
|
BattleScriptPushCursor();
|
|
gBattlescriptCurrInstr = BattleScript_BerryCurePsnRet;
|
|
effect = ITEM_STATUS_CHANGE;
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_CURE_BRN:
|
|
if (gBattleMons[battlerId].status1 & STATUS1_BURN)
|
|
{
|
|
gBattleMons[battlerId].status1 &= ~(STATUS1_BURN);
|
|
BattleScriptPushCursor();
|
|
gBattlescriptCurrInstr = BattleScript_BerryCureBrnRet;
|
|
effect = ITEM_STATUS_CHANGE;
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_CURE_FRZ:
|
|
if (gBattleMons[battlerId].status1 & STATUS1_FREEZE)
|
|
{
|
|
gBattleMons[battlerId].status1 &= ~(STATUS1_FREEZE);
|
|
BattleScriptPushCursor();
|
|
gBattlescriptCurrInstr = BattleScript_BerryCureFrzRet;
|
|
effect = ITEM_STATUS_CHANGE;
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_CURE_SLP:
|
|
if (gBattleMons[battlerId].status1 & STATUS1_SLEEP)
|
|
{
|
|
gBattleMons[battlerId].status1 &= ~(STATUS1_SLEEP);
|
|
gBattleMons[battlerId].status2 &= ~(STATUS2_NIGHTMARE);
|
|
BattleScriptPushCursor();
|
|
gBattlescriptCurrInstr = BattleScript_BerryCureSlpRet;
|
|
effect = ITEM_STATUS_CHANGE;
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_CURE_CONFUSION:
|
|
if (gBattleMons[battlerId].status2 & STATUS2_CONFUSION)
|
|
{
|
|
gBattleMons[battlerId].status2 &= ~(STATUS2_CONFUSION);
|
|
BattleScriptPushCursor();
|
|
gBattlescriptCurrInstr = BattleScript_BerryCureConfusionRet;
|
|
effect = ITEM_EFFECT_OTHER;
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_CURE_ATTRACT:
|
|
if (gBattleMons[battlerId].status2 & STATUS2_INFATUATION)
|
|
{
|
|
gBattleMons[battlerId].status2 &= ~(STATUS2_INFATUATION);
|
|
StringCopy(gBattleTextBuff1, gStatusConditionString_LoveJpn);
|
|
BattleScriptPushCursor();
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
gBattlescriptCurrInstr = BattleScript_BerryCureChosenStatusRet;
|
|
effect = ITEM_EFFECT_OTHER;
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_CURE_STATUS:
|
|
if (gBattleMons[battlerId].status1 & STATUS1_ANY || gBattleMons[battlerId].status2 & STATUS2_CONFUSION)
|
|
{
|
|
if (gBattleMons[battlerId].status1 & STATUS1_PSN_ANY)
|
|
{
|
|
StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn);
|
|
}
|
|
if (gBattleMons[battlerId].status1 & STATUS1_SLEEP)
|
|
{
|
|
gBattleMons[battlerId].status2 &= ~(STATUS2_NIGHTMARE);
|
|
StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn);
|
|
}
|
|
if (gBattleMons[battlerId].status1 & STATUS1_PARALYSIS)
|
|
{
|
|
StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn);
|
|
}
|
|
if (gBattleMons[battlerId].status1 & STATUS1_BURN)
|
|
{
|
|
StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn);
|
|
}
|
|
if (gBattleMons[battlerId].status1 & STATUS1_FREEZE)
|
|
{
|
|
StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn);
|
|
}
|
|
if (gBattleMons[battlerId].status2 & STATUS2_CONFUSION)
|
|
{
|
|
StringCopy(gBattleTextBuff1, gStatusConditionString_ConfusionJpn);
|
|
}
|
|
gBattleMons[battlerId].status1 = 0;
|
|
gBattleMons[battlerId].status2 &= ~(STATUS2_CONFUSION);
|
|
BattleScriptPushCursor();
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
|
gBattlescriptCurrInstr = BattleScript_BerryCureChosenStatusRet;
|
|
effect = ITEM_STATUS_CHANGE;
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_RESTORE_STATS:
|
|
for (i = 0; i < BATTLE_STATS_NO; i++)
|
|
{
|
|
if (gBattleMons[battlerId].statStages[i] < 6)
|
|
{
|
|
gBattleMons[battlerId].statStages[i] = 6;
|
|
effect = ITEM_STATS_CHANGE;
|
|
}
|
|
}
|
|
if (effect)
|
|
{
|
|
gBattleScripting.battler = battlerId;
|
|
gPotentialItemEffectBattler = battlerId;
|
|
BattleScriptPushCursor();
|
|
gBattlescriptCurrInstr = BattleScript_WhiteHerbRet;
|
|
return effect;
|
|
}
|
|
break;
|
|
}
|
|
if (effect)
|
|
{
|
|
gBattleScripting.battler = battlerId;
|
|
gPotentialItemEffectBattler = battlerId;
|
|
gActiveBattler = battlerId;
|
|
BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBattler].status1);
|
|
MarkBattlerForControllerExec(gActiveBattler);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case ITEMEFFECT_KINGSROCK_SHELLBELL:
|
|
if (gBattleMoveDamage)
|
|
{
|
|
switch (atkHoldEffect)
|
|
{
|
|
case HOLD_EFFECT_FLINCH:
|
|
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
|
|
&& TARGET_TURN_DAMAGED
|
|
&& (Random() % 100) < atkHoldEffectParam
|
|
&& gBattleMoves[gCurrentMove].flags & FLAG_KINGSROCK_AFFECTED
|
|
&& gBattleMons[gBattlerTarget].hp)
|
|
{
|
|
gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_FLINCH;
|
|
BattleScriptPushCursor();
|
|
SetMoveEffect(0, 0);
|
|
BattleScriptPop();
|
|
}
|
|
break;
|
|
case HOLD_EFFECT_SHELL_BELL:
|
|
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
|
|
&& gSpecialStatuses[gBattlerTarget].dmg != 0
|
|
&& gSpecialStatuses[gBattlerTarget].dmg != 0xFFFF
|
|
&& gBattlerAttacker != gBattlerTarget
|
|
&& gBattleMons[gBattlerAttacker].hp != gBattleMons[gBattlerAttacker].maxHP
|
|
&& gBattleMons[gBattlerAttacker].hp != 0)
|
|
{
|
|
gLastUsedItem = atkItem;
|
|
gPotentialItemEffectBattler = gBattlerAttacker;
|
|
gBattleScripting.battler = gBattlerAttacker;
|
|
gBattleMoveDamage = (gSpecialStatuses[gBattlerTarget].dmg / atkHoldEffectParam) * -1;
|
|
if (gBattleMoveDamage == 0)
|
|
gBattleMoveDamage = -1;
|
|
gSpecialStatuses[gBattlerTarget].dmg = 0;
|
|
BattleScriptPushCursor();
|
|
gBattlescriptCurrInstr = BattleScript_ItemHealHP_Ret;
|
|
effect++;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return effect;
|
|
}
|
|
|
|
void ClearFuryCutterDestinyBondGrudge(u8 battlerId)
|
|
{
|
|
gDisableStructs[battlerId].furyCutterCounter = 0;
|
|
gBattleMons[battlerId].status2 &= ~(STATUS2_DESTINY_BOND);
|
|
gStatuses3[battlerId] &= ~(STATUS3_GRUDGE);
|
|
}
|
|
|
|
void HandleAction_RunBattleScript(void) // identical to RunBattleScriptCommands
|
|
{
|
|
if (gBattleControllerExecFlags == 0)
|
|
gBattleScriptingCommandsTable[*gBattlescriptCurrInstr]();
|
|
}
|
|
|
|
u8 GetMoveTarget(u16 move, u8 setTarget)
|
|
{
|
|
u8 targetBattler = 0;
|
|
u8 moveTarget;
|
|
u8 side;
|
|
|
|
if (setTarget)
|
|
moveTarget = setTarget - 1;
|
|
else
|
|
moveTarget = gBattleMoves[move].target;
|
|
|
|
switch (moveTarget)
|
|
{
|
|
case MOVE_TARGET_SELECTED:
|
|
side = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE;
|
|
if (gSideTimers[side].followmeTimer && gBattleMons[gSideTimers[side].followmeTarget].hp)
|
|
targetBattler = gSideTimers[side].followmeTarget;
|
|
else
|
|
{
|
|
side = GetBattlerSide(gBattlerAttacker);
|
|
do
|
|
{
|
|
targetBattler = Random() % gBattlersCount;
|
|
} while (targetBattler == gBattlerAttacker || side == GetBattlerSide(targetBattler) || gAbsentBattlerFlags & gBitTable[targetBattler]);
|
|
if (gBattleMoves[move].type == TYPE_ELECTRIC
|
|
&& AbilityBattleEffects(ABILITYEFFECT_COUNT_OTHER_SIDE, gBattlerAttacker, ABILITY_LIGHTNING_ROD, 0, 0)
|
|
&& gBattleMons[targetBattler].ability != ABILITY_LIGHTNING_ROD)
|
|
{
|
|
targetBattler ^= BIT_FLANK;
|
|
RecordAbilityBattle(targetBattler, gBattleMons[targetBattler].ability);
|
|
gSpecialStatuses[targetBattler].lightningRodRedirected = 1;
|
|
}
|
|
}
|
|
break;
|
|
case MOVE_TARGET_DEPENDS:
|
|
case MOVE_TARGET_BOTH:
|
|
case MOVE_TARGET_FOES_AND_ALLY:
|
|
case MOVE_TARGET_OPPONENTS_FIELD:
|
|
targetBattler = GetBattlerAtPosition((GetBattlerPosition(gBattlerAttacker) & BIT_SIDE) ^ BIT_SIDE);
|
|
if (gAbsentBattlerFlags & gBitTable[targetBattler])
|
|
targetBattler ^= BIT_FLANK;
|
|
break;
|
|
case MOVE_TARGET_RANDOM:
|
|
side = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE;
|
|
if (gSideTimers[side].followmeTimer && gBattleMons[gSideTimers[side].followmeTarget].hp)
|
|
targetBattler = gSideTimers[side].followmeTarget;
|
|
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && moveTarget & MOVE_TARGET_RANDOM)
|
|
{
|
|
if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER)
|
|
{
|
|
if (Random() & 1)
|
|
targetBattler = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
|
|
else
|
|
targetBattler = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT);
|
|
}
|
|
else
|
|
{
|
|
if (Random() & 1)
|
|
targetBattler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
|
|
else
|
|
targetBattler = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT);
|
|
}
|
|
if (gAbsentBattlerFlags & gBitTable[targetBattler])
|
|
targetBattler ^= BIT_FLANK;
|
|
}
|
|
else
|
|
targetBattler = GetBattlerAtPosition((GetBattlerPosition(gBattlerAttacker) & BIT_SIDE) ^ BIT_SIDE);
|
|
break;
|
|
case MOVE_TARGET_USER_OR_SELECTED:
|
|
case MOVE_TARGET_USER:
|
|
targetBattler = gBattlerAttacker;
|
|
break;
|
|
}
|
|
|
|
*(gBattleStruct->moveTarget + gBattlerAttacker) = targetBattler;
|
|
|
|
return targetBattler;
|
|
}
|
|
|
|
static bool32 HasObedientBitSet(u8 battlerId)
|
|
{
|
|
if (GetBattlerSide(battlerId) == B_SIDE_OPPONENT)
|
|
return TRUE;
|
|
if (GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_SPECIES, NULL) != SPECIES_DEOXYS
|
|
&& GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_SPECIES, NULL) != SPECIES_MEW)
|
|
return TRUE;
|
|
return GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_OBEDIENCE, NULL);
|
|
}
|
|
|
|
u8 IsMonDisobedient(void)
|
|
{
|
|
s32 rnd;
|
|
s32 calc;
|
|
u8 obedienceLevel = 0;
|
|
|
|
if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000))
|
|
return 0;
|
|
if (GetBattlerSide(gBattlerAttacker) == B_SIDE_OPPONENT)
|
|
return 0;
|
|
|
|
if (HasObedientBitSet(gBattlerAttacker)) // only if species is Mew or Deoxys
|
|
{
|
|
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && GetBattlerPosition(gBattlerAttacker) == 2)
|
|
return 0;
|
|
if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER)
|
|
return 0;
|
|
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED)
|
|
return 0;
|
|
if (!IsOtherTrainer(gBattleMons[gBattlerAttacker].otId, gBattleMons[gBattlerAttacker].otName))
|
|
return 0;
|
|
if (FlagGet(FLAG_BADGE08_GET))
|
|
return 0;
|
|
|
|
obedienceLevel = 10;
|
|
|
|
if (FlagGet(FLAG_BADGE02_GET))
|
|
obedienceLevel = 30;
|
|
if (FlagGet(FLAG_BADGE04_GET))
|
|
obedienceLevel = 50;
|
|
if (FlagGet(FLAG_BADGE06_GET))
|
|
obedienceLevel = 70;
|
|
}
|
|
|
|
if (gBattleMons[gBattlerAttacker].level <= obedienceLevel)
|
|
return 0;
|
|
rnd = (Random() & 255);
|
|
calc = (gBattleMons[gBattlerAttacker].level + obedienceLevel) * rnd >> 8;
|
|
if (calc < obedienceLevel)
|
|
return 0;
|
|
|
|
// is not obedient
|
|
if (gCurrentMove == MOVE_RAGE)
|
|
gBattleMons[gBattlerAttacker].status2 &= ~(STATUS2_RAGE);
|
|
if (gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP && (gCurrentMove == MOVE_SNORE || gCurrentMove == MOVE_SLEEP_TALK))
|
|
{
|
|
gBattlescriptCurrInstr = BattleScript_IgnoresWhileAsleep;
|
|
return 1;
|
|
}
|
|
|
|
rnd = (Random() & 255);
|
|
calc = (gBattleMons[gBattlerAttacker].level + obedienceLevel) * rnd >> 8;
|
|
if (calc < obedienceLevel)
|
|
{
|
|
calc = CheckMoveLimitations(gBattlerAttacker, gBitTable[gCurrMovePos], 0xFF);
|
|
if (calc == 0xF) // all moves cannot be used
|
|
{
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = Random() & 3;
|
|
gBattlescriptCurrInstr = BattleScript_MoveUsedLoafingAround;
|
|
return 1;
|
|
}
|
|
else // use a random move
|
|
{
|
|
do
|
|
{
|
|
gCurrMovePos = gChosenMovePos = Random() & 3;
|
|
} while (gBitTable[gCurrMovePos] & calc);
|
|
|
|
gCalledMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos];
|
|
gBattlescriptCurrInstr = BattleScript_IgnoresAndUsesRandomMove;
|
|
gBattlerTarget = GetMoveTarget(gCalledMove, 0);
|
|
gHitMarker |= HITMARKER_x200000;
|
|
return 2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
obedienceLevel = gBattleMons[gBattlerAttacker].level - obedienceLevel;
|
|
|
|
calc = (Random() & 255);
|
|
if (calc < obedienceLevel && !(gBattleMons[gBattlerAttacker].status1 & STATUS1_ANY) && gBattleMons[gBattlerAttacker].ability != ABILITY_VITAL_SPIRIT && gBattleMons[gBattlerAttacker].ability != ABILITY_INSOMNIA)
|
|
{
|
|
// try putting asleep
|
|
int i;
|
|
for (i = 0; i < gBattlersCount; i++)
|
|
{
|
|
if (gBattleMons[i].status2 & STATUS2_UPROAR)
|
|
break;
|
|
}
|
|
if (i == gBattlersCount)
|
|
{
|
|
gBattlescriptCurrInstr = BattleScript_IgnoresAndFallsAsleep;
|
|
return 1;
|
|
}
|
|
}
|
|
calc -= obedienceLevel;
|
|
if (calc < obedienceLevel)
|
|
{
|
|
gBattleMoveDamage = CalculateBaseDamage(&gBattleMons[gBattlerAttacker], &gBattleMons[gBattlerAttacker], MOVE_POUND, 0, 40, 0, gBattlerAttacker, gBattlerAttacker);
|
|
gBattlerTarget = gBattlerAttacker;
|
|
gBattlescriptCurrInstr = BattleScript_IgnoresAndHitsItself;
|
|
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
|
return 2;
|
|
}
|
|
else
|
|
{
|
|
gBattleCommunication[MULTISTRING_CHOOSER] = Random() & 3;
|
|
gBattlescriptCurrInstr = BattleScript_MoveUsedLoafingAround;
|
|
return 1;
|
|
}
|
|
}
|
|
}
|