pokeemerald/src/battle_util.c
2017-12-05 12:42:30 -06:00

3433 lines
136 KiB
C

#include "global.h"
#include "battle.h"
#include "constants/abilities.h"
#include "moves.h"
#include "constants/hold_effects.h"
#include "pokemon.h"
#include "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 "battle_string_ids.h"
#include "battle_ai_script_commands.h"
#include "battle_controllers.h"
#include "event_data.h"
#include "calculate_base_damage.h"
#include "link.h"
#include "berry.h"
extern const u8* gBattlescriptCurrInstr;
extern const u8* gSelectionBattleScripts[BATTLE_BANKS_COUNT];
extern const u8* gPalaceSelectionBattleScripts[BATTLE_BANKS_COUNT];
extern struct BattlePokemon gBattleMons[BATTLE_BANKS_COUNT];
extern u8 gActiveBank;
extern u8 gStringBank;
extern u16 gCurrentMove;
extern u16 gLastUsedItem;
extern u8 gNoOfAllBanks;
extern u32 gStatuses3[BATTLE_BANKS_COUNT];
extern u8 gBankAttacker;
extern u8 gBankTarget;
extern u8 gAbsentBankFlags;
extern u16 gBattleWeather;
extern u8 gBanksByTurnOrder[BATTLE_BANKS_COUNT];
extern u16 gSideAffecting[2];
extern u8 gBattleCommunication[];
extern void (*gBattleMainFunc)(void);
extern s32 gBattleMoveDamage;
extern struct BattleEnigmaBerry gEnigmaBerries[BATTLE_BANKS_COUNT];
extern u8 gBattleBufferB[BATTLE_BANKS_COUNT][0x200];
extern u32 gBattleTypeFlags;
extern u16 gLastMoves[BATTLE_BANKS_COUNT];
extern u32 gHitMarker;
extern u8 gEffectBank;
extern u16 gBattlePartyID[BATTLE_BANKS_COUNT];
extern u8 gBank1;
extern u16 gChosenMovesByBanks[BATTLE_BANKS_COUNT];
extern u8 gBattleMoveFlags;
extern s32 gTakenDmg[BATTLE_BANKS_COUNT];
extern u8 gTakenDmgBanks[BATTLE_BANKS_COUNT];
extern u8 gLastUsedAbility;
extern u8 gCurrentActionFuncId;
extern u32 gBattleExecBuffer;
extern u16 gRandomMove;
extern u8 gCurrMovePos;
extern u8 gUnknown_020241E9;
extern u8 gSentPokesToOpponent[2];
extern const struct BattleMove gBattleMoves[];
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 GetBattleBank(u8 caseId)
{
u8 ret = 0;
switch (caseId)
{
case BS_GET_TARGET:
ret = gBankTarget;
break;
case BS_GET_ATTACKER:
ret = gBankAttacker;
break;
case BS_GET_EFFECT_BANK:
ret = gEffectBank;
break;
case BS_GET_BANK_0:
ret = 0;
break;
case BS_GET_SCRIPTING_BANK:
ret = gBattleScripting.bank;
break;
case BS_GET_gBank1:
ret = gBank1;
break;
case 5:
ret = gBank1;
break;
case 4:
case 6:
case 8:
case 9:
case BS_GET_PLAYER1:
ret = GetBankByIdentity(IDENTITY_PLAYER_MON1);
break;
case BS_GET_OPPONENT1:
ret = GetBankByIdentity(IDENTITY_OPPONENT_MON1);
break;
case BS_GET_PLAYER2:
ret = GetBankByIdentity(IDENTITY_PLAYER_MON2);
break;
case BS_GET_OPPONENT2:
ret = GetBankByIdentity(IDENTITY_OPPONENT_MON2);
break;
}
return ret;
}
void PressurePPLose(u8 bankDef, u8 bankAtk, u16 move)
{
s32 i;
if (gBattleMons[bankDef].ability != ABILITY_PRESSURE)
return;
for (i = 0; i < 4; i++)
{
if (gBattleMons[bankAtk].moves[i] == move)
break;
}
if (i == 4) // mons don't share any moves
return;
if (gBattleMons[bankAtk].pp[i] != 0)
gBattleMons[bankAtk].pp[i]--;
if (!(gBattleMons[bankAtk].status2 & STATUS2_TRANSFORMED)
&& !(gDisableStructs[bankAtk].unk18_b & gBitTable[i]))
{
gActiveBank = bankAtk;
EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + i, 0, 1, &gBattleMons[gActiveBank].pp[i]);
MarkBufferBankForExecution(gActiveBank);
}
}
void PressurePPLoseOnUsingImprision(u8 bankAtk)
{
s32 i, j;
s32 imprisionPos = 4;
u8 atkSide = GetBankSide(bankAtk);
for (i = 0; i < gNoOfAllBanks; i++)
{
if (atkSide != GetBankSide(i) && gBattleMons[i].ability == ABILITY_PRESSURE)
{
for (j = 0; j < 4; j++)
{
if (gBattleMons[bankAtk].moves[j] == MOVE_IMPRISON)
break;
}
if (j != 4)
{
imprisionPos = j;
if (gBattleMons[bankAtk].pp[j] != 0)
gBattleMons[bankAtk].pp[j]--;
}
}
}
if (imprisionPos != 4
&& !(gBattleMons[bankAtk].status2 & STATUS2_TRANSFORMED)
&& !(gDisableStructs[bankAtk].unk18_b & gBitTable[imprisionPos]))
{
gActiveBank = bankAtk;
EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + imprisionPos, 0, 1, &gBattleMons[gActiveBank].pp[imprisionPos]);
MarkBufferBankForExecution(gActiveBank);
}
}
void PressurePPLoseOnUsingPerishSong(u8 bankAtk)
{
s32 i, j;
s32 perishSongPos = 4;
for (i = 0; i < gNoOfAllBanks; i++)
{
if (gBattleMons[i].ability == ABILITY_PRESSURE && i != bankAtk)
{
for (j = 0; j < 4; j++)
{
if (gBattleMons[bankAtk].moves[j] == MOVE_PERISH_SONG)
break;
}
if (j != 4)
{
perishSongPos = j;
if (gBattleMons[bankAtk].pp[j] != 0)
gBattleMons[bankAtk].pp[j]--;
}
}
}
if (perishSongPos != 4
&& !(gBattleMons[bankAtk].status2 & STATUS2_TRANSFORMED)
&& !(gDisableStructs[bankAtk].unk18_b & gBitTable[perishSongPos]))
{
gActiveBank = bankAtk;
EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + perishSongPos, 0, 1, &gBattleMons[gActiveBank].pp[perishSongPos]);
MarkBufferBankForExecution(gActiveBank);
}
}
void MarkAllBufferBanksForExecution(void) // unused
{
s32 i;
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
{
for (i = 0; i < gNoOfAllBanks; i++)
gBattleExecBuffer |= gBitTable[i] << 0x1C;
}
else
{
for (i = 0; i < gNoOfAllBanks; i++)
gBattleExecBuffer |= gBitTable[i];
}
}
void MarkBufferBankForExecution(u8 bank)
{
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
{
gBattleExecBuffer |= gBitTable[bank] << 0x1C;
}
else
{
gBattleExecBuffer |= gBitTable[bank];
}
}
void sub_803F850(u8 arg0)
{
s32 i;
for (i = 0; i < GetLinkPlayerCount(); i++)
gBattleExecBuffer |= gBitTable[arg0] << (i << 2);
gBattleExecBuffer &= ~(0x10000000 << arg0);
}
void CancelMultiTurnMoves(u8 bank)
{
gBattleMons[bank].status2 &= ~(STATUS2_MULTIPLETURNS);
gBattleMons[bank].status2 &= ~(STATUS2_LOCK_CONFUSE);
gBattleMons[bank].status2 &= ~(STATUS2_UPROAR);
gBattleMons[bank].status2 &= ~(STATUS2_BIDE);
gStatuses3[bank] &= ~(STATUS3_SEMI_INVULNERABLE);
gDisableStructs[bank].rolloutCounter1 = 0;
gDisableStructs[bank].furyCutterCounter = 0;
}
bool8 WasUnableToUseMove(u8 bank)
{
if (gProtectStructs[bank].prlzImmobility
|| gProtectStructs[bank].targetNotAffected
|| gProtectStructs[bank].usedImprisionedMove
|| gProtectStructs[bank].loveImmobility
|| gProtectStructs[bank].usedDisabledMove
|| gProtectStructs[bank].usedTauntedMove
|| gProtectStructs[bank].flag2Unknown
|| gProtectStructs[bank].flinchImmobility
|| gProtectStructs[bank].confusionSelfDmg)
return TRUE;
else
return FALSE;
}
void PrepareStringBattle(u16 stringId, u8 bank)
{
gActiveBank = bank;
EmitPrintString(0, stringId);
MarkBufferBankForExecution(gActiveBank);
}
void ResetSentPokesToOpponentValue(void)
{
s32 i;
u32 bits = 0;
gSentPokesToOpponent[0] = 0;
gSentPokesToOpponent[1] = 0;
for (i = 0; i < gNoOfAllBanks; i += 2)
bits |= gBitTable[gBattlePartyID[i]];
for (i = 1; i < gNoOfAllBanks; i += 2)
gSentPokesToOpponent[(i & BIT_MON) >> 1] = bits;
}
void sub_803F9EC(u8 bank)
{
s32 i = 0;
u32 bits = 0;
if (GetBankSide(bank) == SIDE_OPPONENT)
{
u8 id = ((bank & BIT_MON) >> 1);
gSentPokesToOpponent[id] = 0;
for (i = 0; i < gNoOfAllBanks; i += 2)
{
if (!(gAbsentBankFlags & gBitTable[i]))
bits |= gBitTable[gBattlePartyID[i]];
}
gSentPokesToOpponent[id] = bits;
}
}
void sub_803FA70(u8 bank)
{
if (GetBankSide(bank) == SIDE_OPPONENT)
{
sub_803F9EC(bank);
}
else
{
s32 i;
for (i = 1; i < gNoOfAllBanks; i++)
gSentPokesToOpponent[(i & BIT_MON) >> 1] |= gBitTable[gBattlePartyID[bank]];
}
}
void BattleScriptPush(const u8* bsPtr)
{
BATTLESCRIPTS_STACK->ptr[BATTLESCRIPTS_STACK->size++] = bsPtr;
}
void BattleScriptPushCursor(void)
{
BATTLESCRIPTS_STACK->ptr[BATTLESCRIPTS_STACK->size++] = gBattlescriptCurrInstr;
}
void BattleScriptPop(void)
{
gBattlescriptCurrInstr = BATTLESCRIPTS_STACK->ptr[--BATTLESCRIPTS_STACK->size];
}
u8 TrySetCantSelectMoveBattleScript(void)
{
u8 limitations = 0;
u16 move = gBattleMons[gActiveBank].moves[gBattleBufferB[gActiveBank][2]];
u8 holdEffect;
u16* choicedMove = &gBattleStruct->choicedMove[gActiveBank];
if (gDisableStructs[gActiveBank].disabledMove == move && move != 0)
{
gBattleScripting.bank = gActiveBank;
gCurrentMove = move;
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
{
gPalaceSelectionBattleScripts[gActiveBank] = BattleScript_SelectingDisabledMoveInPalace;
gProtectStructs[gActiveBank].flag_x10 = 1;
}
else
{
gSelectionBattleScripts[gActiveBank] = BattleScript_SelectingDisabledMove;
limitations = 1;
}
}
if (move == gLastMoves[gActiveBank] && move != MOVE_STRUGGLE && (gBattleMons[gActiveBank].status2 & STATUS2_TORMENT))
{
CancelMultiTurnMoves(gActiveBank);
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
{
gPalaceSelectionBattleScripts[gActiveBank] = BattleScript_SelectingTormentedMoveInPalace;
gProtectStructs[gActiveBank].flag_x10 = 1;
}
else
{
gSelectionBattleScripts[gActiveBank] = BattleScript_SelectingTormentedMove;
limitations++;
}
}
if (gDisableStructs[gActiveBank].tauntTimer1 != 0 && gBattleMoves[move].power == 0)
{
gCurrentMove = move;
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
{
gPalaceSelectionBattleScripts[gActiveBank] = BattleScript_SelectingNotAllowedMoveTauntInPalace;
gProtectStructs[gActiveBank].flag_x10 = 1;
}
else
{
gSelectionBattleScripts[gActiveBank] = BattleScript_SelectingNotAllowedMoveTaunt;
limitations++;
}
}
if (GetImprisonedMovesCount(gActiveBank, move))
{
gCurrentMove = move;
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
{
gPalaceSelectionBattleScripts[gActiveBank] = BattleScript_SelectingImprisionedMoveInPalace;
gProtectStructs[gActiveBank].flag_x10 = 1;
}
else
{
gSelectionBattleScripts[gActiveBank] = BattleScript_SelectingImprisionedMove;
limitations++;
}
}
if (gBattleMons[gActiveBank].item == ITEM_ENIGMA_BERRY)
holdEffect = gEnigmaBerries[gActiveBank].holdEffect;
else
holdEffect = ItemId_GetHoldEffect(gBattleMons[gActiveBank].item);
gStringBank = gActiveBank;
if (holdEffect == HOLD_EFFECT_CHOICE_BAND && *choicedMove != 0 && *choicedMove != 0xFFFF && *choicedMove != move)
{
gCurrentMove = *choicedMove;
gLastUsedItem = gBattleMons[gActiveBank].item;
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
{
gProtectStructs[gActiveBank].flag_x10 = 1;
}
else
{
gSelectionBattleScripts[gActiveBank] = BattleScript_SelectingNotAllowedMoveChoiceItem;
limitations++;
}
}
if (gBattleMons[gActiveBank].pp[gBattleBufferB[gActiveBank][2]] == 0)
{
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
{
gProtectStructs[gActiveBank].flag_x10 = 1;
}
else
{
gSelectionBattleScripts[gActiveBank] = BattleScript_SelectingMoveWithNoPP;
limitations++;
}
}
return limitations;
}
u8 CheckMoveLimitations(u8 bank, u8 unusableMoves, u8 check)
{
u8 holdEffect;
u16 *choicedMove = &gBattleStruct->choicedMove[bank];
s32 i;
if (gBattleMons[bank].item == ITEM_ENIGMA_BERRY)
holdEffect = gEnigmaBerries[bank].holdEffect;
else
holdEffect = ItemId_GetHoldEffect(gBattleMons[bank].item);
gStringBank = bank;
for (i = 0; i < BATTLE_BANKS_COUNT; i++)
{
if (gBattleMons[bank].moves[i] == 0 && check & MOVE_LIMITATION_ZEROMOVE)
unusableMoves |= gBitTable[i];
if (gBattleMons[bank].pp[i] == 0 && check & MOVE_LIMITATION_PP)
unusableMoves |= gBitTable[i];
if (gBattleMons[bank].moves[i] == gDisableStructs[bank].disabledMove && check & MOVE_LIMITATION_DISABLED)
unusableMoves |= gBitTable[i];
if (gBattleMons[bank].moves[i] == gLastMoves[bank] && check & MOVE_LIMITATION_TORMENTED && gBattleMons[bank].status2 & STATUS2_TORMENT)
unusableMoves |= gBitTable[i];
if (gDisableStructs[bank].tauntTimer1 && check & MOVE_LIMITATION_TAUNT && gBattleMoves[gBattleMons[bank].moves[i]].power == 0)
unusableMoves |= gBitTable[i];
if (GetImprisonedMovesCount(bank, gBattleMons[bank].moves[i]) && check & MOVE_LIMITATION_IMPRISION)
unusableMoves |= gBitTable[i];
if (gDisableStructs[bank].encoreTimer1 && gDisableStructs[bank].encoredMove != gBattleMons[bank].moves[i])
unusableMoves |= gBitTable[i];
if (holdEffect == HOLD_EFFECT_CHOICE_BAND && *choicedMove != 0 && *choicedMove != 0xFFFF && *choicedMove != gBattleMons[bank].moves[i])
unusableMoves |= gBitTable[i];
}
return unusableMoves;
}
bool8 AreAllMovesUnusable(void)
{
u8 unusable;
unusable = CheckMoveLimitations(gActiveBank, 0, 0xFF);
if (unusable == 0xF) // all moves are unusable
{
gProtectStructs[gActiveBank].onlyStruggle = 1;
gSelectionBattleScripts[gActiveBank] = BattleScript_NoMovesLeft;
}
else
{
gProtectStructs[gActiveBank].onlyStruggle = 0;
}
return (unusable == 0xF);
}
u8 GetImprisonedMovesCount(u8 bank, u16 move)
{
s32 i;
u8 imprisionedMoves = 0;
u8 bankSide = GetBankSide(bank);
for (i = 0; i < gNoOfAllBanks; i++)
{
if (bankSide != GetBankSide(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;
}
u8 UpdateTurnCounters(void)
{
u8 effect = 0;
s32 i;
for (gBankAttacker = 0; gBankAttacker < gNoOfAllBanks && gAbsentBankFlags & gBitTable[gBankAttacker]; gBankAttacker++)
{
}
for (gBankTarget = 0; gBankTarget < gNoOfAllBanks && gAbsentBankFlags & gBitTable[gBankTarget]; gBankTarget++)
{
}
do
{
u8 sideBank;
switch (gBattleStruct->turncountersTracker)
{
case 0:
for (i = 0; i < gNoOfAllBanks; i++)
{
gBanksByTurnOrder[i] = i;
}
for (i = 0; i < gNoOfAllBanks - 1; i++)
{
s32 j;
for (j = i + 1; j < gNoOfAllBanks; j++)
{
if (GetWhoStrikesFirst(gBanksByTurnOrder[i], gBanksByTurnOrder[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 1:
while (gBattleStruct->turnSideTracker < 2)
{
sideBank = gBattleStruct->turnSideTracker;
gActiveBank = gBankAttacker = gSideTimers[sideBank].reflectBank;
if (gSideAffecting[sideBank] & SIDE_STATUS_REFLECT)
{
if (--gSideTimers[sideBank].reflectTimer == 0)
{
gSideAffecting[sideBank] &= ~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 2:
while (gBattleStruct->turnSideTracker < 2)
{
sideBank = gBattleStruct->turnSideTracker;
gActiveBank = gBankAttacker = gSideTimers[sideBank].lightscreenBank;
if (gSideAffecting[sideBank] & SIDE_STATUS_LIGHTSCREEN)
{
if (--gSideTimers[sideBank].lightscreenTimer == 0)
{
gSideAffecting[sideBank] &= ~SIDE_STATUS_LIGHTSCREEN;
BattleScriptExecute(BattleScript_SideStatusWoreOff);
gBattleCommunication[MULTISTRING_CHOOSER] = sideBank;
PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_LIGHT_SCREEN);
effect++;
}
}
gBattleStruct->turnSideTracker++;
if (effect)
break;
}
if (!effect)
{
gBattleStruct->turncountersTracker++;
gBattleStruct->turnSideTracker = 0;
}
break;
case 3:
while (gBattleStruct->turnSideTracker < 2)
{
sideBank = gBattleStruct->turnSideTracker;
gActiveBank = gBankAttacker = gSideTimers[sideBank].mistBank;
if (gSideTimers[sideBank].mistTimer != 0
&& --gSideTimers[sideBank].mistTimer == 0)
{
gSideAffecting[sideBank] &= ~SIDE_STATUS_MIST;
BattleScriptExecute(BattleScript_SideStatusWoreOff);
gBattleCommunication[MULTISTRING_CHOOSER] = sideBank;
PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_MIST);
effect++;
}
gBattleStruct->turnSideTracker++;
if (effect)
break;
}
if (!effect)
{
gBattleStruct->turncountersTracker++;
gBattleStruct->turnSideTracker = 0;
}
break;
case 4:
while (gBattleStruct->turnSideTracker < 2)
{
sideBank = gBattleStruct->turnSideTracker;
gActiveBank = gBankAttacker = gSideTimers[sideBank].safeguardBank;
if (gSideAffecting[sideBank] & SIDE_STATUS_SAFEGUARD)
{
if (--gSideTimers[sideBank].safeguardTimer == 0)
{
gSideAffecting[sideBank] &= ~SIDE_STATUS_SAFEGUARD;
BattleScriptExecute(BattleScript_SafeguardEnds);
effect++;
}
}
gBattleStruct->turnSideTracker++;
if (effect)
break;
}
if (!effect)
{
gBattleStruct->turncountersTracker++;
gBattleStruct->turnSideTracker = 0;
}
break;
case 5:
while (gBattleStruct->turnSideTracker < gNoOfAllBanks)
{
gActiveBank = gBanksByTurnOrder[gBattleStruct->turnSideTracker];
if (gWishFutureKnock.wishCounter[gActiveBank] != 0
&& --gWishFutureKnock.wishCounter[gActiveBank] == 0
&& gBattleMons[gActiveBank].hp != 0)
{
gBankTarget = gActiveBank;
BattleScriptExecute(BattleScript_WishComesTrue);
effect++;
}
gBattleStruct->turnSideTracker++;
if (effect)
break;
}
if (!effect)
{
gBattleStruct->turncountersTracker++;
}
break;
case 6:
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 7:
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 8:
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 9:
if (gBattleWeather & WEATHER_HAIL)
{
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 10:
effect++;
break;
}
} while (effect == 0);
return (gBattleMainFunc != BattleTurnPassed);
}
#define TURNBASED_MAX_CASE 19
u8 TurnBasedEffects(void)
{
u8 effect = 0;
gHitMarker |= (HITMARKER_GRUDGE | HITMARKER_x20);
while (gBattleStruct->turnEffectsBank < gNoOfAllBanks && gBattleStruct->turnEffectsTracker <= TURNBASED_MAX_CASE)
{
gActiveBank = gBankAttacker = gBanksByTurnOrder[gBattleStruct->turnEffectsBank];
if (gAbsentBankFlags & gBitTable[gActiveBank])
{
gBattleStruct->turnEffectsBank++;
}
else
{
switch (gBattleStruct->turnEffectsTracker)
{
case 0: // ingrain
if ((gStatuses3[gActiveBank] & STATUS3_ROOTED)
&& gBattleMons[gActiveBank].hp != gBattleMons[gActiveBank].maxHP
&& gBattleMons[gActiveBank].hp != 0)
{
gBattleMoveDamage = gBattleMons[gActiveBank].maxHP / 16;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
gBattleMoveDamage *= -1;
BattleScriptExecute(BattleScript_IngrainTurnHeal);
effect++;
}
gBattleStruct->turnEffectsTracker++;
break;
case 1: // end turn abilities
if (AbilityBattleEffects(ABILITYEFFECT_ENDTURN, gActiveBank, 0, 0, 0))
effect++;
gBattleStruct->turnEffectsTracker++;
break;
case 2: // item effects
if (ItemBattleEffects(1, gActiveBank, 0))
effect++;
gBattleStruct->turnEffectsTracker++;
break;
case 18: // item effects again
if (ItemBattleEffects(1, gActiveBank, 1))
effect++;
gBattleStruct->turnEffectsTracker++;
break;
case 3: // leech seed
if ((gStatuses3[gActiveBank] & STATUS3_LEECHSEED)
&& gBattleMons[gStatuses3[gActiveBank] & STATUS3_LEECHSEED_BANK].hp != 0
&& gBattleMons[gActiveBank].hp != 0)
{
gBankTarget = gStatuses3[gActiveBank] & STATUS3_LEECHSEED_BANK; //funny how the 'target' is actually the bank that receives HP
gBattleMoveDamage = gBattleMons[gActiveBank].maxHP / 8;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
gBattleScripting.animArg1 = gBankTarget;
gBattleScripting.animArg2 = gBankAttacker;
BattleScriptExecute(BattleScript_LeechSeedTurnDrain);
effect++;
}
gBattleStruct->turnEffectsTracker++;
break;
case 4: // poison
if ((gBattleMons[gActiveBank].status1 & STATUS_POISON) && gBattleMons[gActiveBank].hp != 0)
{
gBattleMoveDamage = gBattleMons[gActiveBank].maxHP / 8;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
BattleScriptExecute(BattleScript_PoisonTurnDmg);
effect++;
}
gBattleStruct->turnEffectsTracker++;
break;
case 5: // toxic poison
if ((gBattleMons[gActiveBank].status1 & STATUS_TOXIC_POISON) && gBattleMons[gActiveBank].hp != 0)
{
gBattleMoveDamage = gBattleMons[gActiveBank].maxHP / 16;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
if ((gBattleMons[gActiveBank].status1 & 0xF00) != 0xF00) // not 16 turns
gBattleMons[gActiveBank].status1 += 0x100;
gBattleMoveDamage *= (gBattleMons[gActiveBank].status1 & 0xF00) >> 8;
BattleScriptExecute(BattleScript_PoisonTurnDmg);
effect++;
}
gBattleStruct->turnEffectsTracker++;
break;
case 6: // burn
if ((gBattleMons[gActiveBank].status1 & STATUS_BURN) && gBattleMons[gActiveBank].hp != 0)
{
gBattleMoveDamage = gBattleMons[gActiveBank].maxHP / 8;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
BattleScriptExecute(BattleScript_BurnTurnDmg);
effect++;
}
gBattleStruct->turnEffectsTracker++;
break;
case 7: // spooky nightmares
if ((gBattleMons[gActiveBank].status2 & STATUS2_NIGHTMARE) && gBattleMons[gActiveBank].hp != 0)
{
// R/S does not perform this sleep check, which causes the nighmare effect to
// persist even after the affected Pokemon has been awakened by Shed Skin
if (gBattleMons[gActiveBank].status1 & STATUS_SLEEP)
{
gBattleMoveDamage = gBattleMons[gActiveBank].maxHP / 4;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
BattleScriptExecute(BattleScript_NightmareTurnDmg);
effect++;
}
else
{
gBattleMons[gActiveBank].status2 &= ~STATUS2_NIGHTMARE;
}
}
gBattleStruct->turnEffectsTracker++;
break;
case 8: // curse
if ((gBattleMons[gActiveBank].status2 & STATUS2_CURSED) && gBattleMons[gActiveBank].hp != 0)
{
gBattleMoveDamage = gBattleMons[gActiveBank].maxHP / 4;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
BattleScriptExecute(BattleScript_CurseTurnDmg);
effect++;
}
gBattleStruct->turnEffectsTracker++;
break;
case 9: // wrap
if ((gBattleMons[gActiveBank].status2 & STATUS2_WRAPPED) && gBattleMons[gActiveBank].hp != 0)
{
gBattleMons[gActiveBank].status2 -= 0x2000;
if (gBattleMons[gActiveBank].status2 & STATUS2_WRAPPED) // damaged by wrap
{
// This is the only way I could get this array access to match.
gBattleScripting.animArg1 = *(gBattleStruct->wrappedMove + gActiveBank * 2 + 0);
gBattleScripting.animArg2 = *(gBattleStruct->wrappedMove + gActiveBank * 2 + 1);
gBattleTextBuff1[0] = B_BUFF_PLACEHOLDER_BEGIN;
gBattleTextBuff1[1] = B_BUFF_MOVE;
gBattleTextBuff1[2] = *(gBattleStruct->wrappedMove + gActiveBank * 2 + 0);
gBattleTextBuff1[3] = *(gBattleStruct->wrappedMove + gActiveBank * 2 + 1);
gBattleTextBuff1[4] = EOS;
gBattlescriptCurrInstr = BattleScript_WrapTurnDmg;
gBattleMoveDamage = gBattleMons[gActiveBank].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 + gActiveBank * 2 + 0);
gBattleTextBuff1[3] = *(gBattleStruct->wrappedMove + gActiveBank * 2 + 1);
gBattleTextBuff1[4] = EOS;
gBattlescriptCurrInstr = BattleScript_WrapEnds;
}
BattleScriptExecute(gBattlescriptCurrInstr);
effect++;
}
gBattleStruct->turnEffectsTracker++;
break;
case 10: // uproar
if (gBattleMons[gActiveBank].status2 & STATUS2_UPROAR)
{
for (gBankAttacker = 0; gBankAttacker < gNoOfAllBanks; gBankAttacker++)
{
if ((gBattleMons[gBankAttacker].status1 & STATUS_SLEEP)
&& gBattleMons[gBankAttacker].ability != ABILITY_SOUNDPROOF)
{
gBattleMons[gBankAttacker].status1 &= ~(STATUS_SLEEP);
gBattleMons[gBankAttacker].status2 &= ~(STATUS2_NIGHTMARE);
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
BattleScriptExecute(BattleScript_MonWokeUpInUproar);
gActiveBank = gBankAttacker;
EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1);
MarkBufferBankForExecution(gActiveBank);
break;
}
}
if (gBankAttacker != gNoOfAllBanks)
{
effect = 2; // a pokemon was awaken
break;
}
else
{
gBankAttacker = gActiveBank;
gBattleMons[gActiveBank].status2 -= 0x10; // uproar timer goes down
if (WasUnableToUseMove(gActiveBank))
{
CancelMultiTurnMoves(gActiveBank);
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
}
else if (gBattleMons[gActiveBank].status2 & STATUS2_UPROAR)
{
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
gBattleMons[gActiveBank].status2 |= STATUS2_MULTIPLETURNS;
}
else
{
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
CancelMultiTurnMoves(gActiveBank);
}
BattleScriptExecute(BattleScript_PrintUproarOverTurns);
effect = 1;
}
}
if (effect != 2)
gBattleStruct->turnEffectsTracker++;
break;
case 11: // thrash
if (gBattleMons[gActiveBank].status2 & STATUS2_LOCK_CONFUSE)
{
gBattleMons[gActiveBank].status2 -= 0x400;
if (WasUnableToUseMove(gActiveBank))
CancelMultiTurnMoves(gActiveBank);
else if (!(gBattleMons[gActiveBank].status2 & STATUS2_LOCK_CONFUSE)
&& (gBattleMons[gActiveBank].status2 & STATUS2_MULTIPLETURNS))
{
gBattleMons[gActiveBank].status2 &= ~(STATUS2_MULTIPLETURNS);
if (!(gBattleMons[gActiveBank].status2 & STATUS2_CONFUSION))
{
gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_CONFUSION | MOVE_EFFECT_AFFECTS_USER;
SetMoveEffect(1, 0);
if (gBattleMons[gActiveBank].status2 & STATUS2_CONFUSION)
BattleScriptExecute(BattleScript_ThrashConfuses);
effect++;
}
}
}
gBattleStruct->turnEffectsTracker++;
break;
case 12: // disable
if (gDisableStructs[gActiveBank].disableTimer1 != 0)
{
int i;
for (i = 0; i < 4; i++)
{
if (gDisableStructs[gActiveBank].disabledMove == gBattleMons[gActiveBank].moves[i])
break;
}
if (i == 4) // pokemon does not have the disabled move anymore
{
gDisableStructs[gActiveBank].disabledMove = 0;
gDisableStructs[gActiveBank].disableTimer1 = 0;
}
else if (--gDisableStructs[gActiveBank].disableTimer1 == 0) // disable ends
{
gDisableStructs[gActiveBank].disabledMove = 0;
BattleScriptExecute(BattleScript_DisabledNoMore);
effect++;
}
}
gBattleStruct->turnEffectsTracker++;
break;
case 13: // encore
if (gDisableStructs[gActiveBank].encoreTimer1 != 0)
{
if (gBattleMons[gActiveBank].moves[gDisableStructs[gActiveBank].encoredMovePos] != gDisableStructs[gActiveBank].encoredMove) // pokemon does not have the encored move anymore
{
gDisableStructs[gActiveBank].encoredMove = 0;
gDisableStructs[gActiveBank].encoreTimer1 = 0;
}
else if (--gDisableStructs[gActiveBank].encoreTimer1 == 0
|| gBattleMons[gActiveBank].pp[gDisableStructs[gActiveBank].encoredMovePos] == 0)
{
gDisableStructs[gActiveBank].encoredMove = 0;
gDisableStructs[gActiveBank].encoreTimer1 = 0;
BattleScriptExecute(BattleScript_EncoredNoMore);
effect++;
}
}
gBattleStruct->turnEffectsTracker++;
break;
case 14: // lock-on decrement
if (gStatuses3[gActiveBank] & STATUS3_ALWAYS_HITS)
gStatuses3[gActiveBank] -= 0x8;
gBattleStruct->turnEffectsTracker++;
break;
case 15: // charge
if (gDisableStructs[gActiveBank].chargeTimer1 && --gDisableStructs[gActiveBank].chargeTimer1 == 0)
gStatuses3[gActiveBank] &= ~STATUS3_CHARGED_UP;
gBattleStruct->turnEffectsTracker++;
break;
case 16: // taunt
if (gDisableStructs[gActiveBank].tauntTimer1)
gDisableStructs[gActiveBank].tauntTimer1--;
gBattleStruct->turnEffectsTracker++;
break;
case 17: // yawn
if (gStatuses3[gActiveBank] & STATUS3_YAWN)
{
gStatuses3[gActiveBank] -= 0x800;
if (!(gStatuses3[gActiveBank] & STATUS3_YAWN) && !(gBattleMons[gActiveBank].status1 & STATUS_ANY)
&& gBattleMons[gActiveBank].ability != ABILITY_VITAL_SPIRIT
&& gBattleMons[gActiveBank].ability != ABILITY_INSOMNIA && !UproarWakeUpCheck(gActiveBank))
{
CancelMultiTurnMoves(gActiveBank);
gBattleMons[gActiveBank].status1 |= (Random() & 3) + 2;
EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1);
MarkBufferBankForExecution(gActiveBank);
gEffectBank = gActiveBank;
BattleScriptExecute(BattleScript_YawnMakesAsleep);
effect++;
}
}
gBattleStruct->turnEffectsTracker++;
break;
case 19: // done
gBattleStruct->turnEffectsTracker = 0;
gBattleStruct->turnEffectsBank++;
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->wishPerishSongBank < gNoOfAllBanks)
{
gActiveBank = gBattleStruct->wishPerishSongBank;
if (gAbsentBankFlags & gBitTable[gActiveBank])
{
gBattleStruct->wishPerishSongBank++;
continue;
}
gBattleStruct->wishPerishSongBank++;
if (gWishFutureKnock.futureSightCounter[gActiveBank] != 0
&& --gWishFutureKnock.futureSightCounter[gActiveBank] == 0
&& gBattleMons[gActiveBank].hp != 0)
{
if (gWishFutureKnock.futureSightMove[gActiveBank] == MOVE_FUTURE_SIGHT)
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
else
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
PREPARE_MOVE_BUFFER(gBattleTextBuff1, gWishFutureKnock.futureSightMove[gActiveBank]);
gBankTarget = gActiveBank;
gBankAttacker = gWishFutureKnock.futureSightAttacker[gActiveBank];
gBattleMoveDamage = gWishFutureKnock.futureSightDmg[gActiveBank];
gSpecialStatuses[gBankTarget].moveturnLostHP = 0xFFFF;
BattleScriptExecute(BattleScript_MonTookFutureAttack);
if (gWishFutureKnock.futureSightCounter[gActiveBank] == 0
&& gWishFutureKnock.futureSightCounter[gActiveBank ^ BIT_MON] == 0)
{
gSideAffecting[GET_BANK_SIDE(gBankTarget)] &= ~(SIDE_STATUS_FUTUREATTACK);
}
return TRUE;
}
}
// Why do I have to keep doing this to match?
{
u8 *state = &gBattleStruct->wishPerishSongState;
*state = 1;
gBattleStruct->wishPerishSongBank = 0;
}
// fall through
case 1:
while (gBattleStruct->wishPerishSongBank < gNoOfAllBanks)
{
gActiveBank = gBankAttacker = gBanksByTurnOrder[gBattleStruct->wishPerishSongBank];
if (gAbsentBankFlags & gBitTable[gActiveBank])
{
gBattleStruct->wishPerishSongBank++;
continue;
}
gBattleStruct->wishPerishSongBank++;
if (gStatuses3[gActiveBank] & STATUS3_PERISH_SONG)
{
PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff1, 1, gDisableStructs[gActiveBank].perishSongTimer1);
if (gDisableStructs[gActiveBank].perishSongTimer1 == 0)
{
gStatuses3[gActiveBank] &= ~STATUS3_PERISH_SONG;
gBattleMoveDamage = gBattleMons[gActiveBank].hp;
gBattlescriptCurrInstr = BattleScript_PerishSongTakesLife;
}
else
{
gDisableStructs[gActiveBank].perishSongTimer1--;
gBattlescriptCurrInstr = BattleScript_PerishSongCountGoesDown;
}
BattleScriptExecute(gBattlescriptCurrInstr);
return TRUE;
}
}
// Hm...
{
u8 *state = &gBattleStruct->wishPerishSongState;
*state = 2;
gBattleStruct->wishPerishSongBank = 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
{
int i;
switch (gBattleStruct->faintedActionsState)
{
case 0:
gBattleStruct->faintedActionsBank = 0;
gBattleStruct->faintedActionsState++;
for (i = 0; i < gNoOfAllBanks; i++)
{
if (gAbsentBankFlags & gBitTable[i] && !sub_80423F4(i, 6, 6))
gAbsentBankFlags &= ~(gBitTable[i]);
}
// fall through
case 1:
do
{
gBank1 = gBankTarget = gBattleStruct->faintedActionsBank;
if (gBattleMons[gBattleStruct->faintedActionsBank].hp == 0
&& !(gBattleStruct->field_DF & gBitTable[gBattlePartyID[gBattleStruct->faintedActionsBank]])
&& !(gAbsentBankFlags & gBitTable[gBattleStruct->faintedActionsBank]))
{
BattleScriptExecute(BattleScript_GiveExp);
gBattleStruct->faintedActionsState = 2;
return TRUE;
}
} while (++gBattleStruct->faintedActionsBank != gNoOfAllBanks);
gBattleStruct->faintedActionsState = 3;
break;
case 2:
sub_803F9EC(gBank1);
if (++gBattleStruct->faintedActionsBank == gNoOfAllBanks)
gBattleStruct->faintedActionsState = 3;
else
gBattleStruct->faintedActionsState = 1;
break;
case 3:
gBattleStruct->faintedActionsBank = 0;
gBattleStruct->faintedActionsState++;
// fall through
case 4:
do
{
gBank1 = gBankTarget = gBattleStruct->faintedActionsBank;
if (gBattleMons[gBattleStruct->faintedActionsBank].hp == 0
&& !(gAbsentBankFlags & gBitTable[gBattleStruct->faintedActionsBank]))
{
BattleScriptExecute(BattleScript_HandleFaintedMon);
gBattleStruct->faintedActionsState = 5;
return TRUE;
}
} while (++gBattleStruct->faintedActionsBank != gNoOfAllBanks);
gBattleStruct->faintedActionsState = 6;
break;
case 5:
if (++gBattleStruct->faintedActionsBank == gNoOfAllBanks)
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, 1) || 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)
{
int i;
for (i = 0; i < gNoOfAllBanks; i++)
{
if ((gBattleMons[i].status2 & STATUS2_RAGE) && gChosenMovesByBanks[i] != MOVE_RAGE)
gBattleMons[i].status2 &= ~(STATUS2_RAGE);
}
}
#define ATKCANCELLER_MAX_CASE 14
u8 AtkCanceller_UnableToUseMove(void)
{
u8 effect = 0;
s32 *bideDmg = &gBattleScripting.bideDmg;
do
{
switch (gBattleStruct->atkCancellerTracker)
{
case 0: // flags clear
gBattleMons[gBankAttacker].status2 &= ~(STATUS2_DESTINY_BOND);
gStatuses3[gBankAttacker] &= ~(STATUS3_GRUDGE);
gBattleStruct->atkCancellerTracker++;
break;
case 1: // check being asleep
if (gBattleMons[gBankAttacker].status1 & STATUS_SLEEP)
{
if (UproarWakeUpCheck(gBankAttacker))
{
gBattleMons[gBankAttacker].status1 &= ~(STATUS_SLEEP);
gBattleMons[gBankAttacker].status2 &= ~(STATUS2_NIGHTMARE);
BattleScriptPushCursor();
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
gBattlescriptCurrInstr = BattleScript_MoveUsedWokeUp;
effect = 2;
}
else
{
u8 toSub;
if (gBattleMons[gBankAttacker].ability == ABILITY_EARLY_BIRD)
toSub = 2;
else
toSub = 1;
if ((gBattleMons[gBankAttacker].status1 & STATUS_SLEEP) < toSub)
gBattleMons[gBankAttacker].status1 &= ~(STATUS_SLEEP);
else
gBattleMons[gBankAttacker].status1 -= toSub;
if (gBattleMons[gBankAttacker].status1 & STATUS_SLEEP)
{
if (gCurrentMove != MOVE_SNORE && gCurrentMove != MOVE_SLEEP_TALK)
{
gBattlescriptCurrInstr = BattleScript_MoveUsedIsAsleep;
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
effect = 2;
}
}
else
{
gBattleMons[gBankAttacker].status2 &= ~(STATUS2_NIGHTMARE);
BattleScriptPushCursor();
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
gBattlescriptCurrInstr = BattleScript_MoveUsedWokeUp;
effect = 2;
}
}
}
gBattleStruct->atkCancellerTracker++;
break;
case 2: // check being frozen
if (gBattleMons[gBankAttacker].status1 & STATUS_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[gBankAttacker].status1 &= ~(STATUS_FREEZE);
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_MoveUsedUnfroze;
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
}
effect = 2;
}
gBattleStruct->atkCancellerTracker++;
break;
case 3: // truant
if (gBattleMons[gBankAttacker].ability == ABILITY_TRUANT && gDisableStructs[gBankAttacker].truantCounter)
{
CancelMultiTurnMoves(gBankAttacker);
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
gBattlescriptCurrInstr = BattleScript_MoveUsedLoafingAround;
gBattleMoveFlags |= MOVESTATUS_MISSED;
effect = 1;
}
gBattleStruct->atkCancellerTracker++;
break;
case 4: // recharge
if (gBattleMons[gBankAttacker].status2 & STATUS2_RECHARGE)
{
gBattleMons[gBankAttacker].status2 &= ~(STATUS2_RECHARGE);
gDisableStructs[gBankAttacker].rechargeCounter = 0;
CancelMultiTurnMoves(gBankAttacker);
gBattlescriptCurrInstr = BattleScript_MoveUsedMustRecharge;
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
effect = 1;
}
gBattleStruct->atkCancellerTracker++;
break;
case 5: // flinch
if (gBattleMons[gBankAttacker].status2 & STATUS2_FLINCHED)
{
gBattleMons[gBankAttacker].status2 &= ~(STATUS2_FLINCHED);
gProtectStructs[gBankAttacker].flinchImmobility = 1;
CancelMultiTurnMoves(gBankAttacker);
gBattlescriptCurrInstr = BattleScript_MoveUsedFlinched;
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
effect = 1;
}
gBattleStruct->atkCancellerTracker++;
break;
case 6: // disabled move
if (gDisableStructs[gBankAttacker].disabledMove == gCurrentMove && gDisableStructs[gBankAttacker].disabledMove != 0)
{
gProtectStructs[gBankAttacker].usedDisabledMove = 1;
gBattleScripting.bank = gBankAttacker;
CancelMultiTurnMoves(gBankAttacker);
gBattlescriptCurrInstr = BattleScript_MoveUsedIsDisabled;
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
effect = 1;
}
gBattleStruct->atkCancellerTracker++;
break;
case 7: // taunt
if (gDisableStructs[gBankAttacker].tauntTimer1 && gBattleMoves[gCurrentMove].power == 0)
{
gProtectStructs[gBankAttacker].usedTauntedMove = 1;
CancelMultiTurnMoves(gBankAttacker);
gBattlescriptCurrInstr = BattleScript_MoveUsedIsTaunted;
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
effect = 1;
}
gBattleStruct->atkCancellerTracker++;
break;
case 8: // imprisoned
if (GetImprisonedMovesCount(gBankAttacker, gCurrentMove))
{
gProtectStructs[gBankAttacker].usedImprisionedMove = 1;
CancelMultiTurnMoves(gBankAttacker);
gBattlescriptCurrInstr = BattleScript_MoveUsedIsImprisoned;
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
effect = 1;
}
gBattleStruct->atkCancellerTracker++;
break;
case 9: // confusion
if (gBattleMons[gBankAttacker].status2 & STATUS2_CONFUSION)
{
gBattleMons[gBankAttacker].status2--;
if (gBattleMons[gBankAttacker].status2 & STATUS2_CONFUSION)
{
if (Random() & 1)
{
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
BattleScriptPushCursor();
}
else // confusion dmg
{
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
gBankTarget = gBankAttacker;
gBattleMoveDamage = CalculateBaseDamage(&gBattleMons[gBankAttacker], &gBattleMons[gBankAttacker], MOVE_POUND, 0, 40, 0, gBankAttacker, gBankAttacker);
gProtectStructs[gBankAttacker].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 10: // paralysis
if ((gBattleMons[gBankAttacker].status1 & STATUS_PARALYSIS) && (Random() % 4) == 0)
{
gProtectStructs[gBankAttacker].prlzImmobility = 1;
// This is removed in Emerald for some reason
//CancelMultiTurnMoves(gBankAttacker);
gBattlescriptCurrInstr = BattleScript_MoveUsedIsParalyzed;
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
effect = 1;
}
gBattleStruct->atkCancellerTracker++;
break;
case 11: // infatuation
if (gBattleMons[gBankAttacker].status2 & STATUS2_INFATUATION)
{
gBattleScripting.bank = CountTrailingZeroBits((gBattleMons[gBankAttacker].status2 & STATUS2_INFATUATION) >> 0x10);
if (Random() & 1)
BattleScriptPushCursor();
else
{
BattleScriptPush(BattleScript_MoveUsedIsParalyzedCantAttack);
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
gProtectStructs[gBankAttacker].loveImmobility = 1;
CancelMultiTurnMoves(gBankAttacker);
}
gBattlescriptCurrInstr = BattleScript_MoveUsedIsInLove;
effect = 1;
}
gBattleStruct->atkCancellerTracker++;
break;
case 12: // bide
if (gBattleMons[gBankAttacker].status2 & STATUS2_BIDE)
{
gBattleMons[gBankAttacker].status2 -= 0x100;
if (gBattleMons[gBankAttacker].status2 & STATUS2_BIDE)
gBattlescriptCurrInstr = BattleScript_BideStoringEnergy;
else
{
// This is removed in Emerald for some reason
//gBattleMons[gBankAttacker].status2 &= ~(STATUS2_MULTIPLETURNS);
if (gTakenDmg[gBankAttacker])
{
gCurrentMove = MOVE_BIDE;
*bideDmg = gTakenDmg[gBankAttacker] * 2;
gBankTarget = gTakenDmgBanks[gBankAttacker];
if (gAbsentBankFlags & gBitTable[gBankTarget])
gBankTarget = GetMoveTarget(MOVE_BIDE, 1);
gBattlescriptCurrInstr = BattleScript_BideAttack;
}
else
gBattlescriptCurrInstr = BattleScript_BideNoEnergyToAttack;
}
effect = 1;
}
gBattleStruct->atkCancellerTracker++;
break;
case 13: // move thawing
if (gBattleMons[gBankAttacker].status1 & STATUS_FREEZE)
{
if (gBattleMoves[gCurrentMove].effect == EFFECT_THAW_HIT)
{
gBattleMons[gBankAttacker].status1 &= ~(STATUS_FREEZE);
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_MoveUsedUnfroze;
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
}
effect = 2;
}
gBattleStruct->atkCancellerTracker++;
break;
case ATKCANCELLER_MAX_CASE:
break;
}
} while (gBattleStruct->atkCancellerTracker != ATKCANCELLER_MAX_CASE && effect == 0);
if (effect == 2)
{
gActiveBank = gBankAttacker;
EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1);
MarkBufferBankForExecution(gActiveBank);
}
return effect;
}
bool8 sub_80423F4(u8 bank, u8 r1, u8 r2)
{
struct Pokemon* party;
u8 r7;
u8 r6;
s32 i;
if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE))
return FALSE;
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
{
if (GetBankSide(bank) == SIDE_PLAYER)
party = gPlayerParty;
else
party = gEnemyParty;
r6 = ((bank & 2) / 2);
for (i = r6 * 3; i < r6 * 3 + 3; i++)
{
if (GetMonData(&party[i], MON_DATA_HP) != 0
&& GetMonData(&party[i], MON_DATA_SPECIES2) != 0
&& GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_EGG)
break;
}
return (i == r6 * 3 + 3);
}
else if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
{
if (gBattleTypeFlags & BATTLE_TYPE_x800000)
{
if (GetBankSide(bank) == SIDE_PLAYER)
{
party = gPlayerParty;
r7 = GetBankMultiplayerId(bank);
r6 = sub_806D82C(r7);
}
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 = bank ^ 1;
r6 = (var != 0) ? 1 : 0;
}
}
else
{
r7 = GetBankMultiplayerId(bank);
if (GetBankSide(bank) == SIDE_PLAYER)
party = gPlayerParty;
else
party = gEnemyParty;
r6 = sub_806D82C(r7);
}
for (i = r6 * 3; i < r6 * 3 + 3; i++)
{
if (GetMonData(&party[i], MON_DATA_HP) != 0
&& GetMonData(&party[i], MON_DATA_SPECIES2) != 0
&& GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_EGG)
break;
}
return (i == r6 * 3 + 3);
}
else if ((gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) && GetBankSide(bank) == SIDE_OPPONENT)
{
party = gEnemyParty;
if (bank == 1)
r6 = 0;
else
r6 = 3;
for (i = r6; i < r6 + 3; i++)
{
if (GetMonData(&party[i], MON_DATA_HP) != 0
&& GetMonData(&party[i], MON_DATA_SPECIES2) != 0
&& GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_EGG)
break;
}
return (i == r6 + 3);
}
else
{
if (GetBankSide(bank) == SIDE_OPPONENT)
{
r7 = GetBankByIdentity(IDENTITY_OPPONENT_MON1);
r6 = GetBankByIdentity(IDENTITY_OPPONENT_MON2);
party = gEnemyParty;
}
else
{
r7 = GetBankByIdentity(IDENTITY_PLAYER_MON1);
r6 = GetBankByIdentity(IDENTITY_PLAYER_MON2);
party = gPlayerParty;
}
if (r1 == 6)
r1 = gBattlePartyID[r7];
if (r2 == 6)
r2 = gBattlePartyID[r6];
for (i = 0; i < 6; i++)
{
if (GetMonData(&party[i], MON_DATA_HP) != 0
&& GetMonData(&party[i], MON_DATA_SPECIES2) != 0
&& GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_EGG
// FIXME: Using index[array] instead of array[index] is BAD!
&& i != r1 && i != r2 && i != r7[gBattleStruct->monToSwitchIntoId] && i != r6[gBattleStruct->monToSwitchIntoId])
break;
}
return (i == 6);
}
}
enum
{
CASTFORM_NO_CHANGE, //0
CASTFORM_TO_NORMAL, //1
CASTFORM_TO_FIRE, //2
CASTFORM_TO_WATER, //3
CASTFORM_TO_ICE, //4
};
u8 CastformDataTypeChange(u8 bank)
{
u8 formChange = 0;
if (gBattleMons[bank].species != SPECIES_CASTFORM || gBattleMons[bank].ability != ABILITY_FORECAST || gBattleMons[bank].hp == 0)
return CASTFORM_NO_CHANGE;
if (!WEATHER_HAS_EFFECT && gBattleMons[bank].type1 != TYPE_NORMAL && gBattleMons[bank].type2 != TYPE_NORMAL)
{
gBattleMons[bank].type1 = TYPE_NORMAL;
gBattleMons[bank].type2 = TYPE_NORMAL;
return CASTFORM_TO_NORMAL;
}
if (!WEATHER_HAS_EFFECT)
return CASTFORM_NO_CHANGE;
if (!(gBattleWeather & (WEATHER_RAIN_ANY | WEATHER_SUN_ANY | WEATHER_HAIL)) && gBattleMons[bank].type1 != TYPE_NORMAL && gBattleMons[bank].type2 != TYPE_NORMAL)
{
gBattleMons[bank].type1 = TYPE_NORMAL;
gBattleMons[bank].type2 = TYPE_NORMAL;
formChange = CASTFORM_TO_NORMAL;
}
if (gBattleWeather & WEATHER_SUN_ANY && gBattleMons[bank].type1 != TYPE_FIRE && gBattleMons[bank].type2 != TYPE_FIRE)
{
gBattleMons[bank].type1 = TYPE_FIRE;
gBattleMons[bank].type2 = TYPE_FIRE;
formChange = CASTFORM_TO_FIRE;
}
if (gBattleWeather & WEATHER_RAIN_ANY && gBattleMons[bank].type1 != TYPE_WATER && gBattleMons[bank].type2 != TYPE_WATER)
{
gBattleMons[bank].type1 = TYPE_WATER;
gBattleMons[bank].type2 = TYPE_WATER;
formChange = CASTFORM_TO_WATER;
}
if (gBattleWeather & WEATHER_HAIL && gBattleMons[bank].type1 != TYPE_ICE && gBattleMons[bank].type2 != TYPE_ICE)
{
gBattleMons[bank].type1 = TYPE_ICE;
gBattleMons[bank].type2 = 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 bank, u8 ability, u8 special, u16 moveArg)
{
u8 effect = 0;
struct Pokemon *pokeAtk;
struct Pokemon *pokeDef;
u16 speciesAtk;
u16 speciesDef;
u32 pidAtk;
u32 pidDef;
if (gBankAttacker >= gNoOfAllBanks)
gBankAttacker = bank;
if (GetBankSide(gBankAttacker) == SIDE_PLAYER)
pokeAtk = &gPlayerParty[gBattlePartyID[gBankAttacker]];
else
pokeAtk = &gEnemyParty[gBattlePartyID[gBankAttacker]];
if (gBankTarget >= gNoOfAllBanks)
gBankTarget = bank;
if (GetBankSide(gBankTarget) == SIDE_PLAYER)
pokeDef = &gPlayerParty[gBattlePartyID[gBankTarget]];
else
pokeDef = &gEnemyParty[gBattlePartyID[gBankTarget]];
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[bank].ability;
if (moveArg)
move = moveArg;
else
move = gCurrentMove;
GET_MOVE_TYPE(move, moveType);
switch (caseID)
{
case ABILITYEFFECT_ON_SWITCHIN: // 0
if (gBankAttacker >= gNoOfAllBanks)
gBankAttacker = bank;
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.bank = bank;
effect++;
}
break;
case 8:
if (!(gBattleWeather & WEATHER_SANDSTORM_ANY))
{
gBattleWeather = (WEATHER_SANDSTORM_PERMANENT | WEATHER_SANDSTORM_TEMPORARY);
gBattleScripting.animArg1 = B_ANIM_SANDSTORM_CONTINUES;
gBattleScripting.bank = bank;
effect++;
}
break;
case 12:
if (!(gBattleWeather & WEATHER_SUN_ANY))
{
gBattleWeather = (WEATHER_SUN_PERMANENT | WEATHER_SUN_TEMPORARY);
gBattleScripting.animArg1 = B_ANIM_SUN_CONTINUES;
gBattleScripting.bank = bank;
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.bank = bank;
effect++;
}
break;
case ABILITY_SAND_STREAM:
if (!(gBattleWeather & WEATHER_SANDSTORM_PERMANENT))
{
gBattleWeather = (WEATHER_SANDSTORM_PERMANENT | WEATHER_SANDSTORM_TEMPORARY);
BattleScriptPushCursorAndCallback(BattleScript_SandstreamActivates);
gBattleScripting.bank = bank;
effect++;
}
break;
case ABILITY_DROUGHT:
if (!(gBattleWeather & WEATHER_SUN_PERMANENT))
{
gBattleWeather = (WEATHER_SUN_PERMANENT | WEATHER_SUN_TEMPORARY);
BattleScriptPushCursorAndCallback(BattleScript_DroughtActivates);
gBattleScripting.bank = bank;
effect++;
}
break;
case ABILITY_INTIMIDATE:
if (!(gSpecialStatuses[bank].intimidatedPoke))
{
gStatuses3[bank] |= STATUS3_INTIMIDATE_POKES;
gSpecialStatuses[bank].intimidatedPoke = 1;
}
break;
case ABILITY_FORECAST:
effect = CastformDataTypeChange(bank);
if (effect != 0)
{
BattleScriptPushCursorAndCallback(BattleScript_CastformChange);
gBattleScripting.bank = bank;
*(&gBattleStruct->formToChangeInto) = effect - 1;
}
break;
case ABILITY_TRACE:
if (!(gSpecialStatuses[bank].traced))
{
gStatuses3[bank] |= STATUS3_TRACE;
gSpecialStatuses[bank].traced = 1;
}
break;
case ABILITY_CLOUD_NINE:
case ABILITY_AIR_LOCK:
{
// that's a weird choice for a variable, why not use i or bank?
for (target1 = 0; target1 < gNoOfAllBanks; target1++)
{
effect = CastformDataTypeChange(target1);
if (effect != 0)
{
BattleScriptPushCursorAndCallback(BattleScript_CastformChange);
gBattleScripting.bank = target1;
*(&gBattleStruct->formToChangeInto) = effect - 1;
break;
}
}
}
break;
}
break;
case ABILITYEFFECT_ENDTURN: // 1
if (gBattleMons[bank].hp != 0)
{
gBankAttacker = bank;
switch (gLastUsedAbility)
{
case ABILITY_RAIN_DISH:
if (WEATHER_HAS_EFFECT && (gBattleWeather & WEATHER_RAIN_ANY)
&& gBattleMons[bank].maxHP > gBattleMons[bank].hp)
{
gLastUsedAbility = ABILITY_RAIN_DISH; // why
BattleScriptPushCursorAndCallback(BattleScript_RainDishActivates);
gBattleMoveDamage = gBattleMons[bank].maxHP / 16;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
gBattleMoveDamage *= -1;
effect++;
}
break;
case ABILITY_SHED_SKIN:
if ((gBattleMons[bank].status1 & STATUS_ANY) && (Random() % 3) == 0)
{
if (gBattleMons[bank].status1 & (STATUS_POISON | STATUS_TOXIC_POISON))
StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn);
if (gBattleMons[bank].status1 & STATUS_SLEEP)
StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn);
if (gBattleMons[bank].status1 & STATUS_PARALYSIS)
StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn);
if (gBattleMons[bank].status1 & STATUS_BURN)
StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn);
if (gBattleMons[bank].status1 & STATUS_FREEZE)
StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn);
gBattleMons[bank].status1 = 0;
gBattleMons[bank].status2 &= ~(STATUS2_NIGHTMARE); // fix nightmare glitch
gBattleScripting.bank = gActiveBank = bank;
BattleScriptPushCursorAndCallback(BattleScript_ShedSkinActivates);
EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[bank].status1);
MarkBufferBankForExecution(gActiveBank);
effect++;
}
break;
case ABILITY_SPEED_BOOST:
if (gBattleMons[bank].statStages[STAT_STAGE_SPEED] < 0xC && gDisableStructs[bank].isFirstTurn != 2)
{
gBattleMons[bank].statStages[STAT_STAGE_SPEED]++;
gBattleScripting.animArg1 = 0x11;
gBattleScripting.animArg2 = 0;
BattleScriptPushCursorAndCallback(BattleScript_SpeedBoostActivates);
gBattleScripting.bank = bank;
effect++;
}
break;
case ABILITY_TRUANT:
gDisableStructs[gBankAttacker].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[gBankAttacker].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[gBankAttacker].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[gBankAttacker].notFirstStrike)
gBattlescriptCurrInstr = BattleScript_MoveHPDrain;
else
gBattlescriptCurrInstr = BattleScript_MoveHPDrain_PPLoss;
effect = 1;
}
break;
case ABILITY_FLASH_FIRE:
if (moveType == TYPE_FIRE && !(gBattleMons[bank].status1 & STATUS_FREEZE))
{
if (!(gBattleResources->flags->flags[bank] & UNKNOWN_FLAG_FLASH_FIRE))
{
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
if (gProtectStructs[gBankAttacker].notFirstStrike)
gBattlescriptCurrInstr = BattleScript_FlashFireBoost;
else
gBattlescriptCurrInstr = BattleScript_FlashFireBoost_PPLoss;
gBattleResources->flags->flags[bank] |= UNKNOWN_FLAG_FLASH_FIRE;
effect = 2;
}
else
{
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
if (gProtectStructs[gBankAttacker].notFirstStrike)
gBattlescriptCurrInstr = BattleScript_FlashFireBoost;
else
gBattlescriptCurrInstr = BattleScript_FlashFireBoost_PPLoss;
effect = 2;
}
}
break;
}
if (effect == 1)
{
if (gBattleMons[bank].maxHP == gBattleMons[bank].hp)
{
if ((gProtectStructs[gBankAttacker].notFirstStrike))
gBattlescriptCurrInstr = BattleScript_MonMadeMoveUseless;
else
gBattlescriptCurrInstr = BattleScript_MonMadeMoveUseless_PPLoss;
}
else
{
gBattleMoveDamage = gBattleMons[bank].maxHP / 4;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
gBattleMoveDamage *= -1;
}
}
}
break;
case ABILITYEFFECT_CONTACT: // 4
switch (gLastUsedAbility)
{
case ABILITY_COLOR_CHANGE:
if (!(gBattleMoveFlags & MOVESTATUS_NOEFFECT)
&& move != MOVE_STRUGGLE
&& gBattleMoves[move].power != 0
&& (gSpecialStatuses[gBankTarget].moveturnLostHP_physical || gSpecialStatuses[gBankTarget].moveturnLostHP_special)
&& gBattleMons[bank].type1 != moveType
&& gBattleMons[bank].type2 != moveType
&& gBattleMons[bank].hp != 0)
{
gBattleMons[bank].type1 = moveType;
gBattleMons[bank].type2 = moveType;
PREPARE_TYPE_BUFFER(gBattleTextBuff1, moveType)
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_ColorChangeActivates;
effect++;
}
break;
case ABILITY_ROUGH_SKIN:
if (!(gBattleMoveFlags & MOVESTATUS_NOEFFECT)
&& gBattleMons[gBankAttacker].hp != 0
&& !gProtectStructs[gBankAttacker].confusionSelfDmg
&& (gSpecialStatuses[gBankTarget].moveturnLostHP_physical || gSpecialStatuses[gBankTarget].moveturnLostHP_special)
&& (gBattleMoves[move].flags & FLAG_MAKES_CONTACT))
{
gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 16;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_RoughSkinActivates;
effect++;
}
break;
case ABILITY_EFFECT_SPORE:
if (!(gBattleMoveFlags & MOVESTATUS_NOEFFECT)
&& gBattleMons[gBankAttacker].hp != 0
&& !gProtectStructs[gBankAttacker].confusionSelfDmg
&& (gSpecialStatuses[gBankTarget].moveturnLostHP_physical || gSpecialStatuses[gBankTarget].moveturnLostHP_special)
&& (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 (!(gBattleMoveFlags & MOVESTATUS_NOEFFECT)
&& gBattleMons[gBankAttacker].hp != 0
&& !gProtectStructs[gBankAttacker].confusionSelfDmg
&& (gSpecialStatuses[gBankTarget].moveturnLostHP_physical || gSpecialStatuses[gBankTarget].moveturnLostHP_special)
&& (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 (!(gBattleMoveFlags & MOVESTATUS_NOEFFECT)
&& gBattleMons[gBankAttacker].hp != 0
&& !gProtectStructs[gBankAttacker].confusionSelfDmg
&& (gSpecialStatuses[gBankTarget].moveturnLostHP_physical || gSpecialStatuses[gBankTarget].moveturnLostHP_special)
&& (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 (!(gBattleMoveFlags & MOVESTATUS_NOEFFECT)
&& gBattleMons[gBankAttacker].hp != 0
&& !gProtectStructs[gBankAttacker].confusionSelfDmg
&& (gBattleMoves[move].flags & FLAG_MAKES_CONTACT)
&& (gSpecialStatuses[gBankTarget].moveturnLostHP_physical || gSpecialStatuses[gBankTarget].moveturnLostHP_special)
&& (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 (!(gBattleMoveFlags & MOVESTATUS_NOEFFECT)
&& gBattleMons[gBankAttacker].hp != 0
&& !gProtectStructs[gBankAttacker].confusionSelfDmg
&& (gBattleMoves[move].flags & FLAG_MAKES_CONTACT)
&& (gSpecialStatuses[gBankTarget].moveturnLostHP_physical || gSpecialStatuses[gBankTarget].moveturnLostHP_special)
&& gBattleMons[gBankTarget].hp != 0
&& (Random() % 3) == 0
&& gBattleMons[gBankAttacker].ability != ABILITY_OBLIVIOUS
&& GetGenderFromSpeciesAndPersonality(speciesAtk, pidAtk) != GetGenderFromSpeciesAndPersonality(speciesDef, pidDef)
&& !(gBattleMons[gBankAttacker].status2 & STATUS2_INFATUATION)
&& GetGenderFromSpeciesAndPersonality(speciesAtk, pidAtk) != MON_GENDERLESS
&& GetGenderFromSpeciesAndPersonality(speciesDef, pidDef) != MON_GENDERLESS)
{
gBattleMons[gBankAttacker].status2 |= STATUS2_INFATUATED_WITH(gBankTarget);
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_CuteCharmActivates;
effect++;
}
break;
}
break;
case ABILITYEFFECT_IMMUNITY: // 5
for (bank = 0; bank < gNoOfAllBanks; bank++)
{
switch (gBattleMons[bank].ability)
{
case ABILITY_IMMUNITY:
if (gBattleMons[bank].status1 & (STATUS_POISON | STATUS_TOXIC_POISON | STATUS_TOXIC_COUNTER))
{
StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn);
effect = 1;
}
break;
case ABILITY_OWN_TEMPO:
if (gBattleMons[bank].status2 & STATUS2_CONFUSION)
{
StringCopy(gBattleTextBuff1, gStatusConditionString_ConfusionJpn);
effect = 2;
}
break;
case ABILITY_LIMBER:
if (gBattleMons[bank].status1 & STATUS_PARALYSIS)
{
StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn);
effect = 1;
}
break;
case ABILITY_INSOMNIA:
case ABILITY_VITAL_SPIRIT:
if (gBattleMons[bank].status1 & STATUS_SLEEP)
{
gBattleMons[bank].status2 &= ~(STATUS2_NIGHTMARE);
StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn);
effect = 1;
}
break;
case ABILITY_WATER_VEIL:
if (gBattleMons[bank].status1 & STATUS_BURN)
{
StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn);
effect = 1;
}
break;
case ABILITY_MAGMA_ARMOR:
if (gBattleMons[bank].status1 & STATUS_FREEZE)
{
StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn);
effect = 1;
}
break;
case ABILITY_OBLIVIOUS:
if (gBattleMons[bank].status2 & STATUS2_INFATUATION)
{
StringCopy(gBattleTextBuff1, gStatusConditionString_LoveJpn);
effect = 3;
}
break;
}
if (effect)
{
switch (effect)
{
case 1: // status cleared
gBattleMons[bank].status1 = 0;
break;
case 2: // get rid of confusion
gBattleMons[bank].status2 &= ~(STATUS2_CONFUSION);
break;
case 3: // get rid of infatuation
gBattleMons[bank].status2 &= ~(STATUS2_INFATUATION);
break;
}
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_AbilityCuredStatus;
gBattleScripting.bank = bank;
gActiveBank = bank;
EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1);
MarkBufferBankForExecution(gActiveBank);
return effect;
}
}
break;
case ABILITYEFFECT_FORECAST: // 6
for (bank = 0; bank < gNoOfAllBanks; bank++)
{
if (gBattleMons[bank].ability == ABILITY_FORECAST)
{
effect = CastformDataTypeChange(bank);
if (effect)
{
BattleScriptPushCursorAndCallback(BattleScript_CastformChange);
gBattleScripting.bank = bank;
*(&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.bank = gBankTarget;
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.bank = gBankAttacker;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_SynchronizeActivates;
gHitMarker |= HITMARKER_IGNORE_SAFEGUARD;
effect++;
}
break;
case ABILITYEFFECT_INTIMIDATE1: // 9
for (i = 0; i < gNoOfAllBanks; i++)
{
if (gBattleMons[i].ability == ABILITY_INTIMIDATE && gStatuses3[i] & STATUS3_INTIMIDATE_POKES)
{
gLastUsedAbility = ABILITY_INTIMIDATE;
gStatuses3[i] &= ~(STATUS3_INTIMIDATE_POKES);
BattleScriptPushCursorAndCallback(BattleScript_82DB4B8);
gBattleStruct->intimidateBank = i;
effect++;
break;
}
}
break;
case ABILITYEFFECT_TRACE: // 11
for (i = 0; i < gNoOfAllBanks; i++)
{
if (gBattleMons[i].ability == ABILITY_TRACE && (gStatuses3[i] & STATUS3_TRACE))
{
u8 target2;
side = (GetBankIdentity(i) ^ BIT_SIDE) & BIT_SIDE; // side of the opposing pokemon
target1 = GetBankByIdentity(side);
target2 = GetBankByIdentity(side + BIT_MON);
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
{
if (gBattleMons[target1].ability != 0 && gBattleMons[target1].hp != 0
&& gBattleMons[target2].ability != 0 && gBattleMons[target2].hp != 0)
{
gActiveBank = GetBankByIdentity(((Random() & 1) * 2) | side);
gBattleMons[i].ability = gBattleMons[gActiveBank].ability;
gLastUsedAbility = gBattleMons[gActiveBank].ability;
effect++;
}
else if (gBattleMons[target1].ability != 0 && gBattleMons[target1].hp != 0)
{
gActiveBank = target1;
gBattleMons[i].ability = gBattleMons[gActiveBank].ability;
gLastUsedAbility = gBattleMons[gActiveBank].ability;
effect++;
}
else if (gBattleMons[target2].ability != 0 && gBattleMons[target2].hp != 0)
{
gActiveBank = target2;
gBattleMons[i].ability = gBattleMons[gActiveBank].ability;
gLastUsedAbility = gBattleMons[gActiveBank].ability;
effect++;
}
}
else
{
gActiveBank = 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.bank = i;
PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gActiveBank, gBattlePartyID[gActiveBank])
PREPARE_ABILITY_BUFFER(gBattleTextBuff2, gLastUsedAbility)
break;
}
}
}
break;
case ABILITYEFFECT_INTIMIDATE2: // 10
for (i = 0; i < gNoOfAllBanks; i++)
{
if (gBattleMons[i].ability == ABILITY_INTIMIDATE && (gStatuses3[i] & STATUS3_INTIMIDATE_POKES))
{
gLastUsedAbility = ABILITY_INTIMIDATE;
gStatuses3[i] &= ~(STATUS3_INTIMIDATE_POKES);
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_82DB4C1;
gBattleStruct->intimidateBank = i;
effect++;
break;
}
}
break;
case ABILITYEFFECT_CHECK_OTHER_SIDE: // 12
side = GetBankSide(bank);
for (i = 0; i < gNoOfAllBanks; i++)
{
if (GetBankSide(i) != side && gBattleMons[i].ability == ability)
{
gLastUsedAbility = ability;
effect = i + 1;
}
}
break;
case ABILITYEFFECT_CHECK_BANK_SIDE: // 13
side = GetBankSide(bank);
for (i = 0; i < gNoOfAllBanks; i++)
{
if (GetBankSide(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 < gNoOfAllBanks; i++)
{
if (gStatuses3[i] & STATUS3_MUDSPORT)
effect = i + 1;
}
break;
case 0xFE:
for (i = 0; i < gNoOfAllBanks; i++)
{
if (gStatuses3[i] & STATUS3_WATERSPORT)
effect = i + 1;
}
break;
default:
for (i = 0; i < gNoOfAllBanks; i++)
{
if (gBattleMons[i].ability == ability)
{
gLastUsedAbility = ability;
effect = i + 1;
}
}
break;
}
break;
case ABILITYEFFECT_CHECK_ON_FIELD: // 19
for (i = 0; i < gNoOfAllBanks; i++)
{
if (gBattleMons[i].ability == ability && gBattleMons[i].hp != 0)
{
gLastUsedAbility = ability;
effect = i + 1;
}
}
break;
case ABILITYEFFECT_CHECK_FIELD_EXCEPT_BANK: // 15
for (i = 0; i < gNoOfAllBanks; i++)
{
if (gBattleMons[i].ability == ability && i != bank)
{
gLastUsedAbility = ability;
effect = i + 1;
}
}
break;
case ABILITYEFFECT_COUNT_OTHER_SIDE: // 16
side = GetBankSide(bank);
for (i = 0; i < gNoOfAllBanks; i++)
{
if (GetBankSide(i) != side && gBattleMons[i].ability == ability)
{
gLastUsedAbility = ability;
effect++;
}
}
break;
case ABILITYEFFECT_COUNT_BANK_SIDE: // 17
side = GetBankSide(bank);
for (i = 0; i < gNoOfAllBanks; i++)
{
if (GetBankSide(i) == side && gBattleMons[i].ability == ability)
{
gLastUsedAbility = ability;
effect++;
}
}
break;
case ABILITYEFFECT_COUNT_ON_FIELD: // 18
for (i = 0; i < gNoOfAllBanks; i++)
{
if (gBattleMons[i].ability == ability && i != bank)
{
gLastUsedAbility = ability;
effect++;
}
}
break;
}
if (effect && caseID < ABILITYEFFECT_CHECK_OTHER_SIDE && gLastUsedAbility != 0xFF)
RecordAbilityBattle(bank, gLastUsedAbility);
}
return effect;
}
void BattleScriptExecute(const u8 *BS_ptr)
{
gBattlescriptCurrInstr = BS_ptr;
BATTLE_CALLBACKS_STACK->function[BATTLE_CALLBACKS_STACK->size++] = gBattleMainFunc;
gBattleMainFunc = RunBattleScriptCommands_PopCallbacksStack;
gCurrentActionFuncId = 0;
}
void BattleScriptPushCursorAndCallback(const u8 *BS_ptr)
{
BattleScriptPushCursor();
gBattlescriptCurrInstr = BS_ptr;
BATTLE_CALLBACKS_STACK->function[BATTLE_CALLBACKS_STACK->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 bank, bool8 moveTurn)
{
int i = 0;
u8 effect = ITEM_NO_EFFECT;
u8 changedPP = 0;
u8 bankHoldEffect, atkHoldEffect, defHoldEffect;
u8 bankQuality, atkQuality, defQuality;
u16 atkItem, defItem;
gLastUsedItem = gBattleMons[bank].item;
if (gLastUsedItem == ITEM_ENIGMA_BERRY)
{
bankHoldEffect = gEnigmaBerries[bank].holdEffect;
bankQuality = gEnigmaBerries[bank].holdEffectParam;
}
else
{
bankHoldEffect = ItemId_GetHoldEffect(gLastUsedItem);
bankQuality = ItemId_GetHoldEffectParam(gLastUsedItem);
}
atkItem = gBattleMons[gBankAttacker].item;
if (atkItem == ITEM_ENIGMA_BERRY)
{
atkHoldEffect = gEnigmaBerries[gBankAttacker].holdEffect;
atkQuality = gEnigmaBerries[gBankAttacker].holdEffectParam;
}
else
{
atkHoldEffect = ItemId_GetHoldEffect(atkItem);
atkQuality = ItemId_GetHoldEffectParam(atkItem);
}
// def variables are unused
defItem = gBattleMons[gBankTarget].item;
if (defItem == ITEM_ENIGMA_BERRY)
{
defHoldEffect = gEnigmaBerries[gBankTarget].holdEffect;
defQuality = gEnigmaBerries[gBankTarget].holdEffectParam;
}
else
{
defHoldEffect = ItemId_GetHoldEffect(defItem);
defQuality = ItemId_GetHoldEffectParam(defItem);
}
switch (caseID)
{
case ITEMEFFECT_ON_SWITCH_IN:
switch (bankHoldEffect)
{
case HOLD_EFFECT_DOUBLE_PRIZE:
if (GetBankSide(bank) == SIDE_PLAYER)
gBattleStruct->moneyMultiplier = 2;
break;
case HOLD_EFFECT_RESTORE_STATS:
for (i = 0; i < BATTLE_STATS_NO; i++)
{
if (gBattleMons[bank].statStages[i] < 6)
{
gBattleMons[bank].statStages[i] = 6;
effect = ITEM_STATS_CHANGE;
}
}
if (effect)
{
gBattleScripting.bank = bank;
gStringBank = bank;
gActiveBank = gBankAttacker = bank;
BattleScriptExecute(BattleScript_WhiteHerbEnd2);
}
break;
}
break;
case 1:
if (gBattleMons[bank].hp)
{
switch (bankHoldEffect)
{
case HOLD_EFFECT_RESTORE_HP:
if (gBattleMons[bank].hp <= gBattleMons[bank].maxHP / 2 && !moveTurn)
{
gBattleMoveDamage = bankQuality;
if (gBattleMons[bank].hp + bankQuality > gBattleMons[bank].maxHP)
gBattleMoveDamage = gBattleMons[bank].maxHP - gBattleMons[bank].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 (GetBankSide(bank) == SIDE_PLAYER)
mon = &gPlayerParty[gBattlePartyID[bank]];
else
mon = &gEnemyParty[gBattlePartyID[bank]];
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 + bankQuality > maxPP)
changedPP = maxPP;
else
changedPP = changedPP + bankQuality;
PREPARE_MOVE_BUFFER(gBattleTextBuff1, move);
BattleScriptExecute(BattleScript_BerryPPHealEnd2);
EmitSetMonData(0, i + REQUEST_PPMOVE1_BATTLE, 0, 1, &changedPP);
MarkBufferBankForExecution(gActiveBank);
effect = ITEM_PP_CHANGE;
}
}
break;
case HOLD_EFFECT_RESTORE_STATS:
for (i = 0; i < BATTLE_STATS_NO; i++)
{
if (gBattleMons[bank].statStages[i] < 6)
{
gBattleMons[bank].statStages[i] = 6;
effect = ITEM_STATS_CHANGE;
}
}
if (effect)
{
gBattleScripting.bank = bank;
gStringBank = bank;
gActiveBank = gBankAttacker = bank;
BattleScriptExecute(BattleScript_WhiteHerbEnd2);
}
break;
case HOLD_EFFECT_LEFTOVERS:
if (gBattleMons[bank].hp < gBattleMons[bank].maxHP && !moveTurn)
{
gBattleMoveDamage = gBattleMons[bank].maxHP / 16;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
if (gBattleMons[bank].hp + gBattleMoveDamage > gBattleMons[bank].maxHP)
gBattleMoveDamage = gBattleMons[bank].maxHP - gBattleMons[bank].hp;
gBattleMoveDamage *= -1;
BattleScriptExecute(BattleScript_ItemHealHP_End2);
effect = ITEM_HP_CHANGE;
RecordItemEffectBattle(bank, bankHoldEffect);
}
break;
// nice copy/paste there gamefreak, making a function for confuse berries was too much eh?
case HOLD_EFFECT_CONFUSE_SPICY:
if (gBattleMons[bank].hp <= gBattleMons[bank].maxHP / 2 && !moveTurn)
{
PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, FLAVOR_SPICY);
gBattleMoveDamage = gBattleMons[bank].maxHP / bankQuality;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
if (gBattleMons[bank].hp + gBattleMoveDamage > gBattleMons[bank].maxHP)
gBattleMoveDamage = gBattleMons[bank].maxHP - gBattleMons[bank].hp;
gBattleMoveDamage *= -1;
if (GetFlavorRelationByPersonality(gBattleMons[bank].personality, FLAVOR_SPICY) < 0)
BattleScriptExecute(BattleScript_BerryConfuseHealEnd2);
else
BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem);
effect = ITEM_HP_CHANGE;
}
break;
case HOLD_EFFECT_CONFUSE_DRY:
if (gBattleMons[bank].hp <= gBattleMons[bank].maxHP / 2 && !moveTurn)
{
PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, FLAVOR_DRY);
gBattleMoveDamage = gBattleMons[bank].maxHP / bankQuality;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
if (gBattleMons[bank].hp + gBattleMoveDamage > gBattleMons[bank].maxHP)
gBattleMoveDamage = gBattleMons[bank].maxHP - gBattleMons[bank].hp;
gBattleMoveDamage *= -1;
if (GetFlavorRelationByPersonality(gBattleMons[bank].personality, FLAVOR_DRY) < 0)
BattleScriptExecute(BattleScript_BerryConfuseHealEnd2);
else
BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem);
effect = ITEM_HP_CHANGE;
}
break;
case HOLD_EFFECT_CONFUSE_SWEET:
if (gBattleMons[bank].hp <= gBattleMons[bank].maxHP / 2 && !moveTurn)
{
PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, FLAVOR_SWEET);
gBattleMoveDamage = gBattleMons[bank].maxHP / bankQuality;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
if (gBattleMons[bank].hp + gBattleMoveDamage > gBattleMons[bank].maxHP)
gBattleMoveDamage = gBattleMons[bank].maxHP - gBattleMons[bank].hp;
gBattleMoveDamage *= -1;
if (GetFlavorRelationByPersonality(gBattleMons[bank].personality, FLAVOR_SWEET) < 0)
BattleScriptExecute(BattleScript_BerryConfuseHealEnd2);
else
BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem);
effect = ITEM_HP_CHANGE;
}
break;
case HOLD_EFFECT_CONFUSE_BITTER:
if (gBattleMons[bank].hp <= gBattleMons[bank].maxHP / 2 && !moveTurn)
{
PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, FLAVOR_BITTER);
gBattleMoveDamage = gBattleMons[bank].maxHP / bankQuality;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
if (gBattleMons[bank].hp + gBattleMoveDamage > gBattleMons[bank].maxHP)
gBattleMoveDamage = gBattleMons[bank].maxHP - gBattleMons[bank].hp;
gBattleMoveDamage *= -1;
if (GetFlavorRelationByPersonality(gBattleMons[bank].personality, FLAVOR_BITTER) < 0)
BattleScriptExecute(BattleScript_BerryConfuseHealEnd2);
else
BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem);
effect = ITEM_HP_CHANGE;
}
break;
case HOLD_EFFECT_CONFUSE_SOUR:
if (gBattleMons[bank].hp <= gBattleMons[bank].maxHP / 2 && !moveTurn)
{
PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, FLAVOR_SOUR);
gBattleMoveDamage = gBattleMons[bank].maxHP / bankQuality;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
if (gBattleMons[bank].hp + gBattleMoveDamage > gBattleMons[bank].maxHP)
gBattleMoveDamage = gBattleMons[bank].maxHP - gBattleMons[bank].hp;
gBattleMoveDamage *= -1;
if (GetFlavorRelationByPersonality(gBattleMons[bank].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[bank].hp <= gBattleMons[bank].maxHP / bankQuality && !moveTurn && gBattleMons[bank].statStages[STAT_STAGE_ATK] < 0xC)
{
PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_STAGE_ATK);
PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_STATROSE);
gEffectBank = bank;
SET_STATCHANGER(STAT_STAGE_ATK, 1, FALSE);
gBattleScripting.animArg1 = 0xE + STAT_STAGE_ATK;
gBattleScripting.animArg2 = 0;
BattleScriptExecute(BattleScript_BerryStatRaiseEnd2);
effect = ITEM_STATS_CHANGE;
}
break;
case HOLD_EFFECT_DEFENSE_UP:
if (gBattleMons[bank].hp <= gBattleMons[bank].maxHP / bankQuality && !moveTurn && gBattleMons[bank].statStages[STAT_STAGE_DEF] < 0xC)
{
PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_STAGE_DEF);
gEffectBank = bank;
SET_STATCHANGER(STAT_STAGE_DEF, 1, FALSE);
gBattleScripting.animArg1 = 0xE + STAT_STAGE_DEF;
gBattleScripting.animArg2 = 0;
BattleScriptExecute(BattleScript_BerryStatRaiseEnd2);
effect = ITEM_STATS_CHANGE;
}
break;
case HOLD_EFFECT_SPEED_UP:
if (gBattleMons[bank].hp <= gBattleMons[bank].maxHP / bankQuality && !moveTurn && gBattleMons[bank].statStages[STAT_STAGE_SPEED] < 0xC)
{
PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_STAGE_SPEED);
gEffectBank = bank;
SET_STATCHANGER(STAT_STAGE_SPEED, 1, FALSE);
gBattleScripting.animArg1 = 0xE + STAT_STAGE_SPEED;
gBattleScripting.animArg2 = 0;
BattleScriptExecute(BattleScript_BerryStatRaiseEnd2);
effect = ITEM_STATS_CHANGE;
}
break;
case HOLD_EFFECT_SP_ATTACK_UP:
if (gBattleMons[bank].hp <= gBattleMons[bank].maxHP / bankQuality && !moveTurn && gBattleMons[bank].statStages[STAT_STAGE_SPATK] < 0xC)
{
PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_STAGE_SPATK);
gEffectBank = bank;
SET_STATCHANGER(STAT_STAGE_SPATK, 1, FALSE);
gBattleScripting.animArg1 = 0xE + STAT_STAGE_SPATK;
gBattleScripting.animArg2 = 0;
BattleScriptExecute(BattleScript_BerryStatRaiseEnd2);
effect = ITEM_STATS_CHANGE;
}
break;
case HOLD_EFFECT_SP_DEFENSE_UP:
if (gBattleMons[bank].hp <= gBattleMons[bank].maxHP / bankQuality && !moveTurn && gBattleMons[bank].statStages[STAT_STAGE_SPDEF] < 0xC)
{
PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_STAGE_SPDEF);
gEffectBank = bank;
SET_STATCHANGER(STAT_STAGE_SPDEF, 1, FALSE);
gBattleScripting.animArg1 = 0xE + STAT_STAGE_SPDEF;
gBattleScripting.animArg2 = 0;
BattleScriptExecute(BattleScript_BerryStatRaiseEnd2);
effect = ITEM_STATS_CHANGE;
}
break;
case HOLD_EFFECT_CRITICAL_UP:
if (gBattleMons[bank].hp <= gBattleMons[bank].maxHP / bankQuality && !moveTurn && !(gBattleMons[bank].status2 & STATUS2_FOCUS_ENERGY))
{
gBattleMons[bank].status2 |= STATUS2_FOCUS_ENERGY;
BattleScriptExecute(BattleScript_BerryFocusEnergyEnd2);
effect = ITEM_EFFECT_OTHER;
}
break;
case HOLD_EFFECT_RANDOM_STAT_UP:
if (!moveTurn && gBattleMons[bank].hp <= gBattleMons[bank].maxHP / bankQuality)
{
for (i = 0; i < 5; i++)
{
if (gBattleMons[bank].statStages[STAT_STAGE_ATK + i] < 0xC)
break;
}
if (i != 5)
{
do
{
i = Random() % 5;
} while (gBattleMons[bank].statStages[STAT_STAGE_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;
gEffectBank = bank;
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[bank].status1 & STATUS_PARALYSIS)
{
gBattleMons[bank].status1 &= ~(STATUS_PARALYSIS);
BattleScriptExecute(BattleScript_BerryCurePrlzEnd2);
effect = ITEM_STATUS_CHANGE;
}
break;
case HOLD_EFFECT_CURE_PSN:
if (gBattleMons[bank].status1 & STATUS_PSN_ANY)
{
gBattleMons[bank].status1 &= ~(STATUS_PSN_ANY | STATUS_TOXIC_COUNTER);
BattleScriptExecute(BattleScript_BerryCurePsnEnd2);
effect = ITEM_STATUS_CHANGE;
}
break;
case HOLD_EFFECT_CURE_BRN:
if (gBattleMons[bank].status1 & STATUS_BURN)
{
gBattleMons[bank].status1 &= ~(STATUS_BURN);
BattleScriptExecute(BattleScript_BerryCureBrnEnd2);
effect = ITEM_STATUS_CHANGE;
}
break;
case HOLD_EFFECT_CURE_FRZ:
if (gBattleMons[bank].status1 & STATUS_FREEZE)
{
gBattleMons[bank].status1 &= ~(STATUS_FREEZE);
BattleScriptExecute(BattleScript_BerryCureFrzEnd2);
effect = ITEM_STATUS_CHANGE;
}
break;
case HOLD_EFFECT_CURE_SLP:
if (gBattleMons[bank].status1 & STATUS_SLEEP)
{
gBattleMons[bank].status1 &= ~(STATUS_SLEEP);
gBattleMons[bank].status2 &= ~(STATUS2_NIGHTMARE);
BattleScriptExecute(BattleScript_BerryCureSlpEnd2);
effect = ITEM_STATUS_CHANGE;
}
break;
case HOLD_EFFECT_CURE_CONFUSION:
if (gBattleMons[bank].status2 & STATUS2_CONFUSION)
{
gBattleMons[bank].status2 &= ~(STATUS2_CONFUSION);
BattleScriptExecute(BattleScript_BerryCureConfusionEnd2);
effect = ITEM_EFFECT_OTHER;
}
break;
case HOLD_EFFECT_CURE_STATUS:
if (gBattleMons[bank].status1 & STATUS_ANY || gBattleMons[bank].status2 & STATUS2_CONFUSION)
{
i = 0;
if (gBattleMons[bank].status1 & STATUS_PSN_ANY)
{
StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn);
i++;
}
if (gBattleMons[bank].status1 & STATUS_SLEEP)
{
gBattleMons[bank].status2 &= ~(STATUS2_NIGHTMARE);
StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn);
i++;
}
if (gBattleMons[bank].status1 & STATUS_PARALYSIS)
{
StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn);
i++;
}
if (gBattleMons[bank].status1 & STATUS_BURN)
{
StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn);
i++;
}
if (gBattleMons[bank].status1 & STATUS_FREEZE)
{
StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn);
i++;
}
if (gBattleMons[bank].status2 & STATUS2_CONFUSION)
{
StringCopy(gBattleTextBuff1, gStatusConditionString_ConfusionJpn);
i++;
}
if (!(i > 1))
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
else
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
gBattleMons[bank].status1 = 0;
gBattleMons[bank].status2 &= ~(STATUS2_CONFUSION);
BattleScriptExecute(BattleScript_BerryCureChosenStatusEnd2);
effect = ITEM_STATUS_CHANGE;
}
break;
case HOLD_EFFECT_CURE_ATTRACT:
if (gBattleMons[bank].status2 & STATUS2_INFATUATION)
{
gBattleMons[bank].status2 &= ~(STATUS2_INFATUATION);
StringCopy(gBattleTextBuff1, gStatusConditionString_LoveJpn);
BattleScriptExecute(BattleScript_BerryCureChosenStatusEnd2);
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
effect = ITEM_EFFECT_OTHER;
}
break;
}
if (effect)
{
gBattleScripting.bank = bank;
gStringBank = bank;
gActiveBank = gBankAttacker = bank;
switch (effect)
{
case ITEM_STATUS_CHANGE:
EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[bank].status1);
MarkBufferBankForExecution(gActiveBank);
break;
case ITEM_PP_CHANGE:
if (!(gBattleMons[bank].status2 & STATUS2_TRANSFORMED) && !(gDisableStructs[bank].unk18_b & gBitTable[i]))
gBattleMons[bank].pp[i] = changedPP;
break;
}
}
}
break;
case 2:
break;
case 3:
for (bank = 0; bank < gNoOfAllBanks; bank++)
{
gLastUsedItem = gBattleMons[bank].item;
if (gBattleMons[bank].item == ITEM_ENIGMA_BERRY)
{
bankHoldEffect = gEnigmaBerries[bank].holdEffect;
bankQuality = gEnigmaBerries[bank].holdEffectParam;
}
else
{
bankHoldEffect = ItemId_GetHoldEffect(gLastUsedItem);
bankQuality = ItemId_GetHoldEffectParam(gLastUsedItem);
}
switch (bankHoldEffect)
{
case HOLD_EFFECT_CURE_PAR:
if (gBattleMons[bank].status1 & STATUS_PARALYSIS)
{
gBattleMons[bank].status1 &= ~(STATUS_PARALYSIS);
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_BerryCureParRet;
effect = ITEM_STATUS_CHANGE;
}
break;
case HOLD_EFFECT_CURE_PSN:
if (gBattleMons[bank].status1 & STATUS_PSN_ANY)
{
gBattleMons[bank].status1 &= ~(STATUS_PSN_ANY | STATUS_TOXIC_COUNTER);
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_BerryCurePsnRet;
effect = ITEM_STATUS_CHANGE;
}
break;
case HOLD_EFFECT_CURE_BRN:
if (gBattleMons[bank].status1 & STATUS_BURN)
{
gBattleMons[bank].status1 &= ~(STATUS_BURN);
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_BerryCureBrnRet;
effect = ITEM_STATUS_CHANGE;
}
break;
case HOLD_EFFECT_CURE_FRZ:
if (gBattleMons[bank].status1 & STATUS_FREEZE)
{
gBattleMons[bank].status1 &= ~(STATUS_FREEZE);
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_BerryCureFrzRet;
effect = ITEM_STATUS_CHANGE;
}
break;
case HOLD_EFFECT_CURE_SLP:
if (gBattleMons[bank].status1 & STATUS_SLEEP)
{
gBattleMons[bank].status1 &= ~(STATUS_SLEEP);
gBattleMons[bank].status2 &= ~(STATUS2_NIGHTMARE);
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_BerryCureSlpRet;
effect = ITEM_STATUS_CHANGE;
}
break;
case HOLD_EFFECT_CURE_CONFUSION:
if (gBattleMons[bank].status2 & STATUS2_CONFUSION)
{
gBattleMons[bank].status2 &= ~(STATUS2_CONFUSION);
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_BerryCureConfusionRet;
effect = ITEM_EFFECT_OTHER;
}
break;
case HOLD_EFFECT_CURE_ATTRACT:
if (gBattleMons[bank].status2 & STATUS2_INFATUATION)
{
gBattleMons[bank].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[bank].status1 & STATUS_ANY || gBattleMons[bank].status2 & STATUS2_CONFUSION)
{
if (gBattleMons[bank].status1 & STATUS_PSN_ANY)
{
StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn);
}
if (gBattleMons[bank].status1 & STATUS_SLEEP)
{
gBattleMons[bank].status2 &= ~(STATUS2_NIGHTMARE);
StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn);
}
if (gBattleMons[bank].status1 & STATUS_PARALYSIS)
{
StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn);
}
if (gBattleMons[bank].status1 & STATUS_BURN)
{
StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn);
}
if (gBattleMons[bank].status1 & STATUS_FREEZE)
{
StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn);
}
if (gBattleMons[bank].status2 & STATUS2_CONFUSION)
{
StringCopy(gBattleTextBuff1, gStatusConditionString_ConfusionJpn);
}
gBattleMons[bank].status1 = 0;
gBattleMons[bank].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[bank].statStages[i] < 6)
{
gBattleMons[bank].statStages[i] = 6;
effect = ITEM_STATS_CHANGE;
}
}
if (effect)
{
gBattleScripting.bank = bank;
gStringBank = bank;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_WhiteHerbRet;
return effect; // unnecessary return
}
break;
}
if (effect)
{
gBattleScripting.bank = bank;
gStringBank = bank;
gActiveBank = bank;
EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1);
MarkBufferBankForExecution(gActiveBank);
break;
}
}
break;
case 4:
if (gBattleMoveDamage)
{
switch (atkHoldEffect)
{
case HOLD_EFFECT_FLINCH:
if (!(gBattleMoveFlags & MOVESTATUS_NOEFFECT)
&& (gSpecialStatuses[gBankTarget].moveturnLostHP_physical || gSpecialStatuses[gBankTarget].moveturnLostHP_special)
&& (Random() % 100) < atkQuality
&& gBattleMoves[gCurrentMove].flags & FLAG_KINGSROCK_AFFECTED
&& gBattleMons[gBankTarget].hp)
{
gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_FLINCH;
BattleScriptPushCursor();
SetMoveEffect(0, 0);
BattleScriptPop();
}
break;
case HOLD_EFFECT_SHELL_BELL:
if (!(gBattleMoveFlags & MOVESTATUS_NOEFFECT)
&& gSpecialStatuses[gBankTarget].moveturnLostHP != 0
&& gSpecialStatuses[gBankTarget].moveturnLostHP != 0xFFFF
&& gBankAttacker != gBankTarget
&& gBattleMons[gBankAttacker].hp != gBattleMons[gBankAttacker].maxHP
&& gBattleMons[gBankAttacker].hp != 0)
{
gLastUsedItem = atkItem;
gStringBank = gBankAttacker;
gBattleScripting.bank = gBankAttacker;
gBattleMoveDamage = (gSpecialStatuses[gBankTarget].moveturnLostHP / atkQuality) * -1;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = -1;
gSpecialStatuses[gBankTarget].moveturnLostHP = 0;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_ItemHealHP_Ret;
effect++;
}
break;
}
}
break;
}
return effect;
}
void ClearFuryCutterDestinyBondGrudge(u8 bank)
{
gDisableStructs[bank].furyCutterCounter = 0;
gBattleMons[bank].status2 &= ~(STATUS2_DESTINY_BOND);
gStatuses3[bank] &= ~(STATUS3_GRUDGE);
}
void HandleAction_RunBattleScript(void) // identical to RunBattleScriptCommands
{
if (gBattleExecBuffer == 0)
gBattleScriptingCommandsTable[*gBattlescriptCurrInstr]();
}
u8 GetMoveTarget(u16 move, u8 useMoveTarget)
{
u8 targetBank = 0;
u8 moveTarget;
u8 side;
if (useMoveTarget)
moveTarget = useMoveTarget - 1;
else
moveTarget = gBattleMoves[move].target;
switch (moveTarget)
{
case MOVE_TARGET_SELECTED:
side = GetBankSide(gBankAttacker) ^ BIT_SIDE;
if (gSideTimers[side].followmeTimer && gBattleMons[gSideTimers[side].followmeTarget].hp)
targetBank = gSideTimers[side].followmeTarget;
else
{
side = GetBankSide(gBankAttacker);
do
{
targetBank = Random() % gNoOfAllBanks;
} while (targetBank == gBankAttacker || side == GetBankSide(targetBank) || gAbsentBankFlags & gBitTable[targetBank]);
if (gBattleMoves[move].type == TYPE_ELECTRIC
&& AbilityBattleEffects(ABILITYEFFECT_COUNT_OTHER_SIDE, gBankAttacker, ABILITY_LIGHTNING_ROD, 0, 0)
&& gBattleMons[targetBank].ability != ABILITY_LIGHTNING_ROD)
{
targetBank ^= BIT_MON;
RecordAbilityBattle(targetBank, gBattleMons[targetBank].ability);
gSpecialStatuses[targetBank].lightningRodRedirected = 1;
}
}
break;
case MOVE_TARGET_DEPENDS:
case MOVE_TARGET_BOTH:
case MOVE_TARGET_FOES_AND_ALLY:
case MOVE_TARGET_OPPONENTS_FIELD:
targetBank = GetBankByIdentity((GetBankIdentity(gBankAttacker) & BIT_SIDE) ^ BIT_SIDE);
if (gAbsentBankFlags & gBitTable[targetBank])
targetBank ^= BIT_MON;
break;
case MOVE_TARGET_RANDOM:
side = GetBankSide(gBankAttacker) ^ BIT_SIDE;
if (gSideTimers[side].followmeTimer && gBattleMons[gSideTimers[side].followmeTarget].hp)
targetBank = gSideTimers[side].followmeTarget;
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && moveTarget & MOVE_TARGET_RANDOM)
{
if (GetBankSide(gBankAttacker) == SIDE_PLAYER)
{
if (Random() & 1)
targetBank = GetBankByIdentity(IDENTITY_OPPONENT_MON1);
else
targetBank = GetBankByIdentity(IDENTITY_OPPONENT_MON2);
}
else
{
if (Random() & 1)
targetBank = GetBankByIdentity(IDENTITY_PLAYER_MON1);
else
targetBank = GetBankByIdentity(IDENTITY_PLAYER_MON2);
}
if (gAbsentBankFlags & gBitTable[targetBank])
targetBank ^= BIT_MON;
}
else
targetBank = GetBankByIdentity((GetBankIdentity(gBankAttacker) & BIT_SIDE) ^ BIT_SIDE);
break;
case MOVE_TARGET_USER:
case MOVE_TARGET_x10:
targetBank = gBankAttacker;
break;
}
*(gBattleStruct->moveTarget + gBankAttacker) = targetBank;
return targetBank;
}
static bool32 HasObedientBitSet(u8 bank)
{
if (GetBankSide(bank) == SIDE_OPPONENT)
return TRUE;
if (GetMonData(&gPlayerParty[gBattlePartyID[bank]], MON_DATA_SPECIES, NULL) != SPECIES_DEOXYS
&& GetMonData(&gPlayerParty[gBattlePartyID[bank]], MON_DATA_SPECIES, NULL) != SPECIES_MEW)
return TRUE;
return GetMonData(&gPlayerParty[gBattlePartyID[bank]], 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 (GetBankSide(gBankAttacker) == SIDE_OPPONENT)
return 0;
if (HasObedientBitSet(gBankAttacker)) // only if species is Mew or Deoxys
{
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && GetBankIdentity(gBankAttacker) == 2)
return 0;
if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER)
return 0;
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED)
return 0;
if (!IsOtherTrainer(gBattleMons[gBankAttacker].otId, gBattleMons[gBankAttacker].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[gBankAttacker].level <= obedienceLevel)
return 0;
rnd = (Random() & 255);
calc = (gBattleMons[gBankAttacker].level + obedienceLevel) * rnd >> 8;
if (calc < obedienceLevel)
return 0;
// is not obedient
if (gCurrentMove == MOVE_RAGE)
gBattleMons[gBankAttacker].status2 &= ~(STATUS2_RAGE);
if (gBattleMons[gBankAttacker].status1 & STATUS_SLEEP && (gCurrentMove == MOVE_SNORE || gCurrentMove == MOVE_SLEEP_TALK))
{
gBattlescriptCurrInstr = BattleScript_82DB695;
return 1;
}
rnd = (Random() & 255);
calc = (gBattleMons[gBankAttacker].level + obedienceLevel) * rnd >> 8;
if (calc < obedienceLevel)
{
calc = CheckMoveLimitations(gBankAttacker, 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 = gUnknown_020241E9 = Random() & 3;
} while (gBitTable[gCurrMovePos] & calc);
gRandomMove = gBattleMons[gBankAttacker].moves[gCurrMovePos];
gBattlescriptCurrInstr = BattleScript_IgnoresAndUsesRandomMove;
gBankTarget = GetMoveTarget(gRandomMove, 0);
gHitMarker |= HITMARKER_x200000;
return 2;
}
}
else
{
obedienceLevel = gBattleMons[gBankAttacker].level - obedienceLevel;
calc = (Random() & 255);
if (calc < obedienceLevel && !(gBattleMons[gBankAttacker].status1 & STATUS_ANY) && gBattleMons[gBankAttacker].ability != ABILITY_VITAL_SPIRIT && gBattleMons[gBankAttacker].ability != ABILITY_INSOMNIA)
{
// try putting asleep
int i;
for (i = 0; i < gNoOfAllBanks; i++)
{
if (gBattleMons[i].status2 & STATUS2_UPROAR)
break;
}
if (i == gNoOfAllBanks)
{
gBattlescriptCurrInstr = BattleScript_IgnoresAndFallsAsleep;
return 1;
}
}
calc -= obedienceLevel;
if (calc < obedienceLevel)
{
gBattleMoveDamage = CalculateBaseDamage(&gBattleMons[gBankAttacker], &gBattleMons[gBankAttacker], MOVE_POUND, 0, 40, 0, gBankAttacker, gBankAttacker);
gBankTarget = gBankAttacker;
gBattlescriptCurrInstr = BattleScript_82DB6F0;
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
return 2;
}
else
{
gBattleCommunication[MULTISTRING_CHOOSER] = Random() & 3;
gBattlescriptCurrInstr = BattleScript_MoveUsedLoafingAround;
return 1;
}
}
}