From b3c788f2ca9e3d0ab6e43617ed7fedfe605bc249 Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Tue, 19 Sep 2017 21:01:12 +0200 Subject: begin work on battle4, organize battle headers --- src/battle_3.c | 27 ++-- src/battle_4.c | 423 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 431 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/battle_3.c b/src/battle_3.c index a2ddd1c2d..283305d6c 100644 --- a/src/battle_3.c +++ b/src/battle_3.c @@ -15,6 +15,7 @@ #include "battle_message.h" #include "battle_ai.h" #include "event_data.h" +#include "calculate_base_damage.h" extern const u8* gBattlescriptCurrInstr; extern const u8* gUnknown_02024220[BATTLE_BANKS_COUNT]; @@ -187,11 +188,8 @@ extern void SetMoveEffect(bool8 primary, u8 certainArg); extern bool8 UproarWakeUpCheck(u8 bank); extern void MarkBufferBankForExecution(u8 bank); extern u8 sub_803F90C(u8 bank); -extern u8 GetBankIdentity(u8); extern void sub_803F9EC(); extern bool8 sub_80423F4(u8 bank, u8, u8); -extern s32 CalculateBaseDamage(struct BattlePokemon *attacker, struct BattlePokemon *defender, u32 move, u16 sideFlags, u16 powerOverride, u8 typeOverride, u8 bankAtk, u8 bankDef); -extern u8 GetBankByPlayerAI(u8); extern u8 sub_806D864(u8); extern u8 sub_806D82C(u8); extern u8 weather_get_current(void); @@ -199,11 +197,6 @@ extern void sub_803E08C(void); extern void bc_move_exec_returning(void); extern s8 GetFlavourRelationByPersonality(u32 personality, u8 flavor); -u8 IsImprisoned(u8 bank, u16 move); -u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn); -u8 GetMoveTarget(u16 move, u8 useMoveTarget); -void b_push_move_exec(const u8* BS_ptr); - void b_movescr_stack_push(const u8* bsPtr) { BATTLESCRIPTS_STACK->ptr[BATTLESCRIPTS_STACK->size++] = bsPtr; @@ -6237,7 +6230,7 @@ u8 GetMoveTarget(u16 move, u8 useMoveTarget) switch (moveTarget) { - case 0: + case MOVE_TARGET_SELECTED: side = GetBankSide(gBankAttacker) ^ 1; if (gSideTimers[side].followmeTimer && gBattleMons[gSideTimers[side].followmeTarget].hp) targetBank = gSideTimers[side].followmeTarget; @@ -6258,19 +6251,19 @@ u8 GetMoveTarget(u16 move, u8 useMoveTarget) } } break; - case 1: - case 8: - case 32: - case 64: + case MOVE_TARGET_DEPENDS: + case MOVE_TARGET_BOTH: + case MOVE_TARGET_FOES_AND_ALLY: + case MOVE_TARGET_OPPONENTS_FIELD: targetBank = GetBankByPlayerAI((GetBankIdentity(gBankAttacker) & 1) ^ 1); if (gAbsentBankFlags & gBitTable[targetBank]) targetBank ^= 2; break; - case 4: + case MOVE_TARGET_RANDOM: side = GetBankSide(gBankAttacker) ^ 1; if (gSideTimers[side].followmeTimer && gBattleMons[gSideTimers[side].followmeTarget].hp) targetBank = gSideTimers[side].followmeTarget; - else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && moveTarget & 4) + else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && moveTarget & MOVE_TARGET_RANDOM) { if (GetBankSide(gBankAttacker) == SIDE_PLAYER) { @@ -6292,8 +6285,8 @@ u8 GetMoveTarget(u16 move, u8 useMoveTarget) else targetBank = GetBankByPlayerAI((GetBankIdentity(gBankAttacker) & 1) ^ 1); break; - case 2: - case 16: + case MOVE_TARGET_USER: + case MOVE_TARGET_x10: targetBank = gBankAttacker; break; } diff --git a/src/battle_4.c b/src/battle_4.c index 92561251f..e693162cc 100644 --- a/src/battle_4.c +++ b/src/battle_4.c @@ -1,11 +1,141 @@ #include "global.h" #include "battle.h" #include "battle_move_effects.h" +#include "battle_message.h" +#include "battle_ai.h" #include "moves.h" #include "abilities.h" #include "item.h" #include "items.h" #include "hold_effects.h" +#include "util.h" +#include "pokemon.h" +#include "calculate_base_damage.h" +#include "rng.h" + +// variables + +extern u8 gCritMultiplier; +extern s32 gBattleMoveDamage; +extern u32 gStatuses3[BATTLE_BANKS_COUNT]; +extern u32 gBattleTypeFlags; +extern struct BattleEnigmaBerry gEnigmaBerries[BATTLE_BANKS_COUNT]; +extern struct BattlePokemon gBattleMons[BATTLE_BANKS_COUNT]; +extern u8 gActiveBank; +extern u32 gBattleExecBuffer; +extern u8 gNoOfAllBanks; +extern u16 gBattlePartyID[BATTLE_BANKS_COUNT]; +extern u8 gTurnOrder[BATTLE_BANKS_COUNT]; +extern u8 gUnknown_02024A76[BATTLE_BANKS_COUNT]; +extern u16 gCurrentMove; +extern u8 gLastUsedAbility; +extern u16 gBattleWeather; +extern u8 gStringBank; +extern u8 gEffectBank; +extern u8 gAbsentBankFlags; +extern u8 gMultiHitCounter; +extern u16 gChosenMovesByBanks[BATTLE_BANKS_COUNT]; +extern u16 gSideAffecting[2]; +extern u16 gPauseCounterBattle; +extern u16 gPaydayMoney; +extern u16 gRandomTurnNumber; +extern u8 gBattleOutcome; +extern u8 gBattleTerrain; +extern u16 gTrainerBattleOpponent; +extern u8 gBankAttacker; +extern u8 gBankTarget; +extern const u8* gBattlescriptCurrInstr; +extern u8 gCurrMovePos; +extern u8 gFightStateTracker; +extern u32 gHitMarker; +extern u8 gBattleMoveFlags; +extern u8 gBattleCommunication[]; +extern u16 gUnknown_02024250[4]; +extern u16 gUnknown_02024258[4]; +extern u8 gStringBank; +extern u16 gDynamicBasePower; +extern u16 gLastUsedItem; +extern u16 gBattleMovePower; +extern s32 gHP_dealt; +extern s32 gTakenDmg[BATTLE_BANKS_COUNT]; +extern u8 gTakenDmgBanks[BATTLE_BANKS_COUNT]; +extern u8 gSentPokesToOpponent[2]; +extern u8 gBank1; +extern u16 gExpShareExp; +extern u8 gLeveledUpInBattle; +extern void (*gBattleMainFunc)(void); +extern u8 gPlayerPartyCount; +extern u16 gMoveToLearn; +extern u16 gRandomMove; +extern u8 gBankInMenu; +extern u8 gActionForBanks[4]; +extern u8 gCurrentMoveTurn; +extern u8 gBattleBufferB[4][0x200]; + +extern const struct BattleMove gBattleMoves[]; +extern const u16 gMissStrings[]; +extern const u8 gTrainerMoney[]; +extern const u8 gTypeEffectiveness[]; +extern const struct BaseStats gBaseStats[]; + +// functions + + +// BattleScripts +extern const u8 BattleScript_MoveEnd[]; +extern const u8 BattleScript_NoPPForMove[]; +extern const u8 BattleScript_MagicCoatBounce[]; +extern const u8 BattleScript_TookAttack[]; +extern const u8 BattleScript_SnatchedMove[]; +extern const u8 BattleScript_Pausex20[]; +extern const u8 BattleScript_SubstituteFade[]; +extern const u8 BattleScript_HangedOnMsg[]; +extern const u8 BattleScript_OneHitKOMsg[]; +extern const u8 BattleScript_EnduredMsg[]; +extern const u8 BattleScript_PSNPrevention[]; +extern const u8 BattleScript_BRNPrevention[]; +extern const u8 BattleScript_PRLZPrevention[]; +extern const u8 BattleScript_FlinchPrevention[]; +extern const u8 BattleScript_StatUp[]; +extern const u8 BattleScript_StatDown[]; +extern const u8 BattleScript_NoItemSteal[]; +extern const u8 BattleScript_ItemSteal[]; +extern const u8 BattleScript_RapidSpinAway[]; +extern const u8 BattleScript_TargetPRLZHeal[]; +extern const u8 BattleScript_KnockedOff[]; +extern const u8 BattleScript_LevelUp[]; +extern const u8 BattleScript_WrapFree[]; +extern const u8 BattleScript_LeechSeedFree[]; +extern const u8 BattleScript_SpikesFree[]; +extern const u8 BattleScript_ButItFailed[]; +extern const u8 BattleScript_ObliviousPreventsAttraction[]; +extern const u8 BattleScript_MistProtected[]; +extern const u8 BattleScript_AbilityNoStatLoss[]; +extern const u8 BattleScript_AbilityNoSpecificStatLoss[]; +extern const u8 BattleScript_TrainerBallBlock[]; +extern const u8 BattleScript_WallyBallThrow[]; +extern const u8 BattleScript_SuccessBallThrow[]; +extern const u8 BattleScript_ShakeBallThrow[]; + +// read via orr +#define BSScriptRead32(ptr) ((ptr)[0] | (ptr)[1] << 8 | (ptr)[2] << 16 | (ptr)[3] << 24) +#define BSScriptRead8(ptr) (((u8)((ptr)[0]))) +#define BSScriptReadPtr(ptr) ((void *)BSScriptRead32(ptr)) + +// read via add +#define BS2ScriptRead32(ptr) ((ptr)[0] + ((ptr)[1] << 8) + ((ptr)[2] << 16) + ((ptr)[3] << 24)) +#define BS2ScriptRead16(ptr) ((ptr)[0] + ((ptr)[1] << 8)) +#define BS2ScriptReadPtr(ptr) ((void *)BS2ScriptRead32(ptr)) + +#define TARGET_PROTECT_AFFECTED ((gProtectStructs[gBankTarget].protected && gBattleMoves[gCurrentMove].flags & FLAG_PROTECT_AFFECTED)) + +#define TARGET_TURN_DAMAGED (((gSpecialStatuses[gBankTarget].moveturnLostHP_physical || gSpecialStatuses[gBankTarget].moveturnLostHP_physical.moveturnLostHP_special))) + +// this file's functions +bool8 IsTwoTurnsMove(u16 move); +void DestinyBondFlagUpdate(void); +u8 AttacksThisTurn(u8 bank, u16 move); // Note: returns 1 if it's a charging turn, otherwise 2. +void b_wonderguard_and_levitate(void); void atk00_attackcanceler(void); void atk01_accuracycheck(void); @@ -510,13 +640,13 @@ void (* const gBattleScriptingCommandsTable[])(void) = sub_8056EF8 }; -struct statFractions +struct StatFractions { u8 dividend; u8 divisor; }; -const struct statFractions gAccuracyStageRatios[] = +const struct StatFractions gAccuracyStageRatios[] = { { 33, 100}, // -6 { 36, 100}, // -5 @@ -599,3 +729,292 @@ const u32 gStatusFlagsForMoveEffects[] = 0x00000000, 0x00000000 }; + +void atk00_attackcanceler(void) +{ + s32 i; + + if (gBattleOutcome) + { + gFightStateTracker = 0xC; + return; + } + if (gBattleMons[gBankAttacker].hp == 0 && !(gHitMarker & HITMARKER_NO_ATTACKSTRING)) + { + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + gBattlescriptCurrInstr = BattleScript_MoveEnd; + return; + } + if (AtkCanceller_UnableToUseMove()) + return; + if (AbilityBattleEffects(ABILITYEFFECT_MOVES_BLOCK, gBankTarget, 0, 0, 0)) + return; + if (!gBattleMons[gBankAttacker].pp[gCurrMovePos] && gCurrentMove != MOVE_STRUGGLE && !(gHitMarker & 0x800200) + && !(gBattleMons[gBankAttacker].status2 & STATUS2_MULTIPLETURNS)) + { + gBattlescriptCurrInstr = BattleScript_NoPPForMove; + gBattleMoveFlags |= MOVESTATUS_MISSED; + return; + } + + gHitMarker &= ~(HITMARKER_x800000); + + if (!(gHitMarker & HITMARKER_OBEYS) && !(gBattleMons[gBankAttacker].status2 & STATUS2_MULTIPLETURNS)) + { + i = IsPokeDisobedient(); // why use the 'i' variable...? + switch (i) + { + case 0: + break; + case 2: + gHitMarker |= HITMARKER_OBEYS; + return; + default: + gBattleMoveFlags |= MOVESTATUS_MISSED; + return; + } + } + + gHitMarker |= HITMARKER_OBEYS; + + if (gProtectStructs[gBankTarget].bounceMove && gBattleMoves[gCurrentMove].flags & FLAG_MAGICCOAT_AFFECTED) + { + PressurePPLose(gBankAttacker, gBankTarget, MOVE_MAGIC_COAT); + gProtectStructs[gBankTarget].bounceMove = 0; + b_movescr_stack_push_cursor(); + gBattlescriptCurrInstr = BattleScript_MagicCoatBounce; + return; + } + + for (i = 0; i < gNoOfAllBanks; i++) + { + if ((gProtectStructs[gTurnOrder[i]].stealMove) && gBattleMoves[gCurrentMove].flags & FLAG_SNATCH_AFFECTED) + { + PressurePPLose(gBankAttacker, gTurnOrder[i], MOVE_SNATCH); + gProtectStructs[gTurnOrder[i]].stealMove = 0; + gBattleScripting.bank = gTurnOrder[i]; + b_movescr_stack_push_cursor(); + gBattlescriptCurrInstr = BattleScript_SnatchedMove; + return; + } + } + + if (gSpecialStatuses[gBankTarget].lightningRodRedirected) + { + gSpecialStatuses[gBankTarget].lightningRodRedirected = 0; + gLastUsedAbility = ABILITY_LIGHTNING_ROD; + b_movescr_stack_push_cursor(); + gBattlescriptCurrInstr = BattleScript_TookAttack; + RecordAbilityBattle(gBankTarget, gLastUsedAbility); + } + else if (TARGET_PROTECT_AFFECTED + && (gCurrentMove != MOVE_CURSE || (gBattleMons[gBankAttacker].type1 == TYPE_GHOST || gBattleMons[gBankAttacker].type2 == TYPE_GHOST)) + && ((!IsTwoTurnsMove(gCurrentMove) || (gBattleMons[gBankAttacker].status2 & STATUS2_MULTIPLETURNS)))) + { + CancelMultiTurnMoves(gBankAttacker); + gBattleMoveFlags |= MOVESTATUS_MISSED; + gUnknown_02024250[gBankTarget] = 0; + gUnknown_02024258[gBankTarget] = 0; + gBattleCommunication[6] = 1; + gBattlescriptCurrInstr++; + } + else + { + gBattlescriptCurrInstr++; + } +} + +void JumpIfMoveFailed(u8 adder, u16 move) +{ + const void* BS_ptr = gBattlescriptCurrInstr + adder; + if (gBattleMoveFlags & MOVESTATUS_NOEFFECT) + { + gUnknown_02024250[gBankTarget] = 0; + gUnknown_02024258[gBankTarget] = 0; + BS_ptr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + DestinyBondFlagUpdate(); + if (AbilityBattleEffects(ABILITYEFFECT_ABSORBING, gBankTarget, 0, 0, move)) + return; + } + gBattlescriptCurrInstr = BS_ptr; +} + +void atk40_jump_if_move_affected_by_protect(void) +{ + if (TARGET_PROTECT_AFFECTED) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + JumpIfMoveFailed(5, 0); + gBattleCommunication[6] = 1; + } + else + { + gBattlescriptCurrInstr += 5; + } +} + +bool8 JumpIfMoveAffectedByProtect(u16 move) +{ + bool8 affected = FALSE; + if (TARGET_PROTECT_AFFECTED) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + JumpIfMoveFailed(7, move); + gBattleCommunication[6] = 1; + affected = TRUE; + } + return affected; +} + +bool8 AccuracyCalcHelper(u16 move) +{ + if (gStatuses3[gBankTarget] & STATUS3_ALWAYS_HITS && gDisableStructs[gBankTarget].bankWithSureHit == gBankAttacker) + { + JumpIfMoveFailed(7, move); + return TRUE; + } + + if (!(gHitMarker & HITMARKER_IGNORE_ON_AIR) && gStatuses3[gBankTarget] & STATUS3_ON_AIR) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + JumpIfMoveFailed(7, move); + return TRUE; + } + + gHitMarker &= ~HITMARKER_IGNORE_ON_AIR; + + if (!(gHitMarker & HITMARKER_IGNORE_UNDERGROUND) && gStatuses3[gBankTarget] & STATUS3_UNDERGROUND) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + JumpIfMoveFailed(7, move); + return TRUE; + } + + gHitMarker &= ~HITMARKER_IGNORE_UNDERGROUND; + + if (!(gHitMarker & HITMARKER_IGNORE_UNDERWATER) && gStatuses3[gBankTarget] & STATUS3_UNDERWATER) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + JumpIfMoveFailed(7, move); + return TRUE; + } + + gHitMarker &= ~HITMARKER_IGNORE_UNDERWATER; + + if ((WEATHER_HAS_EFFECT && (gBattleWeather & WEATHER_RAIN_ANY) && gBattleMoves[move].effect == EFFECT_THUNDER) + || (gBattleMoves[move].effect == EFFECT_ALWAYS_HIT || gBattleMoves[move].effect == EFFECT_VITAL_THROW)) + { + JumpIfMoveFailed(7, move); + return TRUE; + } + + return FALSE; +} + +void atk01_accuracycheck(void) +{ + u16 move = BS2ScriptRead16(gBattlescriptCurrInstr + 5); + + if (move == 0xFFFE || move == 0xFFFF) + { + if (gStatuses3[gBankTarget] & STATUS3_ALWAYS_HITS && move == 0xFFFF && gDisableStructs[gBankTarget].bankWithSureHit == gBankAttacker) + gBattlescriptCurrInstr += 7; + else if (gStatuses3[gBankTarget] & (STATUS3_ON_AIR | STATUS3_UNDERGROUND | STATUS3_UNDERWATER)) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + else if (!JumpIfMoveAffectedByProtect(0)) + gBattlescriptCurrInstr += 7; + } + else + { + u8 type, moveAcc, holdEffect, quality; + s8 buff; + u16 calc; + + if (move == 0) + move = gCurrentMove; + + GET_MOVE_TYPE(move, type); + + if (JumpIfMoveAffectedByProtect(move)) + return; + if (AccuracyCalcHelper(move)) + return; + + if (gBattleMons[gBankTarget].status2 & STATUS2_FORESIGHT) + { + u8 acc = gBattleMons[gBankAttacker].statStages[STAT_STAGE_ACC]; + buff = acc; + } + else + { + u8 acc = gBattleMons[gBankAttacker].statStages[STAT_STAGE_ACC]; + buff = acc + 6 - gBattleMons[gBankTarget].statStages[STAT_STAGE_EVASION]; + } + + if (buff < 0) + buff = 0; + if (buff > 0xC) + buff = 0xC; + + moveAcc = gBattleMoves[move].accuracy; + // check Thunder on sunny weather + if (WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_SUN_ANY && gBattleMoves[move].effect == EFFECT_THUNDER) + moveAcc = 50; + + calc = gAccuracyStageRatios[buff].dividend * moveAcc; + calc /= gAccuracyStageRatios[buff].divisor; + + if (gBattleMons[gBankAttacker].ability == ABILITY_COMPOUND_EYES) + calc = (calc * 130) / 100; // 1.3 compound eyes boost + if (WEATHER_HAS_EFFECT && gBattleMons[gBankTarget].ability == ABILITY_SAND_VEIL && gBattleWeather & WEATHER_SANDSTORM_ANY) + calc = (calc * 80) / 100; // 1.2 sand veil loss + if (gBattleMons[gBankAttacker].ability == ABILITY_HUSTLE && type < 9) + calc = (calc * 80) / 100; // 1.2 hustle loss + + if (gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY) + { + holdEffect = gEnigmaBerries[gBankTarget].holdEffect; + quality = gEnigmaBerries[gBankTarget].holdEffectParam; + } + else + { + holdEffect = ItemId_GetHoldEffect(gBattleMons[gBankTarget].item); + quality = ItemId_GetHoldEffectParam(gBattleMons[gBankTarget].item); + } + + gStringBank = gBankTarget; + + if (holdEffect == HOLD_EFFECT_EVASION_UP) + calc = (calc * (100 - quality)) / 100; + + // final calculation + if ((Random() % 100 + 1) > calc) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && + (gBattleMoves[move].target == MOVE_TARGET_BOTH || gBattleMoves[move].target == MOVE_TARGET_FOES_AND_ALLY)) + gBattleCommunication[6] = 2; + else + gBattleCommunication[6] = 0; + + b_wonderguard_and_levitate(); + } + JumpIfMoveFailed(7, move); + } +} + +void atk02_attackstring(void) +{ + if (gBattleExecBuffer) + return; + if (!(gHitMarker & (HITMARKER_NO_ATTACKSTRING | HITMARKER_ATTACKSTRING_PRINTED))) + { + PrepareStringBattle(4, gBankAttacker); + gHitMarker |= HITMARKER_ATTACKSTRING_PRINTED; + } + gBattlescriptCurrInstr++; + gBattleCommunication[MSG_DISPLAY] = 0; +} -- cgit v1.2.3 From b4875d82d50b0649c2289b9e470ca0a9ae23782d Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Wed, 20 Sep 2017 00:28:00 +0200 Subject: more battle 4 --- src/battle_3.c | 3 +- src/battle_4.c | 644 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/battle_ai.c | 3 - 3 files changed, 643 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/battle_3.c b/src/battle_3.c index 283305d6c..4f0997aa0 100644 --- a/src/battle_3.c +++ b/src/battle_3.c @@ -14,6 +14,7 @@ #include "string_util.h" #include "battle_message.h" #include "battle_ai.h" +#include "battle_controllers.h" #include "event_data.h" #include "calculate_base_damage.h" @@ -183,10 +184,8 @@ extern u8 b_first_side(u8, u8, u8); extern void sub_803CEDC(u8, u8); extern void b_call_bc_move_exec(const u8 *); extern void BattleTurnPassed(void); -extern void EmitSetAttributes(u8 a, u8 request, u8 c, u8 bytes, void *data); extern void SetMoveEffect(bool8 primary, u8 certainArg); extern bool8 UproarWakeUpCheck(u8 bank); -extern void MarkBufferBankForExecution(u8 bank); extern u8 sub_803F90C(u8 bank); extern void sub_803F9EC(); extern bool8 sub_80423F4(u8 bank, u8, u8); diff --git a/src/battle_4.c b/src/battle_4.c index e693162cc..be7f712c6 100644 --- a/src/battle_4.c +++ b/src/battle_4.c @@ -12,6 +12,8 @@ #include "pokemon.h" #include "calculate_base_damage.h" #include "rng.h" +#include "battle_controllers.h" +#include "species.h" // variables @@ -135,7 +137,7 @@ extern const u8 BattleScript_ShakeBallThrow[]; bool8 IsTwoTurnsMove(u16 move); void DestinyBondFlagUpdate(void); u8 AttacksThisTurn(u8 bank, u16 move); // Note: returns 1 if it's a charging turn, otherwise 2. -void b_wonderguard_and_levitate(void); +static void CheckWonderGuardAndLevitate(void); void atk00_attackcanceler(void); void atk01_accuracycheck(void); @@ -1000,7 +1002,7 @@ void atk01_accuracycheck(void) else gBattleCommunication[6] = 0; - b_wonderguard_and_levitate(); + CheckWonderGuardAndLevitate(); } JumpIfMoveFailed(7, move); } @@ -1018,3 +1020,641 @@ void atk02_attackstring(void) gBattlescriptCurrInstr++; gBattleCommunication[MSG_DISPLAY] = 0; } + +void atk03_ppreduce(void) +{ + s32 to_deduct = 1; + + if (gBattleExecBuffer) + return; + + if (!gSpecialStatuses[gBankAttacker].flag20) + { + switch (gBattleMoves[gCurrentMove].target) + { + case MOVE_TARGET_FOES_AND_ALLY: + to_deduct += AbilityBattleEffects(ABILITYEFFECT_COUNT_ON_FIELD, gBankAttacker, ABILITY_PRESSURE, 0, 0); + break; + case MOVE_TARGET_BOTH: + case MOVE_TARGET_OPPONENTS_FIELD: + to_deduct += AbilityBattleEffects(ABILITYEFFECT_COUNT_OTHER_SIZE, gBankAttacker, ABILITY_PRESSURE, 0, 0); + break; + default: + if (gBankAttacker != gBankTarget && gBattleMons[gBankTarget].ability == ABILITY_PRESSURE) + to_deduct++; + break; + } + } + + if (!(gHitMarker & (HITMARKER_NO_PPDEDUCT | HITMARKER_NO_ATTACKSTRING)) && gBattleMons[gBankAttacker].pp[gCurrMovePos]) + { + gProtectStructs[gBankAttacker].notFirstStrike = 1; + + if (gBattleMons[gBankAttacker].pp[gCurrMovePos] > to_deduct) + gBattleMons[gBankAttacker].pp[gCurrMovePos] -= to_deduct; + else + gBattleMons[gBankAttacker].pp[gCurrMovePos] = 0; + + if (!(gBattleMons[gBankAttacker].status2 & STATUS2_TRANSFORMED) + && !((gDisableStructs[gBankAttacker].unk18_b) & gBitTable[gCurrMovePos])) + { + gActiveBank = gBankAttacker; + EmitSetAttributes(0, REQUEST_PPMOVE1_BATTLE + gCurrMovePos, 0, 1, &gBattleMons[gBankAttacker].pp[gCurrMovePos]); + MarkBufferBankForExecution(gBankAttacker); + } + } + + gHitMarker &= ~(HITMARKER_NO_PPDEDUCT); + gBattlescriptCurrInstr++; +} + +void atk04_critcalc(void) +{ + u8 holdEffect; + u16 item, critChance; + + item = gBattleMons[gBankAttacker].item; + + if (item == ITEM_ENIGMA_BERRY) + holdEffect = gEnigmaBerries[gBankAttacker].holdEffect; + else + holdEffect = ItemId_GetHoldEffect(item); + + gStringBank = gBankAttacker; + + critChance = 2 * ((gBattleMons[gBankAttacker].status2 & STATUS2_FOCUS_ENERGY) != 0) + + (gBattleMoves[gCurrentMove].effect == EFFECT_HIGH_CRITICAL) + + (gBattleMoves[gCurrentMove].effect == EFFECT_SKY_ATTACK) + + (gBattleMoves[gCurrentMove].effect == EFFECT_BLAZE_KICK) + + (gBattleMoves[gCurrentMove].effect == EFFECT_POISON_TAIL) + + (holdEffect == HOLD_EFFECT_SCOPE_LENS) + + 2 * (holdEffect == HOLD_EFFECT_LUCKY_PUNCH && gBattleMons[gBankAttacker].species == SPECIES_CHANSEY) + + 2 * (holdEffect == HOLD_EFFECT_STICK && gBattleMons[gBankAttacker].species == SPECIES_FARFETCHD); + + if (critChance > 4) + critChance = 4; + + if ((gBattleMons[gBankTarget].ability != ABILITY_BATTLE_ARMOR && gBattleMons[gBankTarget].ability != ABILITY_SHELL_ARMOR) + && !(gStatuses3[gBankAttacker] & STATUS3_CANT_SCORE_A_CRIT) + && !(gBattleTypeFlags & (BATTLE_TYPE_WALLY_TUTORIAL | BATTLE_TYPE_FIRST_BATTLE)) + && !(Random() % gCriticalHitChance[critChance])) + gCritMultiplier = 2; + else + gCritMultiplier = 1; + + gBattlescriptCurrInstr++; +} + +void atk05_damagecalc1(void) +{ + u16 sideStatus = gSideAffecting[GET_BANK_SIDE(gBankTarget)]; + gBattleMoveDamage = CalculateBaseDamage(&gBattleMons[gBankAttacker], &gBattleMons[gBankTarget], gCurrentMove, + sideStatus, gDynamicBasePower, + gBattleStruct->dynamicMoveType, gBankAttacker, gBankTarget); + gBattleMoveDamage = gBattleMoveDamage * gCritMultiplier * gBattleScripting.dmgMultiplier; + + if (gStatuses3[gBankAttacker] & STATUS3_CHARGED_UP && gBattleMoves[gCurrentMove].type == TYPE_ELECTRIC) + gBattleMoveDamage *= 2; + if (gProtectStructs[gBankAttacker].helpingHand) + gBattleMoveDamage = gBattleMoveDamage * 15 / 10; + + gBattlescriptCurrInstr++; +} + +void AI_CalcDmg(u8 bankAtk, u8 bankDef) +{ + u16 sideStatus = gSideAffecting[GET_BANK_SIDE(bankDef)]; + gBattleMoveDamage = CalculateBaseDamage(&gBattleMons[bankAtk], &gBattleMons[bankDef], gCurrentMove, + sideStatus, gDynamicBasePower, + gBattleStruct->dynamicMoveType, bankAtk, bankDef); + gDynamicBasePower = 0; + gBattleMoveDamage = gBattleMoveDamage * gCritMultiplier * gBattleScripting.dmgMultiplier; + + if (gStatuses3[bankAtk] & STATUS3_CHARGED_UP && gBattleMoves[gCurrentMove].type == TYPE_ELECTRIC) + gBattleMoveDamage *= 2; + if (gProtectStructs[bankAtk].helpingHand) + gBattleMoveDamage = gBattleMoveDamage * 15 / 10; +} + +void ModulateDmgByType(u8 multiplier) +{ + gBattleMoveDamage = gBattleMoveDamage * multiplier / 10; + if (gBattleMoveDamage == 0 && multiplier != 0) + gBattleMoveDamage = 1; + + switch (multiplier) + { + case TYPE_MUL_NO_EFFECT: + gBattleMoveFlags |= MOVESTATUS_NOTAFFECTED; + gBattleMoveFlags &= ~MOVESTATUS_NOTVERYEFFECTIVE; + gBattleMoveFlags &= ~MOVESTATUS_SUPEREFFECTIVE; + break; + case TYPE_MUL_NOT_EFFECTIVE: + if (gBattleMoves[gCurrentMove].power && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + if (gBattleMoveFlags & MOVESTATUS_SUPEREFFECTIVE) + gBattleMoveFlags &= ~MOVESTATUS_SUPEREFFECTIVE; + else + gBattleMoveFlags |= MOVESTATUS_NOTVERYEFFECTIVE; + } + break; + case TYPE_MUL_SUPER_EFFECTIVE: + if (gBattleMoves[gCurrentMove].power && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + if (gBattleMoveFlags & MOVESTATUS_NOTVERYEFFECTIVE) + gBattleMoveFlags &= ~MOVESTATUS_NOTVERYEFFECTIVE; + else + gBattleMoveFlags |= MOVESTATUS_SUPEREFFECTIVE; + } + break; + } +} + +#define TYPE_FORESIGHT 0xFE +#define TYPE_ENDTABLE 0xFF + +void atk06_typecalc(void) +{ + s32 i = 0; + u8 moveType; + + if (gCurrentMove == MOVE_STRUGGLE) + { + gBattlescriptCurrInstr++; + return; + } + + GET_MOVE_TYPE(gCurrentMove, moveType); + + // check stab + if (gBattleMons[gBankAttacker].type1 == moveType || gBattleMons[gBankAttacker].type2 == moveType) + { + gBattleMoveDamage = gBattleMoveDamage * 15; + gBattleMoveDamage = gBattleMoveDamage / 10; + } + + if (gBattleMons[gBankTarget].ability == ABILITY_LEVITATE && moveType == TYPE_GROUND) + { + gLastUsedAbility = gBattleMons[gBankTarget].ability; + gBattleMoveFlags |= (MOVESTATUS_MISSED | MOVESTATUS_NOTAFFECTED); + gUnknown_02024250[gBankTarget] = 0; + gUnknown_02024258[gBankTarget] = 0; + gBattleCommunication[6] = moveType; + RecordAbilityBattle(gBankTarget, gLastUsedAbility); + } + else + { + while (gTypeEffectiveness[i] != TYPE_ENDTABLE) + { + if (gTypeEffectiveness[i] == TYPE_FORESIGHT) + { + if (gBattleMons[gBankTarget].status2 & STATUS2_FORESIGHT) + break; + i += 3; + continue; + } + else if (gTypeEffectiveness[i] == moveType) + { + // check type1 + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type1) + ModulateDmgByType(gTypeEffectiveness[i + 2]); + // check type2 + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type2 && + gBattleMons[gBankTarget].type1 != gBattleMons[gBankTarget].type2) + ModulateDmgByType(gTypeEffectiveness[i + 2]); + } + i += 3; + } + } + + if (gBattleMons[gBankTarget].ability == ABILITY_WONDER_GUARD && AttacksThisTurn(gBankAttacker, gCurrentMove) == 2 + && (!(gBattleMoveFlags & MOVESTATUS_SUPEREFFECTIVE) || ((gBattleMoveFlags & (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE)) == (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE))) + && gBattleMoves[gCurrentMove].power) + { + gLastUsedAbility = ABILITY_WONDER_GUARD; + gBattleMoveFlags |= MOVESTATUS_MISSED; + gUnknown_02024250[gBankTarget] = 0; + gUnknown_02024258[gBankTarget] = 0; + gBattleCommunication[6] = 3; + RecordAbilityBattle(gBankTarget, gLastUsedAbility); + } + if (gBattleMoveFlags & MOVESTATUS_NOTAFFECTED) + gProtectStructs[gBankAttacker].notEffective = 1; + + gBattlescriptCurrInstr++; +} + +static void CheckWonderGuardAndLevitate(void) +{ + u8 flags = 0; + s32 i = 0; + u8 moveType; + + if (gCurrentMove == MOVE_STRUGGLE || !gBattleMoves[gCurrentMove].power) + return; + + GET_MOVE_TYPE(gCurrentMove, moveType); + + if (gBattleMons[gBankTarget].ability == ABILITY_LEVITATE && moveType == TYPE_GROUND) + { + gLastUsedAbility = ABILITY_LEVITATE; + gBattleCommunication[6] = moveType; + RecordAbilityBattle(gBankTarget, ABILITY_LEVITATE); + return; + } + + while (gTypeEffectiveness[i] != TYPE_ENDTABLE) + { + if (gTypeEffectiveness[i] == TYPE_FORESIGHT) + { + if (gBattleMons[gBankTarget].status2 & STATUS2_FORESIGHT) + break; + i += 3; + continue; + } + if (gTypeEffectiveness[i] == moveType) + { + // check no effect + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type1 && gTypeEffectiveness[i + 2] == 0) + { + gBattleMoveFlags |= MOVESTATUS_NOTAFFECTED; + gProtectStructs[gBankAttacker].notEffective = 1; + } + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type2 && + gBattleMons[gBankTarget].type1 != gBattleMons[gBankTarget].type2 && + gTypeEffectiveness[i + 2] == TYPE_MUL_NO_EFFECT) + { + gBattleMoveFlags |= MOVESTATUS_NOTAFFECTED; + gProtectStructs[gBankAttacker].notEffective = 1; + } + + // check super effective + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type1 && gTypeEffectiveness[i + 2] == 20) + flags |= 1; + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type2 + && gBattleMons[gBankTarget].type1 != gBattleMons[gBankTarget].type2 + && gTypeEffectiveness[i + 2] == TYPE_MUL_SUPER_EFFECTIVE) + flags |= 1; + + // check not very effective + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type1 && gTypeEffectiveness[i + 2] == 5) + flags |= 2; + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type2 + && gBattleMons[gBankTarget].type1 != gBattleMons[gBankTarget].type2 + && gTypeEffectiveness[i + 2] == TYPE_MUL_NOT_EFFECTIVE) + flags |= 2; + } + i += 3; + } + + if (gBattleMons[gBankTarget].ability == ABILITY_WONDER_GUARD && AttacksThisTurn(gBankAttacker, gCurrentMove) == 2) + { + if (((flags & 2) || !(flags & 1)) && gBattleMoves[gCurrentMove].power) + { + gLastUsedAbility = ABILITY_WONDER_GUARD; + gBattleCommunication[6] = 3; + RecordAbilityBattle(gBankTarget, ABILITY_WONDER_GUARD); + } + } +} + +void ModulateDmgByType2(u8 multiplier, u16 move, u8* flags) // same as ModulateDmgByType except different arguments +{ + gBattleMoveDamage = gBattleMoveDamage * multiplier / 10; + if (gBattleMoveDamage == 0 && multiplier != 0) + gBattleMoveDamage = 1; + + switch (multiplier) + { + case TYPE_MUL_NO_EFFECT: + *flags |= MOVESTATUS_NOTAFFECTED; + *flags &= ~MOVESTATUS_NOTVERYEFFECTIVE; + *flags &= ~MOVESTATUS_SUPEREFFECTIVE; + break; + case TYPE_MUL_NOT_EFFECTIVE: + if (gBattleMoves[move].power && !(*flags & MOVESTATUS_NOEFFECT)) + { + if (*flags & MOVESTATUS_SUPEREFFECTIVE) + *flags &= ~MOVESTATUS_SUPEREFFECTIVE; + else + *flags |= MOVESTATUS_NOTVERYEFFECTIVE; + } + break; + case TYPE_MUL_SUPER_EFFECTIVE: + if (gBattleMoves[move].power && !(*flags & MOVESTATUS_NOEFFECT)) + { + if (*flags & MOVESTATUS_NOTVERYEFFECTIVE) + *flags &= ~MOVESTATUS_NOTVERYEFFECTIVE; + else + *flags |= MOVESTATUS_SUPEREFFECTIVE; + } + break; + } +} + +u8 TypeCalc(u16 move, u8 bankAtk, u8 bankDef) +{ + s32 i = 0; + u8 flags = 0; + u8 moveType; + + if (move == MOVE_STRUGGLE) + return 0; + + moveType = gBattleMoves[move].type; + + // check stab + if (gBattleMons[bankAtk].type1 == moveType || gBattleMons[bankAtk].type2 == moveType) + { + gBattleMoveDamage = gBattleMoveDamage * 15; + gBattleMoveDamage = gBattleMoveDamage / 10; + } + + if (gBattleMons[bankDef].ability == ABILITY_LEVITATE && moveType == TYPE_GROUND) + { + flags |= (MOVESTATUS_MISSED | MOVESTATUS_NOTAFFECTED); + } + else + { + while (gTypeEffectiveness[i]!= TYPE_ENDTABLE) + { + if (gTypeEffectiveness[i] == TYPE_FORESIGHT) + { + if (gBattleMons[bankDef].status2 & STATUS2_FORESIGHT) + break; + i += 3; + continue; + } + + else if (gTypeEffectiveness[i] == moveType) + { + // check type1 + if (gTypeEffectiveness[i + 1] == gBattleMons[bankDef].type1) + ModulateDmgByType2(gTypeEffectiveness[i + 2], move, &flags); + // check type2 + if (gTypeEffectiveness[i + 1] == gBattleMons[bankDef].type2 && + gBattleMons[bankDef].type1 != gBattleMons[bankDef].type2) + ModulateDmgByType2(gTypeEffectiveness[i + 2], move, &flags); + } + i += 3; + } + } + + if (gBattleMons[bankDef].ability == ABILITY_WONDER_GUARD && !(flags & MOVESTATUS_MISSED) + && AttacksThisTurn(bankAtk, move) == 2 + && (!(flags & MOVESTATUS_SUPEREFFECTIVE) || ((flags & (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE)) == (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE))) + && gBattleMoves[move].power) + { + flags |= MOVESTATUS_MISSED; + } + return flags; +} + +u8 AI_TypeCalc(u16 move, u16 species, u8 ability) +{ + s32 i = 0; + u8 flags = 0; + u8 type1 = gBaseStats[species].type1, type2 = gBaseStats[species].type2; + u8 moveType; + + if (move == MOVE_STRUGGLE) + return 0; + + moveType = gBattleMoves[move].type; + + if (ability == ABILITY_LEVITATE && moveType == TYPE_GROUND) + { + flags = MOVESTATUS_MISSED | MOVESTATUS_NOTAFFECTED; + } + else + { + while (gTypeEffectiveness[i] != TYPE_ENDTABLE) + { + if (gTypeEffectiveness[i] == TYPE_FORESIGHT) + { + i += 3; + continue; + } + if (gTypeEffectiveness[i] == moveType) + { + // check type1 + if (gTypeEffectiveness[i + 1] == type1) + ModulateDmgByType2(gTypeEffectiveness[i + 2], move, &flags); + // check type2 + if (gTypeEffectiveness[i + 1] == type2 && type1 != type2) + ModulateDmgByType2(gTypeEffectiveness[i + 2], move, &flags); + } + i += 3; + } + } + if (ability == ABILITY_WONDER_GUARD + && (!(flags & MOVESTATUS_SUPEREFFECTIVE) || ((flags & (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE)) == (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE))) + && gBattleMoves[move].power) + flags |= MOVESTATUS_NOTAFFECTED; + return flags; +} + +// Multiplies the damage by a random factor between 85% to 100% inclusive +static inline void ApplyRandomDmgMultiplier(void) +{ + u16 rand = Random(); + u16 randPercent = 100 - (rand % 16); + + if (gBattleMoveDamage != 0) + { + gBattleMoveDamage *= randPercent; + gBattleMoveDamage /= 100; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + } +} + +void Unused_ApplyRandomDmgMultiplier(void) +{ + ApplyRandomDmgMultiplier(); +} + +void atk07_dmg_adjustment(void) +{ + u8 holdEffect, quality; + + ApplyRandomDmgMultiplier(); + + if (gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY) + { + holdEffect = gEnigmaBerries[gBankTarget].holdEffect, quality = gEnigmaBerries[gBankTarget].holdEffectParam; + } + else + { + holdEffect = ItemId_GetHoldEffect(gBattleMons[gBankTarget].item); + quality = ItemId_GetHoldEffectParam(gBattleMons[gBankTarget].item); + } + + gStringBank = gBankTarget; + + if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < quality) + { + RecordItemEffectBattle(gBankTarget, holdEffect); + gSpecialStatuses[gBankTarget].focusBanded = 1; + } + if (gBattleMons[gBankTarget].status2 & STATUS2_SUBSTITUTE) + goto END; + if (gBattleMoves[gCurrentMove].effect != EFFECT_FALSE_SWIPE && !gProtectStructs[gBankTarget].endured + && !gSpecialStatuses[gBankTarget].focusBanded) + goto END; + + if (gBattleMons[gBankTarget].hp > gBattleMoveDamage) + goto END; + + gBattleMoveDamage = gBattleMons[gBankTarget].hp - 1; + + if (gProtectStructs[gBankTarget].endured) + { + gBattleMoveFlags |= MOVESTATUS_ENDURED; + } + else if (gSpecialStatuses[gBankTarget].focusBanded) + { + gBattleMoveFlags |= MOVESTATUS_HUNGON; + gLastUsedItem = gBattleMons[gBankTarget].item; + } + + END: + gBattlescriptCurrInstr++; +} + +void atk08_dmg_adjustment2(void) // The same as 0x7 except it doesn't check for false swipe move effect. +{ + u8 holdEffect, quality; + + ApplyRandomDmgMultiplier(); + + if (gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY) + { + holdEffect = gEnigmaBerries[gBankTarget].holdEffect, quality = gEnigmaBerries[gBankTarget].holdEffectParam; + } + else + { + holdEffect = ItemId_GetHoldEffect(gBattleMons[gBankTarget].item); + quality = ItemId_GetHoldEffectParam(gBattleMons[gBankTarget].item); + } + + gStringBank = gBankTarget; + + if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < quality) + { + RecordItemEffectBattle(gBankTarget, holdEffect); + gSpecialStatuses[gBankTarget].focusBanded = 1; + } + if (gBattleMons[gBankTarget].status2 & STATUS2_SUBSTITUTE) + goto END; + if (!gProtectStructs[gBankTarget].endured && !gSpecialStatuses[gBankTarget].focusBanded) + goto END; + if (gBattleMons[gBankTarget].hp > gBattleMoveDamage) + goto END; + + gBattleMoveDamage = gBattleMons[gBankTarget].hp - 1; + + if (gProtectStructs[gBankTarget].endured) + { + gBattleMoveFlags |= MOVESTATUS_ENDURED; + } + else if (gSpecialStatuses[gBankTarget].focusBanded) + { + gBattleMoveFlags |= MOVESTATUS_HUNGON; + gLastUsedItem = gBattleMons[gBankTarget].item; + } + + END: + gBattlescriptCurrInstr++; +} + +void atk09_attackanimation(void) +{ + if (gBattleExecBuffer) + return; + + if ((gHitMarker & HITMARKER_NO_ANIMATIONS) && (gCurrentMove != MOVE_TRANSFORM && gCurrentMove != MOVE_SUBSTITUTE)) + { + b_movescr_stack_push(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_Pausex20; + gBattleScripting.animTurn++; + gBattleScripting.animTargetsHit++; + } + else + { + if ((gBattleMoves[gCurrentMove].target & MOVE_TARGET_BOTH + || gBattleMoves[gCurrentMove].target & MOVE_TARGET_FOES_AND_ALLY + || gBattleMoves[gCurrentMove].target & MOVE_TARGET_DEPENDS) + && gBattleScripting.animTargetsHit) + { + gBattlescriptCurrInstr++; + return; + } + if (!(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + u8 multihit; + + gActiveBank = gBankAttacker; + + if (gBattleMons[gBankTarget].status2 & STATUS2_SUBSTITUTE) + multihit = gMultiHitCounter; + else if (gMultiHitCounter != 0 && gMultiHitCounter != 1) + { + if (gBattleMons[gBankTarget].hp <= gBattleMoveDamage) + multihit = 1; + else + multihit = gMultiHitCounter; + } + else + multihit = gMultiHitCounter; + + EmitMoveAnimation(0, gCurrentMove, gBattleScripting.animTurn, gBattleMovePower, gBattleMoveDamage, gBattleMons[gBankAttacker].friendship, &gDisableStructs[gBankAttacker], multihit); + gBattleScripting.animTurn += 1; + gBattleScripting.animTargetsHit += 1; + MarkBufferBankForExecution(gBankAttacker); + gBattlescriptCurrInstr++; + } + else + { + b_movescr_stack_push(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_Pausex20; + } + } +} + +void atk0A_waitanimation(void) +{ + if (gBattleExecBuffer == 0) + gBattlescriptCurrInstr++; +} + +void atk0B_healthbarupdate(void) +{ + register s16 healthValue asm("r1"); + + if (gBattleExecBuffer) + return; + if (gBattleMoveFlags & MOVESTATUS_NOEFFECT) + goto END; + + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + + if (gBattleMons[gActiveBank].status2 & STATUS2_SUBSTITUTE && gDisableStructs[gActiveBank].substituteHP && !(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE)) + { + PrepareStringBattle(0x80, gActiveBank); + goto END; + } + + healthValue = 10000; + if (healthValue <= gBattleMoveDamage) + healthValue = gBattleMoveDamage; + + EmitHealthBarUpdate(0, healthValue); + MarkBufferBankForExecution(gActiveBank); + + if (GetBankSide(gActiveBank) == SIDE_PLAYER && gBattleMoveDamage > 0) + gBattleResults.unk5_0 = 1; + + END: + gBattlescriptCurrInstr += 2; +} diff --git a/src/battle_ai.c b/src/battle_ai.c index 3b696b84e..75b5eb2ed 100644 --- a/src/battle_ai.c +++ b/src/battle_ai.c @@ -73,10 +73,7 @@ extern const struct BaseStats gBaseStats[]; extern const u32 gBitTable[]; extern u8 * const gBattleAI_ScriptsTable[]; -extern u8 GetBankIdentity(u8); extern u8 b_first_side(u8, u8, u8); -extern u8 GetBankByPlayerAI(u8); -extern void TypeCalc(u16 move, u8 bankAtk, u8 bankDef); extern void AI_CalcDmg(u8, u8); extern u8 CheckMoveLimitations(); -- cgit v1.2.3 From 28da80e19af3270b827e98c2e7c69c0199d14d05 Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Wed, 20 Sep 2017 12:56:45 +0200 Subject: battle 4 up to SetMoveEffect --- src/battle_4.c | 399 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 382 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/battle_4.c b/src/battle_4.c index be7f712c6..5d867289b 100644 --- a/src/battle_4.c +++ b/src/battle_4.c @@ -14,6 +14,7 @@ #include "rng.h" #include "battle_controllers.h" #include "species.h" +#include "songs.h" // variables @@ -58,7 +59,7 @@ extern u8 gStringBank; extern u16 gDynamicBasePower; extern u16 gLastUsedItem; extern u16 gBattleMovePower; -extern s32 gHP_dealt; +extern s32 gHpDealt; extern s32 gTakenDmg[BATTLE_BANKS_COUNT]; extern u8 gTakenDmgBanks[BATTLE_BANKS_COUNT]; extern u8 gSentPokesToOpponent[2]; @@ -75,7 +76,7 @@ extern u8 gCurrentMoveTurn; extern u8 gBattleBufferB[4][0x200]; extern const struct BattleMove gBattleMoves[]; -extern const u16 gMissStrings[]; +extern const u16 gMissStringIds[]; extern const u8 gTrainerMoney[]; extern const u8 gTypeEffectiveness[]; extern const struct BaseStats gBaseStats[]; @@ -1630,31 +1631,395 @@ void atk0A_waitanimation(void) void atk0B_healthbarupdate(void) { - register s16 healthValue asm("r1"); + if (gBattleExecBuffer) + return; + + if (!(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + + if (gBattleMons[gActiveBank].status2 & STATUS2_SUBSTITUTE && gDisableStructs[gActiveBank].substituteHP && !(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE)) + { + PrepareStringBattle(0x80, gActiveBank); + } + else + { + s16 healthValue; + + s32 currDmg = gBattleMoveDamage; + s32 maxPossibleDmgValue = 10000; // not present in R/S, ensures that huge damage values don't change sign + + if (currDmg <= maxPossibleDmgValue) + healthValue = currDmg; + else + healthValue = maxPossibleDmgValue; + + EmitHealthBarUpdate(0, healthValue); + MarkBufferBankForExecution(gActiveBank); + + if (GetBankSide(gActiveBank) == SIDE_PLAYER && gBattleMoveDamage > 0) + gBattleResults.unk5_0 = 1; + } + } + + gBattlescriptCurrInstr += 2; +} + +void atk0C_datahpupdate(void) +{ + u32 moveType; if (gBattleExecBuffer) return; - if (gBattleMoveFlags & MOVESTATUS_NOEFFECT) - goto END; - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + if (gBattleStruct->dynamicMoveType == 0) + moveType = gBattleMoves[gCurrentMove].type; + else if (!(gBattleStruct->dynamicMoveType & 0x40)) + moveType = gBattleStruct->dynamicMoveType & 0x3F; + else + moveType = gBattleMoves[gCurrentMove].type; - if (gBattleMons[gActiveBank].status2 & STATUS2_SUBSTITUTE && gDisableStructs[gActiveBank].substituteHP && !(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE)) + if (!(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) { - PrepareStringBattle(0x80, gActiveBank); - goto END; + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + if (gBattleMons[gActiveBank].status2 & STATUS2_SUBSTITUTE && gDisableStructs[gActiveBank].substituteHP && !(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE)) + { + if (gDisableStructs[gActiveBank].substituteHP >= gBattleMoveDamage) + { + if (gSpecialStatuses[gActiveBank].moveturnLostHP == 0) + gSpecialStatuses[gActiveBank].moveturnLostHP = gBattleMoveDamage; + gDisableStructs[gActiveBank].substituteHP -= gBattleMoveDamage; + gHpDealt = gBattleMoveDamage; + } + else + { + if (gSpecialStatuses[gActiveBank].moveturnLostHP == 0) + gSpecialStatuses[gActiveBank].moveturnLostHP = gDisableStructs[gActiveBank].substituteHP; + gHpDealt = gDisableStructs[gActiveBank].substituteHP; + gDisableStructs[gActiveBank].substituteHP = 0; + } + // check substitute fading + if (gDisableStructs[gActiveBank].substituteHP == 0) + { + gBattlescriptCurrInstr += 2; + b_movescr_stack_push_cursor(); + gBattlescriptCurrInstr = BattleScript_SubstituteFade; + return; + } + } + else + { + gHitMarker &= ~(HITMARKER_IGNORE_SUBSTITUTE); + if (gBattleMoveDamage < 0) // hp goes up + { + gBattleMons[gActiveBank].hp -= gBattleMoveDamage; + if (gBattleMons[gActiveBank].hp > gBattleMons[gActiveBank].maxHP) + gBattleMons[gActiveBank].hp = gBattleMons[gActiveBank].maxHP; + + } + else // hp goes down + { + if (gHitMarker & HITMARKER_x20) + { + gHitMarker &= ~(HITMARKER_x20); + } + else + { + gTakenDmg[gActiveBank] += gBattleMoveDamage; + if (BSScriptRead8(gBattlescriptCurrInstr + 1) == BS_GET_TARGET) + gTakenDmgBanks[gActiveBank] = gBankAttacker; + else + gTakenDmgBanks[gActiveBank] = gBankTarget; + } + + if (gBattleMons[gActiveBank].hp > gBattleMoveDamage) + { + gBattleMons[gActiveBank].hp -= gBattleMoveDamage; + gHpDealt = gBattleMoveDamage; + } + else + { + gHpDealt = gBattleMons[gActiveBank].hp; + gBattleMons[gActiveBank].hp = 0; + } + + if (!gSpecialStatuses[gActiveBank].moveturnLostHP && !(gHitMarker & HITMARKER_x100000)) + gSpecialStatuses[gActiveBank].moveturnLostHP = gHpDealt; + + if (moveType <= 8 && !(gHitMarker & HITMARKER_x100000) && gCurrentMove != MOVE_PAIN_SPLIT) + { + gProtectStructs[gActiveBank].physicalDmg = gHpDealt; + gSpecialStatuses[gActiveBank].moveturnLostHP_physical = gHpDealt; + if (BSScriptRead8(gBattlescriptCurrInstr + 1) == BS_GET_TARGET) + { + gProtectStructs[gActiveBank].physicalBank = gBankAttacker; + gSpecialStatuses[gActiveBank].moveturnPhysicalBank = gBankAttacker; + } + else + { + gProtectStructs[gActiveBank].physicalBank = gBankTarget; + gSpecialStatuses[gActiveBank].moveturnPhysicalBank = gBankTarget; + } + } + else if (moveType > 8 && !(gHitMarker & HITMARKER_x100000)) + { + gProtectStructs[gActiveBank].specialDmg = gHpDealt; + gSpecialStatuses[gActiveBank].moveturnLostHP_special = gHpDealt; + if (BSScriptRead8(gBattlescriptCurrInstr + 1) == BS_GET_TARGET) + { + gProtectStructs[gActiveBank].specialBank = gBankAttacker; + gSpecialStatuses[gActiveBank].moveturnSpecialBank = gBankAttacker; + } + else + { + gProtectStructs[gActiveBank].specialBank = gBankTarget; + gSpecialStatuses[gActiveBank].moveturnSpecialBank = gBankTarget; + } + } + } + gHitMarker &= ~(HITMARKER_x100000); + EmitSetAttributes(0, REQUEST_HP_BATTLE, 0, 2, &gBattleMons[gActiveBank].hp); + MarkBufferBankForExecution(gActiveBank); + } + } + else + { + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + if (gSpecialStatuses[gActiveBank].moveturnLostHP == 0) + gSpecialStatuses[gActiveBank].moveturnLostHP = 0xFFFF; + } + gBattlescriptCurrInstr += 2; +} + +void atk0D_critmessage(void) +{ + if (gBattleExecBuffer == 0) + { + if (gCritMultiplier == 2 && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + PrepareStringBattle(0xD9, gBankAttacker); + gBattleCommunication[MSG_DISPLAY] = 1; + } + gBattlescriptCurrInstr++; + } +} + +void atk0E_effectiveness_sound(void) +{ + if (gBattleExecBuffer) + return; + + gActiveBank = gBankTarget; + if (!(gBattleMoveFlags & MOVESTATUS_MISSED)) + { + switch (gBattleMoveFlags & (u8)(~(MOVESTATUS_MISSED))) + { + case MOVESTATUS_SUPEREFFECTIVE: + EmitEffectivenessSound(0, SE_KOUKA_H); + MarkBufferBankForExecution(gActiveBank); + break; + case MOVESTATUS_NOTVERYEFFECTIVE: + EmitEffectivenessSound(0, SE_KOUKA_L); + MarkBufferBankForExecution(gActiveBank); + break; + case MOVESTATUS_NOTAFFECTED: + case MOVESTATUS_FAILED: + // no sound + break; + case MOVESTATUS_ENDURED: + case MOVESTATUS_ONEHITKO: + case MOVESTATUS_HUNGON: + default: + if (gBattleMoveFlags & MOVESTATUS_SUPEREFFECTIVE) + { + EmitEffectivenessSound(0, SE_KOUKA_H); + MarkBufferBankForExecution(gActiveBank); + } + else if (gBattleMoveFlags & MOVESTATUS_NOTVERYEFFECTIVE) + { + EmitEffectivenessSound(0, SE_KOUKA_L); + MarkBufferBankForExecution(gActiveBank); + } + else if (!(gBattleMoveFlags & (MOVESTATUS_NOTAFFECTED | MOVESTATUS_FAILED))) + { + EmitEffectivenessSound(0, SE_KOUKA_M); + MarkBufferBankForExecution(gActiveBank); + } + break; + } + } + gBattlescriptCurrInstr++; +} + +void atk0F_resultmessage(void) +{ + u32 stringId = 0; + + if (gBattleExecBuffer) + return; + + if (gBattleMoveFlags & MOVESTATUS_MISSED && (!(gBattleMoveFlags & MOVESTATUS_NOTAFFECTED) || gBattleCommunication[6] > 2)) + { + stringId = gMissStringIds[gBattleCommunication[6]]; + gBattleCommunication[MSG_DISPLAY] = 1; + } + else + { + gBattleCommunication[MSG_DISPLAY] = 1; + switch (gBattleMoveFlags & (u8)(~(MOVESTATUS_MISSED))) + { + case MOVESTATUS_SUPEREFFECTIVE: + stringId = 0xDE; + break; + case MOVESTATUS_NOTVERYEFFECTIVE: + stringId = 0xDD; + break; + case MOVESTATUS_ONEHITKO: + stringId = 0xDA; + break; + case MOVESTATUS_ENDURED: + stringId = 0x99; + break; + case MOVESTATUS_FAILED: + stringId = 0xE5; + break; + case MOVESTATUS_NOTAFFECTED: + stringId = 0x1B; + break; + case MOVESTATUS_HUNGON: + gLastUsedItem = gBattleMons[gBankTarget].item; + gStringBank = gBankTarget; + gBattleMoveFlags &= ~(MOVESTATUS_ENDURED | MOVESTATUS_HUNGON); + b_movescr_stack_push_cursor(); + gBattlescriptCurrInstr = BattleScript_HangedOnMsg; + return; + default: + if (gBattleMoveFlags & MOVESTATUS_NOTAFFECTED) + { + stringId = 0x1B; + } + else if (gBattleMoveFlags & MOVESTATUS_ONEHITKO) + { + gBattleMoveFlags &= ~(MOVESTATUS_ONEHITKO); + gBattleMoveFlags &= ~(MOVESTATUS_SUPEREFFECTIVE); + gBattleMoveFlags &= ~(MOVESTATUS_NOTVERYEFFECTIVE); + b_movescr_stack_push_cursor(); + gBattlescriptCurrInstr = BattleScript_OneHitKOMsg; + return; + } + else if (gBattleMoveFlags & MOVESTATUS_ENDURED) + { + gBattleMoveFlags &= ~(MOVESTATUS_ENDURED | MOVESTATUS_HUNGON); + b_movescr_stack_push_cursor(); + gBattlescriptCurrInstr = BattleScript_EnduredMsg; + return; + } + else if (gBattleMoveFlags & MOVESTATUS_HUNGON) + { + gLastUsedItem = gBattleMons[gBankTarget].item; + gStringBank = gBankTarget; + gBattleMoveFlags &= ~(MOVESTATUS_ENDURED | MOVESTATUS_HUNGON); + b_movescr_stack_push_cursor(); + gBattlescriptCurrInstr = BattleScript_HangedOnMsg; + return; + } + else if (gBattleMoveFlags & MOVESTATUS_FAILED) + { + stringId = 0xE5; + } + else + { + gBattleCommunication[MSG_DISPLAY] = 0; + } + } + } + + if (stringId) + PrepareStringBattle(stringId, gBankAttacker); + + gBattlescriptCurrInstr++; +} + +void atk10_printstring(void) +{ + if (gBattleExecBuffer == 0) + { + u16 var = BS2ScriptRead16(gBattlescriptCurrInstr + 1); + PrepareStringBattle(var, gBankAttacker); + gBattlescriptCurrInstr += 3; + gBattleCommunication[MSG_DISPLAY] = 1; } +} - healthValue = 10000; - if (healthValue <= gBattleMoveDamage) - healthValue = gBattleMoveDamage; +void atk11_printstring_playeronly(void) +{ + gActiveBank = gBankAttacker; - EmitHealthBarUpdate(0, healthValue); + EmitPrintStringPlayerOnly(0, BS2ScriptRead16(gBattlescriptCurrInstr + 1)); MarkBufferBankForExecution(gActiveBank); - if (GetBankSide(gActiveBank) == SIDE_PLAYER && gBattleMoveDamage > 0) - gBattleResults.unk5_0 = 1; + gBattlescriptCurrInstr += 3; + gBattleCommunication[MSG_DISPLAY] = 1; +} - END: - gBattlescriptCurrInstr += 2; +void atk12_waitmessage(void) +{ + if (gBattleExecBuffer == 0) + { + if (!gBattleCommunication[MSG_DISPLAY]) + { + gBattlescriptCurrInstr += 3; + } + else + { + u16 toWait = BS2ScriptRead16(gBattlescriptCurrInstr + 1); + if (++gPauseCounterBattle >= toWait) + { + gPauseCounterBattle = 0; + gBattlescriptCurrInstr += 3; + gBattleCommunication[MSG_DISPLAY] = 0; + } + } + } +} + +void atk13_printfromtable(void) +{ + if (gBattleExecBuffer == 0) + { + u16 *ptr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + ptr += gBattleCommunication[MULTISTRING_CHOOSER]; + + PrepareStringBattle(*(u16*)ptr, gBankAttacker); + + gBattlescriptCurrInstr += 5; + gBattleCommunication[MSG_DISPLAY] = 1; + } +} + +void atk14_printfromtable_playeronly(void) +{ + if (gBattleExecBuffer == 0) + { + u16 *ptr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + ptr += gBattleCommunication[MULTISTRING_CHOOSER]; + + gActiveBank = gBankAttacker; + EmitPrintStringPlayerOnly(0, *(u16*)ptr); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 5; + gBattleCommunication[MSG_DISPLAY] = 1; + } +} + +u8 BankGetTurnOrder(u8 bank) +{ + s32 i; + for (i = 0; i < gNoOfAllBanks; i++) + { + if (gTurnOrder[i] == bank) + break; + } + return i; } -- cgit v1.2.3 From 0c7555e237e44e0c0056946822e861ec022fcefe Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Wed, 20 Sep 2017 22:54:26 +0200 Subject: SetMoveEffect functionally equivalent and close --- src/battle_4.c | 715 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 703 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/battle_4.c b/src/battle_4.c index 5d867289b..a51da55bf 100644 --- a/src/battle_4.c +++ b/src/battle_4.c @@ -71,15 +71,17 @@ extern u8 gPlayerPartyCount; extern u16 gMoveToLearn; extern u16 gRandomMove; extern u8 gBankInMenu; -extern u8 gActionForBanks[4]; +extern u8 gActionForBanks[BATTLE_BANKS_COUNT]; extern u8 gCurrentMoveTurn; -extern u8 gBattleBufferB[4][0x200]; +extern u8 gBattleBufferB[BATTLE_BANKS_COUNT][0x200]; +extern u16 gLockedMoves[BATTLE_BANKS_COUNT]; extern const struct BattleMove gBattleMoves[]; +extern const struct BaseStats gBaseStats[]; +extern const u8 gTypeEffectiveness[]; extern const u16 gMissStringIds[]; +extern const u16 gTrappingMoves[]; extern const u8 gTrainerMoney[]; -extern const u8 gTypeEffectiveness[]; -extern const struct BaseStats gBaseStats[]; // functions @@ -106,6 +108,9 @@ extern const u8 BattleScript_ItemSteal[]; extern const u8 BattleScript_RapidSpinAway[]; extern const u8 BattleScript_TargetPRLZHeal[]; extern const u8 BattleScript_KnockedOff[]; +extern const u8 BattleScript_AllStatsUp[]; +extern const u8 BattleScript_AtkDefDown[]; +extern const u8 BattleScript_SAtkDown2[]; extern const u8 BattleScript_LevelUp[]; extern const u8 BattleScript_WrapFree[]; extern const u8 BattleScript_LeechSeedFree[]; @@ -139,6 +144,7 @@ bool8 IsTwoTurnsMove(u16 move); void DestinyBondFlagUpdate(void); u8 AttacksThisTurn(u8 bank, u16 move); // Note: returns 1 if it's a charging turn, otherwise 2. static void CheckWonderGuardAndLevitate(void); +u8 ChangeStatBuffs(s8, u8 statId, u8, const u8* BS_ptr); void atk00_attackcanceler(void); void atk01_accuracycheck(void); @@ -672,14 +678,14 @@ const u16 gCriticalHitChance[] = {16, 8, 4, 3, 2}; const u32 gStatusFlagsForMoveEffects[] = { 0x00000000, - 0x00000007, - 0x00000008, - 0x00000010, - 0x00000020, - 0x00000040, - 0x00000080, - 0x00000007, - 0x00000008, + STATUS_SLEEP, + STATUS_POISON, + STATUS_BURN, + STATUS_FREEZE, + STATUS_PARALYSIS, + STATUS_TOXIC_POISON, + STATUS2_CONFUSION, + STATUS2_FLINCHED, 0x00000000, 0x00000070, 0x00000000, @@ -733,6 +739,8 @@ const u32 gStatusFlagsForMoveEffects[] = 0x00000000 }; +extern const u8* gMoveEffectBS_Ptrs[]; + void atk00_attackcanceler(void) { s32 i; @@ -2023,3 +2031,686 @@ u8 BankGetTurnOrder(u8 bank) } return i; } + +#define INCREMENT_RESET_RETURN \ +{ \ + gBattlescriptCurrInstr++; \ + gBattleCommunication[MOVE_EFFECT_BYTE] = 0; \ + return; \ +} + +#define RESET_RETURN \ +{ \ + gBattleCommunication[MOVE_EFFECT_BYTE] = 0; \ + return; \ +} + +void SetMoveEffect(bool8 primary, u8 certain) +{ + bool32 statusChanged = FALSE; + u8 affectsUser = 0; // 0x40 otherwise + bool32 noSunCanFreeze = TRUE; + + if (gBattleCommunication[MOVE_EFFECT_BYTE] & MOVE_EFFECT_AFFECTS_USER) + { + gEffectBank = gBankAttacker; // bank that effects get applied on + gBattleCommunication[MOVE_EFFECT_BYTE] &= ~(MOVE_EFFECT_AFFECTS_USER); + affectsUser = MOVE_EFFECT_AFFECTS_USER; + gBattleScripting.bank = gBankTarget; // theoretically the attacker + } + else + { + gEffectBank = gBankTarget; + gBattleScripting.bank = gBankAttacker; + } + + if (gBattleMons[gEffectBank].ability == ABILITY_SHIELD_DUST && !(gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + && !primary && gBattleCommunication[MOVE_EFFECT_BYTE] <= 9) + INCREMENT_RESET_RETURN + + if (gSideAffecting[GET_BANK_SIDE(gEffectBank)] & SIDE_STATUS_SAFEGUARD && !(gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + && !primary && gBattleCommunication[MOVE_EFFECT_BYTE] <= 7) + INCREMENT_RESET_RETURN + + if (gBattleMons[gEffectBank].hp == 0 + && gBattleCommunication[MOVE_EFFECT_BYTE] != MOVE_EFFECT_PAYDAY + && gBattleCommunication[MOVE_EFFECT_BYTE] != MOVE_EFFECT_STEAL_ITEM) + INCREMENT_RESET_RETURN + + if (gBattleMons[gEffectBank].status2 & STATUS2_SUBSTITUTE && affectsUser != MOVE_EFFECT_AFFECTS_USER) + INCREMENT_RESET_RETURN + + if (gBattleCommunication[MOVE_EFFECT_BYTE] <= 6) // status change + { + switch (gStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]) + { + case STATUS_SLEEP: + // check active uproar + if (gBattleMons[gEffectBank].ability != ABILITY_SOUNDPROOF) + { + for (gActiveBank = 0; + gActiveBank < gNoOfAllBanks && !(gBattleMons[gActiveBank].status2 & STATUS2_UPROAR); + gActiveBank++) + {} + } + else + gActiveBank = gNoOfAllBanks; + + if (gBattleMons[gEffectBank].status1) + break; + if (gActiveBank != gNoOfAllBanks) + break; + if (gBattleMons[gEffectBank].ability == ABILITY_VITAL_SPIRIT) + break; + if (gBattleMons[gEffectBank].ability == ABILITY_INSOMNIA) + break; + + CancelMultiTurnMoves(gEffectBank); + statusChanged = TRUE; + break; + case STATUS_POISON: + if (gBattleMons[gEffectBank].ability == ABILITY_IMMUNITY + && (primary == TRUE || certain == 0x80)) + { + gLastUsedAbility = ABILITY_IMMUNITY; + RecordAbilityBattle(gEffectBank, ABILITY_IMMUNITY); + + b_movescr_stack_push(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_PSNPrevention; + + if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD); + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + RESET_RETURN + } + if ((gBattleMons[gEffectBank].type1 == TYPE_POISON || gBattleMons[gEffectBank].type2 == TYPE_POISON + || gBattleMons[gEffectBank].type1 == TYPE_STEEL || gBattleMons[gEffectBank].type2 == TYPE_STEEL) + && (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + && (primary == 1 || certain == 0x80)) + { + b_movescr_stack_push(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_PSNPrevention; + + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + RESET_RETURN + } + if (gBattleMons[gEffectBank].type1 == TYPE_POISON) + break; + if (gBattleMons[gEffectBank].type2 == TYPE_POISON) + break; + if (gBattleMons[gEffectBank].type1 == TYPE_STEEL) + break; + if (gBattleMons[gEffectBank].type2 == TYPE_STEEL) + break; + if (gBattleMons[gEffectBank].status1) + break; + if (gBattleMons[gEffectBank].ability == ABILITY_IMMUNITY) + break; + + statusChanged = TRUE; + break; + case STATUS_BURN: + if (gBattleMons[gEffectBank].ability == ABILITY_WATER_VEIL + && (primary == 1 || certain == 0x80)) + { + gLastUsedAbility = ABILITY_WATER_VEIL; + RecordAbilityBattle(gEffectBank, ABILITY_WATER_VEIL); + + b_movescr_stack_push(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_BRNPrevention; + if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD); + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + RESET_RETURN + } + if ((gBattleMons[gEffectBank].type1 == TYPE_FIRE + || gBattleMons[gEffectBank].type2 == TYPE_FIRE) + && (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + && (primary == 1 || certain == 0x80)) + { + b_movescr_stack_push(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_BRNPrevention; + + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + RESET_RETURN + } + if (gBattleMons[gEffectBank].type1 == TYPE_FIRE) + break; + if (gBattleMons[gEffectBank].type2 == TYPE_FIRE) + break; + if (gBattleMons[gEffectBank].ability == ABILITY_WATER_VEIL) + break; + if (gBattleMons[gEffectBank].status1) + break; + + statusChanged = TRUE; + break; + case STATUS_FREEZE: + if (WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_SUN_ANY) + noSunCanFreeze = FALSE; + if (gBattleMons[gEffectBank].type1 == TYPE_ICE) + break; + if (gBattleMons[gEffectBank].type2 == TYPE_ICE) + break; + if (gBattleMons[gEffectBank].status1) + break; + if (noSunCanFreeze == 0) + break; + if (gBattleMons[gEffectBank].ability == ABILITY_MAGMA_ARMOR) + break; + + CancelMultiTurnMoves(gEffectBank); + statusChanged = TRUE; + break; + case STATUS_PARALYSIS: + if (gBattleMons[gEffectBank].ability == ABILITY_LIMBER) + { + if (primary == TRUE || certain == 0x80) + { + gLastUsedAbility = ABILITY_LIMBER; + RecordAbilityBattle(gEffectBank, ABILITY_LIMBER); + + b_movescr_stack_push(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_PRLZPrevention; + + if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD); + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + RESET_RETURN + } + else + break; + } + if (gBattleMons[gEffectBank].status1) + break; + + statusChanged = TRUE; + break; + case STATUS_TOXIC_POISON: + if (gBattleMons[gEffectBank].ability == ABILITY_IMMUNITY && (primary == 1 || certain == 0x80)) + { + gLastUsedAbility = ABILITY_IMMUNITY; + RecordAbilityBattle(gEffectBank, ABILITY_IMMUNITY); + + b_movescr_stack_push(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_PSNPrevention; + + if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD); + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + RESET_RETURN + } + if ((gBattleMons[gEffectBank].type1 == TYPE_POISON || gBattleMons[gEffectBank].type2 == TYPE_POISON + || gBattleMons[gEffectBank].type1 == TYPE_STEEL || gBattleMons[gEffectBank].type2 == TYPE_STEEL) + && (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + && (primary == TRUE || certain == 0x80)) + { + b_movescr_stack_push(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_PSNPrevention; + + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + RESET_RETURN + } + if (gBattleMons[gEffectBank].status1) + break; + if (gBattleMons[gEffectBank].type1 != TYPE_POISON + && gBattleMons[gEffectBank].type2 != TYPE_POISON + && gBattleMons[gEffectBank].type1 != TYPE_STEEL + && gBattleMons[gEffectBank].type2 != TYPE_STEEL) + { + if (gBattleMons[gEffectBank].ability == ABILITY_IMMUNITY) + break; + + // It's redundant, because at this point we know the status1 value is 0. + gBattleMons[gEffectBank].status1 &= ~(STATUS_TOXIC_POISON); + gBattleMons[gEffectBank].status1 &= ~(STATUS_POISON); + statusChanged = TRUE; + break; + } + else + { + gBattleMoveFlags |= MOVESTATUS_NOTAFFECTED; + } + break; + } + if (statusChanged == TRUE) + { + b_movescr_stack_push(gBattlescriptCurrInstr + 1); + + if (gStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]] == STATUS_SLEEP) + gBattleMons[gEffectBank].status1 |= ((Random() & 3) + 2); + else + gBattleMons[gEffectBank].status1 |= gStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]; + + gBattlescriptCurrInstr = gMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; + + gActiveBank = gEffectBank; + EmitSetAttributes(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gEffectBank].status1); + MarkBufferBankForExecution(gActiveBank); + + if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD); + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + + // for synchronize + + if (gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_POISON + || gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_TOXIC + || gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_PARALYSIS + || gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_BURN) + { + u8* synchronizeEffect = &gBattleStruct->synchronizeMoveEffect; + *synchronizeEffect = gBattleCommunication[MOVE_EFFECT_BYTE]; + gHitMarker |= HITMARKER_SYNCHRONISE_EFFECT; + } + return; + } + else if (statusChanged == FALSE) + { + gBattleCommunication[MOVE_EFFECT_BYTE] = 0; + gBattlescriptCurrInstr++; + return; + } + } + else + { + if (gBattleMons[gEffectBank].status2 & gStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]) + { + gBattlescriptCurrInstr++; + } + else + { + u8 side; + u32 statusFlag = + switch (gStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]) + { + case MOVE_EFFECT_CONFUSION: + if (gBattleMons[gEffectBank].ability == ABILITY_OWN_TEMPO + || gBattleMons[gEffectBank].status2 & STATUS2_CONFUSION) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleMons[gEffectBank].status2 |= (((Random()) % 0x4)) + 2; + + b_movescr_stack_push(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = gMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; + } + break; + case MOVE_EFFECT_FLINCH: + if (gBattleMons[gEffectBank].ability == ABILITY_INNER_FOCUS) + { + if (primary == 1 || certain == 0x80) + { + gLastUsedAbility = ABILITY_INNER_FOCUS; + RecordAbilityBattle(gEffectBank, ABILITY_INNER_FOCUS); + gBattlescriptCurrInstr = BattleScript_FlinchPrevention; + RESET_RETURN + } + else + { + gBattlescriptCurrInstr++; + break; + } + } + else + { + if (BankGetTurnOrder(gEffectBank) > gCurrentMoveTurn) + gBattleMons[gEffectBank].status2 |= gStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]; + INCREMENT_RESET_RETURN + } + break; + case MOVE_EFFECT_UPROAR: + if (gBattleMons[gEffectBank].status2 & STATUS2_UPROAR) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleMons[gEffectBank].status2 |= STATUS2_MULTIPLETURNS; + gLockedMoves[gEffectBank] = gCurrentMove; + gBattleMons[gEffectBank].status2 |= ((Random() & 3) + 2) << 4; + + b_movescr_stack_push(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = gMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; + } + break; + case MOVE_EFFECT_PAYDAY: + if (GET_BANK_SIDE(gBankAttacker) == SIDE_PLAYER) + { + u16 PayDay = gPaydayMoney; + gPaydayMoney += (gBattleMons[gBankAttacker].level * 5); + if (PayDay > gPaydayMoney) + gPaydayMoney = 0xFFFF; + } + b_movescr_stack_push(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = gMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; + break; + case MOVE_EFFECT_TRI_ATTACK: + if (gBattleMons[gEffectBank].status1) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleCommunication[MOVE_EFFECT_BYTE] = Random() % 3 + 3; + SetMoveEffect(FALSE, 0); + } + break; + case MOVE_EFFECT_CHARGING: + gBattleMons[gEffectBank].status2 |= STATUS2_MULTIPLETURNS; + gLockedMoves[gEffectBank] = gCurrentMove; + gProtectStructs[gEffectBank].chargingTurn = 1; + gBattlescriptCurrInstr++; + break; + case MOVE_EFFECT_WRAP: + if (gBattleMons[gEffectBank].status2 & STATUS2_WRAPPED) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleMons[gEffectBank].status2 |= ((Random() & 3) + 2) << 0xD; + + *(gBattleStruct->wrappedMove + gEffectBank * 2 + 0) = gCurrentMove; + *(gBattleStruct->wrappedMove + gEffectBank * 2 + 1) = gCurrentMove >> 8; + *(gBattleStruct->wrappedBy + gEffectBank) = gBankAttacker; + + b_movescr_stack_push(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = gMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; + + for (gBattleCommunication[MULTISTRING_CHOOSER] = 0; gBattleCommunication[MULTISTRING_CHOOSER] <= 4; gBattleCommunication[MULTISTRING_CHOOSER]++) + { + if (gCurrentMove == gTrappingMoves[gBattleCommunication[MULTISTRING_CHOOSER]]) + break; + } + } + break; + case MOVE_EFFECT_RECOIL_25: // 25% recoil + gBattleMoveDamage = (gHpDealt) / 4; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + + b_movescr_stack_push(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = gMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; + break; + case 15 ... 21: // stat + 1 + if (ChangeStatBuffs(0x10, gBattleCommunication[MOVE_EFFECT_BYTE] + 0xF2, affectsUser, 0)) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleScripting.animArg1 = gBattleCommunication[MOVE_EFFECT_BYTE] & 0x3F; + gBattleScripting.animArg2 = 0; + b_movescr_stack_push(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_StatUp; + } + break; + case 22 ... 28: // stat - 1 + if (ChangeStatBuffs(~(0x6f), gBattleCommunication[MOVE_EFFECT_BYTE] + 0xEB, affectsUser, 0)) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleScripting.animArg1 = gBattleCommunication[MOVE_EFFECT_BYTE] & 0x3F; + gBattleScripting.animArg2 = 0; + b_movescr_stack_push(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_StatDown; + } + break; + case 39 ... 45: // stat + 2 + if (ChangeStatBuffs(0x20, gBattleCommunication[MOVE_EFFECT_BYTE] + 0xDA, affectsUser, 0)) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleScripting.animArg1 = gBattleCommunication[MOVE_EFFECT_BYTE] & 0x3F; + gBattleScripting.animArg2 = 0; + b_movescr_stack_push(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_StatUp; + } + break; + case 46 ... 52: // stat - 2 + if (ChangeStatBuffs(~(0x5f), gBattleCommunication[MOVE_EFFECT_BYTE] + 0xD3, affectsUser, 0)) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleScripting.animArg1 = gBattleCommunication[MOVE_EFFECT_BYTE] & 0x3F; + gBattleScripting.animArg2 = 0; + b_movescr_stack_push(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_StatDown; + } + break; + case MOVE_EFFECT_RECHARGE: + gBattleMons[gEffectBank].status2 |= STATUS2_RECHARGE; + gDisableStructs[gEffectBank].rechargeCounter = 2; + gLockedMoves[gEffectBank] = gCurrentMove; + gBattlescriptCurrInstr++; + break; + case MOVE_EFFECT_RAGE: + gBattleMons[gBankAttacker].status2 |= STATUS2_RAGE; + gBattlescriptCurrInstr++; + break; + case MOVE_EFFECT_STEAL_ITEM: + { + if (gBattleTypeFlags & BATTLE_TYPE_x4000000) + { + gBattlescriptCurrInstr++; + break; + } + + side = GetBankSide(gBankAttacker); + if (GetBankSide(gBankAttacker) == SIDE_OPPONENT + && !(gBattleTypeFlags & + (BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_FRONTIER + | BATTLE_TYPE_LINK + | BATTLE_TYPE_x2000000 + | BATTLE_TYPE_SECRET_BASE))) + { + gBattlescriptCurrInstr++; + break; + } + if (!(gBattleTypeFlags & + (BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_FRONTIER + | BATTLE_TYPE_LINK + | BATTLE_TYPE_x2000000 + | BATTLE_TYPE_SECRET_BASE)) + && (gWishFutureKnock.knockedOffPokes[side] & gBitTable[gBattlePartyID[gBankAttacker]])) + { + gBattlescriptCurrInstr++; + break; + } + if (gBattleMons[gBankTarget].item + && gBattleMons[gBankTarget].ability == ABILITY_STICKY_HOLD) + { + b_movescr_stack_push_cursor(); + gBattlescriptCurrInstr = BattleScript_NoItemSteal; + + gLastUsedAbility = gBattleMons[gBankTarget].ability; + RecordAbilityBattle(gBankTarget, gLastUsedAbility); + + break; + } + if (gBattleMons[gBankAttacker].item) + { + gBattlescriptCurrInstr++; + break; + } + if (gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY) + { + gBattlescriptCurrInstr++; + break; + } + if (gBattleMons[gBankTarget].item > 0x78 + && gBattleMons[gBankTarget].item < (0x79 + 12)) + { + gBattlescriptCurrInstr++; + break; + } + if (gBattleMons[gBankTarget].item == 0) + { + gBattlescriptCurrInstr++; + break; + } + + *(u16*)((u8*)((gBattleStruct->field_D0) + gBankAttacker * 2)) = gLastUsedItem = gBattleMons[gBankTarget].item; + gBattleMons[gBankTarget].item = 0; + + gActiveBank = gBankAttacker; + EmitSetAttributes(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gLastUsedItem); + MarkBufferBankForExecution(gBankAttacker); + + gActiveBank = gBankTarget; + EmitSetAttributes(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gBankTarget].item); + MarkBufferBankForExecution(gBankTarget); + + b_movescr_stack_push(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_ItemSteal; + + *(u8*)((u8*)(&gBattleStruct->choicedMove[gBankTarget]) + 0) = 0; + *(u8*)((u8*)(&gBattleStruct->choicedMove[gBankTarget]) + 1) = 0; + } + break; + case MOVE_EFFECT_PREVENT_ESCAPE: + gBattleMons[gBankTarget].status2 |= STATUS2_ESCAPE_PREVENTION; + gDisableStructs[gBankTarget].bankPreventingEscape = gBankAttacker; + gBattlescriptCurrInstr++; + break; + case MOVE_EFFECT_NIGHTMARE: + gBattleMons[gBankTarget].status2 |= STATUS2_NIGHTMARE; + gBattlescriptCurrInstr++; + break; + case MOVE_EFFECT_ALL_STATS_UP: + b_movescr_stack_push(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_AllStatsUp; + break; + case MOVE_EFFECT_RAPIDSPIN: + b_movescr_stack_push(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_RapidSpinAway; + break; + case MOVE_EFFECT_REMOVE_PARALYSIS: // Smelling salts + if (!(gBattleMons[gBankTarget].status1 & STATUS_PARALYSIS)) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleMons[gBankTarget].status1 &= ~(STATUS_PARALYSIS); + + gActiveBank = gBankTarget; + EmitSetAttributes(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gBankTarget].status1); + MarkBufferBankForExecution(gActiveBank); + + b_movescr_stack_push(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_TargetPRLZHeal; + } + break; + case MOVE_EFFECT_ATK_DEF_DOWN: // SuperPower + b_movescr_stack_push(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_AtkDefDown; + break; + case MOVE_EFFECT_RECOIL_33_PARALYSIS: // Volt Tackle + gBattleMoveDamage = gHpDealt / 3; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + + b_movescr_stack_push(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = gMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; + break; + case MOVE_EFFECT_THRASH: + if (gBattleMons[gEffectBank].status2 & STATUS2_LOCK_CONFUSE) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleMons[gEffectBank].status2 |= STATUS2_MULTIPLETURNS; + gLockedMoves[gEffectBank] = gCurrentMove; + gBattleMons[gEffectBank].status2 |= (((Random() & 1) + 2) << 0xA); + } + break; + case MOVE_EFFECT_KNOCK_OFF: + if (gBattleMons[gEffectBank].ability == ABILITY_STICKY_HOLD) + { + if (gBattleMons[gEffectBank].item == 0) + { + gBattlescriptCurrInstr++; + } + else + { + gLastUsedAbility = ABILITY_STICKY_HOLD; + gBattlescriptCurrInstr = BattleScript_NoItemSteal; + RecordAbilityBattle(gEffectBank, ABILITY_STICKY_HOLD); + } + break; + } + if (gBattleMons[gEffectBank].item == 0) + { + gBattlescriptCurrInstr++; + } + else + { + side = GetBankSide(gEffectBank); + + gLastUsedItem = gBattleMons[gEffectBank].item; + gBattleMons[gEffectBank].item = 0; + gWishFutureKnock.knockedOffPokes[side] |= gBitTable[gBattlePartyID[gEffectBank]]; + + b_movescr_stack_push(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_KnockedOff; + + *(u8*)((u8*)(&gBattleStruct->choicedMove[gEffectBank]) + 0) = 0; + *(u8*)((u8*)(&gBattleStruct->choicedMove[gEffectBank]) + 1) = 0; + } + break; + default: + gBattlescriptCurrInstr++; + break; + case MOVE_EFFECT_SP_ATK_TWO_DOWN: // Overheat + b_movescr_stack_push(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_SAtkDown2; + break; + } + } + } + + gBattleCommunication[MOVE_EFFECT_BYTE] = 0; +} -- cgit v1.2.3 From cf26b0e125aef07052b333139c33a6bbe1088f96 Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Wed, 20 Sep 2017 22:55:37 +0200 Subject: forgot save lol --- src/battle_4.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/battle_4.c b/src/battle_4.c index a51da55bf..6e71a6a57 100644 --- a/src/battle_4.c +++ b/src/battle_4.c @@ -2351,7 +2351,6 @@ void SetMoveEffect(bool8 primary, u8 certain) else { u8 side; - u32 statusFlag = switch (gStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]) { case MOVE_EFFECT_CONFUSION: -- cgit v1.2.3 From d5afb0c6e9566a62ca6d597aeabc173b2c3e7fa5 Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Fri, 22 Sep 2017 21:33:49 +0200 Subject: up to x48 and troubles --- src/battle_3.c | 92 +-- src/battle_4.c | 1884 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 1810 insertions(+), 166 deletions(-) (limited to 'src') diff --git a/src/battle_3.c b/src/battle_3.c index 4f0997aa0..1b62e3bb8 100644 --- a/src/battle_3.c +++ b/src/battle_3.c @@ -196,17 +196,17 @@ extern void sub_803E08C(void); extern void bc_move_exec_returning(void); extern s8 GetFlavourRelationByPersonality(u32 personality, u8 flavor); -void b_movescr_stack_push(const u8* bsPtr) +void BattleScriptPush(const u8* bsPtr) { BATTLESCRIPTS_STACK->ptr[BATTLESCRIPTS_STACK->size++] = bsPtr; } -void b_movescr_stack_push_cursor(void) +void BattleScriptPushCursor(void) { BATTLESCRIPTS_STACK->ptr[BATTLESCRIPTS_STACK->size++] = gBattlescriptCurrInstr; } -void b_movescr_stack_pop_cursor(void) +void BattleScriptPop(void) { gBattlescriptCurrInstr = BATTLESCRIPTS_STACK->ptr[--BATTLESCRIPTS_STACK->size]; } @@ -1206,7 +1206,7 @@ u8 AtkCanceller_UnableToUseMove(void) { gBattleMons[gBankAttacker].status1 &= ~(STATUS_SLEEP); gBattleMons[gBankAttacker].status2 &= ~(STATUS2_NIGHTMARE); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattleCommunication[MULTISTRING_CHOOSER] = 1; gBattlescriptCurrInstr = BattleScript_MoveUsedWokeUp; effect = 2; @@ -1234,7 +1234,7 @@ u8 AtkCanceller_UnableToUseMove(void) else { gBattleMons[gBankAttacker].status2 &= ~(STATUS2_NIGHTMARE); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattleCommunication[MULTISTRING_CHOOSER] = 0; gBattlescriptCurrInstr = BattleScript_MoveUsedWokeUp; effect = 2; @@ -1262,7 +1262,7 @@ u8 AtkCanceller_UnableToUseMove(void) else // unfreeze { gBattleMons[gBankAttacker].status1 &= ~(STATUS_FREEZE); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_MoveUsedUnfroze; gBattleCommunication[MULTISTRING_CHOOSER] = 0; } @@ -1349,7 +1349,7 @@ u8 AtkCanceller_UnableToUseMove(void) if (Random() & 1) { gBattleCommunication[MULTISTRING_CHOOSER] = 0; - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); } else // confusion dmg { @@ -1363,7 +1363,7 @@ u8 AtkCanceller_UnableToUseMove(void) } else // snapped out of confusion { - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_MoveUsedIsConfusedNoMore; } effect = 1; @@ -1387,10 +1387,10 @@ u8 AtkCanceller_UnableToUseMove(void) { gBattleScripting.bank = CountTrailingZeroBits((gBattleMons[gBankAttacker].status2 & STATUS2_INFATUATION) >> 0x10); if (Random() & 1) - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); else { - b_movescr_stack_push(BattleScript_MoveUsedIsParalyzedCantAttack); + BattleScriptPush(BattleScript_MoveUsedIsParalyzedCantAttack); gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; gProtectStructs[gBankAttacker].loveImmobility = 1; CancelMultiTurnMoves(gBankAttacker); @@ -1432,7 +1432,7 @@ u8 AtkCanceller_UnableToUseMove(void) if (gBattleMoves[gCurrentMove].effect == EFFECT_THAW_HIT) { gBattleMons[gBankAttacker].status1 &= ~(STATUS_FREEZE); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_MoveUsedUnfroze; gBattleCommunication[MULTISTRING_CHOOSER] = 1; } @@ -1969,7 +1969,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) gBattleTextBuff1[1] = 3; gBattleTextBuff1[2] = moveType; gBattleTextBuff1[3] = 0xFF; - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_ColorChangeActivates; effect++; } @@ -1985,7 +1985,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 16; if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_RoughSkinActivates; effect++; } @@ -2006,7 +2006,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) if (gBattleCommunication[MOVE_EFFECT_BYTE] == 3) gBattleCommunication[MOVE_EFFECT_BYTE] += 2; gBattleCommunication[MOVE_EFFECT_BYTE] += 0x40; - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_ApplySecondaryEffect; gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; effect++; @@ -2021,7 +2021,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) && (Random() % 3) == 0) { gBattleCommunication[MOVE_EFFECT_BYTE] = 0x42; - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_ApplySecondaryEffect; gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; effect++; @@ -2036,7 +2036,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) && (Random() % 3) == 0) { gBattleCommunication[MOVE_EFFECT_BYTE] = 0x45; - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_ApplySecondaryEffect; gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; effect++; @@ -2051,7 +2051,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) && (Random() % 3) == 0) { gBattleCommunication[MOVE_EFFECT_BYTE] = 0x43; - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_ApplySecondaryEffect; gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; effect++; @@ -2073,7 +2073,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) && GetGenderFromSpeciesAndPersonality(speciesDef, pidDef) != 0xFF) { gBattleMons[gBankAttacker].status2 |= (gBitTable[gBankTarget] << 0x10); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_CuteCharmActivates; effect++; } @@ -2155,7 +2155,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) gBattleMons[i].status2 &= ~(STATUS2_INFATUATION); break; } - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = gUnknown_082DB68C; gBattleScripting.bank = i; gActiveBank = i; @@ -2197,7 +2197,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) gBattleStruct->synchronizeMoveEffect = 2; gBattleCommunication[MOVE_EFFECT_BYTE] = gBattleStruct->synchronizeMoveEffect + 0x40; gBattleScripting.bank = gBankTarget; - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_SynchronizeActivates; gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; effect++; @@ -2212,7 +2212,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) gBattleStruct->synchronizeMoveEffect = 2; gBattleCommunication[MOVE_EFFECT_BYTE] = gBattleStruct->synchronizeMoveEffect; gBattleScripting.bank = gBankAttacker; - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_SynchronizeActivates; gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; effect++; @@ -2303,7 +2303,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) { gLastUsedAbility = ABILITY_INTIMIDATE; gStatuses3[i] &= ~(STATUS3_INTIMIDATE_POKES); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = gUnknown_082DB4C1; gBattleStruct->intimidateBank = i; effect++; @@ -3592,7 +3592,7 @@ _0804330E:\n\ strb r3, [r1, 0x2]\n\ movs r0, 0xFF\n\ strb r0, [r1, 0x3]\n\ - bl b_movescr_stack_push_cursor\n\ + bl BattleScriptPushCursor\n\ ldr r1, =gBattlescriptCurrInstr\n\ ldr r0, =BattleScript_ColorChangeActivates\n\ str r0, [r1]\n\ @@ -3668,7 +3668,7 @@ _080433CA:\n\ bne _080433D8\n\ str r2, [r1]\n\ _080433D8:\n\ - bl b_movescr_stack_push_cursor\n\ + bl BattleScriptPushCursor\n\ ldr r1, =gBattlescriptCurrInstr\n\ ldr r0, =BattleScript_RoughSkinActivates\n\ str r0, [r1]\n\ @@ -3763,7 +3763,7 @@ _080434BC:\n\ ldrb r0, [r1, 0x3]\n\ adds r0, 0x40\n\ strb r0, [r1, 0x3]\n\ - bl b_movescr_stack_push_cursor\n\ + bl BattleScriptPushCursor\n\ ldr r1, =gBattlescriptCurrInstr\n\ ldr r0, =BattleScript_ApplySecondaryEffect\n\ str r0, [r1]\n\ @@ -3849,7 +3849,7 @@ _08043598:\n\ ldr r1, =gBattleCommunication\n\ movs r0, 0x42\n\ strb r0, [r1, 0x3]\n\ - bl b_movescr_stack_push_cursor\n\ + bl BattleScriptPushCursor\n\ ldr r1, =gBattlescriptCurrInstr\n\ ldr r0, =BattleScript_ApplySecondaryEffect\n\ str r0, [r1]\n\ @@ -3935,7 +3935,7 @@ _08043674:\n\ ldr r1, =gBattleCommunication\n\ movs r0, 0x45\n\ strb r0, [r1, 0x3]\n\ - bl b_movescr_stack_push_cursor\n\ + bl BattleScriptPushCursor\n\ ldr r1, =gBattlescriptCurrInstr\n\ ldr r0, =BattleScript_ApplySecondaryEffect\n\ str r0, [r1]\n\ @@ -4021,7 +4021,7 @@ _08043750:\n\ ldr r1, =gBattleCommunication\n\ movs r0, 0x43\n\ strb r0, [r1, 0x3]\n\ - bl b_movescr_stack_push_cursor\n\ + bl BattleScriptPushCursor\n\ ldr r1, =gBattlescriptCurrInstr\n\ ldr r0, =BattleScript_ApplySecondaryEffect\n\ str r0, [r1]\n\ @@ -4183,7 +4183,7 @@ _080438B6:\n\ ldr r0, [r2]\n\ orrs r0, r1\n\ str r0, [r2]\n\ - bl b_movescr_stack_push_cursor\n\ + bl BattleScriptPushCursor\n\ ldr r1, =gBattlescriptCurrInstr\n\ ldr r0, =BattleScript_CuteCharmActivates\n\ str r0, [r1]\n\ @@ -4484,7 +4484,7 @@ _08043BF8:\n\ _08043BFA:\n\ str r0, [r2]\n\ _08043BFC:\n\ - bl b_movescr_stack_push_cursor\n\ + bl BattleScriptPushCursor\n\ ldr r1, =gBattlescriptCurrInstr\n\ ldr r0, =gUnknown_082DB68C\n\ str r0, [r1]\n\ @@ -4607,7 +4607,7 @@ _08043CF8:\n\ ldr r0, =gBankTarget\n\ ldrb r0, [r0]\n\ strb r0, [r1, 0x17]\n\ - bl b_movescr_stack_push_cursor\n\ + bl BattleScriptPushCursor\n\ ldr r1, =gBattlescriptCurrInstr\n\ ldr r0, =BattleScript_SynchronizeActivates\n\ str r0, [r1]\n\ @@ -4662,7 +4662,7 @@ _08043D7C:\n\ ldr r0, =gBankAttacker\n\ ldrb r0, [r0]\n\ strb r0, [r1, 0x17]\n\ - bl b_movescr_stack_push_cursor\n\ + bl BattleScriptPushCursor\n\ ldr r1, =gBattlescriptCurrInstr\n\ ldr r0, =BattleScript_SynchronizeActivates\n\ str r0, [r1]\n\ @@ -5380,7 +5380,7 @@ _080443B4:\n\ ldr r1, =0xfff7ffff\n\ ands r0, r1\n\ str r0, [r2]\n\ - bl b_movescr_stack_push_cursor\n\ + bl BattleScriptPushCursor\n\ ldr r1, =gBattlescriptCurrInstr\n\ ldr r0, =gUnknown_082DB4C1\n\ str r0, [r1]\n\ @@ -5465,7 +5465,7 @@ void b_call_bc_move_exec(const u8* BS_ptr) void b_push_move_exec(const u8* BS_ptr) { - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BS_ptr; BATTLE_CALLBACKS_STACK->function[BATTLE_CALLBACKS_STACK->size++] = gBattleMainFunc; gBattleMainFunc = sub_803E08C; @@ -6029,7 +6029,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) if (gBattleMons[bank].status1 & STATUS_PARALYSIS) { gBattleMons[bank].status1 &= ~(STATUS_PARALYSIS); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_BerryCureParRet; effect = ITEM_STATUS_CHANGE; } @@ -6038,7 +6038,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) if (gBattleMons[bank].status1 & STATUS_PSN_ANY) { gBattleMons[bank].status1 &= ~(STATUS_PSN_ANY | STATUS_TOXIC_COUNTER); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_BerryCurePsnRet; effect = ITEM_STATUS_CHANGE; } @@ -6047,7 +6047,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) if (gBattleMons[bank].status1 & STATUS_BURN) { gBattleMons[bank].status1 &= ~(STATUS_BURN); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_BerryCureBrnRet; effect = ITEM_STATUS_CHANGE; } @@ -6056,7 +6056,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) if (gBattleMons[bank].status1 & STATUS_FREEZE) { gBattleMons[bank].status1 &= ~(STATUS_FREEZE); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_BerryCureFrzRet; effect = ITEM_STATUS_CHANGE; } @@ -6066,7 +6066,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) { gBattleMons[bank].status1 &= ~(STATUS_SLEEP); gBattleMons[bank].status2 &= ~(STATUS2_NIGHTMARE); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_BerryCureSlpRet; effect = ITEM_STATUS_CHANGE; } @@ -6075,7 +6075,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) if (gBattleMons[bank].status2 & STATUS2_CONFUSION) { gBattleMons[bank].status2 &= ~(STATUS2_CONFUSION); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_BerryCureConfusionRet; effect = ITEM_EFFECT_OTHER; } @@ -6085,7 +6085,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) { gBattleMons[bank].status2 &= ~(STATUS2_INFATUATION); StringCopy(gBattleTextBuff1, gStatusConditionString_LoveJpn); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattleCommunication[MULTISTRING_CHOOSER] = 0; gBattlescriptCurrInstr = BattleScript_BerryCureChosenStatusRet; effect = ITEM_EFFECT_OTHER; @@ -6121,7 +6121,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) } gBattleMons[bank].status1 = 0; gBattleMons[bank].status2 &= ~(STATUS2_CONFUSION); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattleCommunication[MULTISTRING_CHOOSER] = 0; gBattlescriptCurrInstr = BattleScript_BerryCureChosenStatusRet; effect = ITEM_STATUS_CHANGE; @@ -6140,7 +6140,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) { gBattleScripting.bank = bank; gStringBank = bank; - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_WhiteHerbRet; return effect; // unnecessary return } @@ -6170,9 +6170,9 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) && gBattleMons[gBankTarget].hp) { gBattleCommunication[MOVE_EFFECT_BYTE] = 8; - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); SetMoveEffect(0, 0); - b_movescr_stack_pop_cursor(); + BattleScriptPop(); } break; case HOLD_EFFECT_SHELL_BELL: @@ -6190,7 +6190,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) if (gBattleMoveDamage == 0) gBattleMoveDamage = -1; gSpecialStatuses[gBankTarget].moveturnLostHP = 0; - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_ItemHealHP_Ret; effect++; } diff --git a/src/battle_4.c b/src/battle_4.c index 6e71a6a57..8e0be22c2 100644 --- a/src/battle_4.c +++ b/src/battle_4.c @@ -15,6 +15,8 @@ #include "battle_controllers.h" #include "species.h" #include "songs.h" +#include "text.h" +#include "sound.h" // variables @@ -75,6 +77,7 @@ extern u8 gActionForBanks[BATTLE_BANKS_COUNT]; extern u8 gCurrentMoveTurn; extern u8 gBattleBufferB[BATTLE_BANKS_COUNT][0x200]; extern u16 gLockedMoves[BATTLE_BANKS_COUNT]; +extern u16 gPartnerTrainerId; extern const struct BattleMove gBattleMoves[]; extern const struct BaseStats gBaseStats[]; @@ -84,7 +87,7 @@ extern const u16 gTrappingMoves[]; extern const u8 gTrainerMoney[]; // functions - +extern void sub_81A5718(u8 bank); // battle frontier 2 // BattleScripts extern const u8 BattleScript_MoveEnd[]; @@ -108,6 +111,7 @@ extern const u8 BattleScript_ItemSteal[]; extern const u8 BattleScript_RapidSpinAway[]; extern const u8 BattleScript_TargetPRLZHeal[]; extern const u8 BattleScript_KnockedOff[]; +extern const u8 BattleScript_StickyHoldOnKnockOff[]; extern const u8 BattleScript_AllStatsUp[]; extern const u8 BattleScript_AtkDefDown[]; extern const u8 BattleScript_SAtkDown2[]; @@ -124,6 +128,10 @@ extern const u8 BattleScript_TrainerBallBlock[]; extern const u8 BattleScript_WallyBallThrow[]; extern const u8 BattleScript_SuccessBallThrow[]; extern const u8 BattleScript_ShakeBallThrow[]; +extern const u8 BattleScript_FaintAttacker[]; +extern const u8 BattleScript_FaintTarget[]; +extern const u8 BattleScript_DestinyBondTakesLife[]; +extern const u8 BattleScript_GrudgeTakesPp[]; // read via orr #define BSScriptRead32(ptr) ((ptr)[0] | (ptr)[1] << 8 | (ptr)[2] << 16 | (ptr)[3] << 24) @@ -144,7 +152,7 @@ bool8 IsTwoTurnsMove(u16 move); void DestinyBondFlagUpdate(void); u8 AttacksThisTurn(u8 bank, u16 move); // Note: returns 1 if it's a charging turn, otherwise 2. static void CheckWonderGuardAndLevitate(void); -u8 ChangeStatBuffs(s8, u8 statId, u8, const u8* BS_ptr); +u8 ChangeStatBuffs(s8 statValue, u8 statId, u8, const u8* BS_ptr); void atk00_attackcanceler(void); void atk01_accuracycheck(void); @@ -687,10 +695,10 @@ const u32 gStatusFlagsForMoveEffects[] = STATUS2_CONFUSION, STATUS2_FLINCHED, 0x00000000, - 0x00000070, + STATUS2_UPROAR, 0x00000000, - 0x00001000, - 0x0000E000, + STATUS2_MULTIPLETURNS, + STATUS2_WRAPPED, 0x00000000, 0x00000000, 0x00000000, @@ -706,10 +714,10 @@ const u32 gStatusFlagsForMoveEffects[] = 0x00000000, 0x00000000, 0x00000000, - 0x00400000, + STATUS2_RECHARGE, 0x00000000, 0x00000000, - 0x04000000, + STATUS2_ESCAPE_PREVENTION, 0x08000000, 0x00000000, 0x00000000, @@ -730,7 +738,7 @@ const u32 gStatusFlagsForMoveEffects[] = 0x00000000, 0x00000000, 0x00000000, - 0x00000C00, + STATUS2_LOCK_CONFUSE, 0x00000000, 0x00000000, 0x00000000, @@ -792,7 +800,7 @@ void atk00_attackcanceler(void) { PressurePPLose(gBankAttacker, gBankTarget, MOVE_MAGIC_COAT); gProtectStructs[gBankTarget].bounceMove = 0; - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_MagicCoatBounce; return; } @@ -804,7 +812,7 @@ void atk00_attackcanceler(void) PressurePPLose(gBankAttacker, gTurnOrder[i], MOVE_SNATCH); gProtectStructs[gTurnOrder[i]].stealMove = 0; gBattleScripting.bank = gTurnOrder[i]; - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_SnatchedMove; return; } @@ -814,7 +822,7 @@ void atk00_attackcanceler(void) { gSpecialStatuses[gBankTarget].lightningRodRedirected = 0; gLastUsedAbility = ABILITY_LIGHTNING_ROD; - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_TookAttack; RecordAbilityBattle(gBankTarget, gLastUsedAbility); } @@ -1584,7 +1592,7 @@ void atk09_attackanimation(void) if ((gHitMarker & HITMARKER_NO_ANIMATIONS) && (gCurrentMove != MOVE_TRANSFORM && gCurrentMove != MOVE_SUBSTITUTE)) { - b_movescr_stack_push(gBattlescriptCurrInstr + 1); + BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_Pausex20; gBattleScripting.animTurn++; gBattleScripting.animTargetsHit++; @@ -1625,7 +1633,7 @@ void atk09_attackanimation(void) } else { - b_movescr_stack_push(gBattlescriptCurrInstr + 1); + BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_Pausex20; } } @@ -1710,7 +1718,7 @@ void atk0C_datahpupdate(void) if (gDisableStructs[gActiveBank].substituteHP == 0) { gBattlescriptCurrInstr += 2; - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_SubstituteFade; return; } @@ -1898,7 +1906,7 @@ void atk0F_resultmessage(void) gLastUsedItem = gBattleMons[gBankTarget].item; gStringBank = gBankTarget; gBattleMoveFlags &= ~(MOVESTATUS_ENDURED | MOVESTATUS_HUNGON); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_HangedOnMsg; return; default: @@ -1911,14 +1919,14 @@ void atk0F_resultmessage(void) gBattleMoveFlags &= ~(MOVESTATUS_ONEHITKO); gBattleMoveFlags &= ~(MOVESTATUS_SUPEREFFECTIVE); gBattleMoveFlags &= ~(MOVESTATUS_NOTVERYEFFECTIVE); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_OneHitKOMsg; return; } else if (gBattleMoveFlags & MOVESTATUS_ENDURED) { gBattleMoveFlags &= ~(MOVESTATUS_ENDURED | MOVESTATUS_HUNGON); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_EnduredMsg; return; } @@ -1927,7 +1935,7 @@ void atk0F_resultmessage(void) gLastUsedItem = gBattleMons[gBankTarget].item; gStringBank = gBankTarget; gBattleMoveFlags &= ~(MOVESTATUS_ENDURED | MOVESTATUS_HUNGON); - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_HangedOnMsg; return; } @@ -2110,12 +2118,12 @@ void SetMoveEffect(bool8 primary, u8 certain) break; case STATUS_POISON: if (gBattleMons[gEffectBank].ability == ABILITY_IMMUNITY - && (primary == TRUE || certain == 0x80)) + && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) { gLastUsedAbility = ABILITY_IMMUNITY; RecordAbilityBattle(gEffectBank, ABILITY_IMMUNITY); - b_movescr_stack_push(gBattlescriptCurrInstr + 1); + BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_PSNPrevention; if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) @@ -2132,9 +2140,9 @@ void SetMoveEffect(bool8 primary, u8 certain) if ((gBattleMons[gEffectBank].type1 == TYPE_POISON || gBattleMons[gEffectBank].type2 == TYPE_POISON || gBattleMons[gEffectBank].type1 == TYPE_STEEL || gBattleMons[gEffectBank].type2 == TYPE_STEEL) && (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) - && (primary == 1 || certain == 0x80)) + && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) { - b_movescr_stack_push(gBattlescriptCurrInstr + 1); + BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_PSNPrevention; gBattleCommunication[MULTISTRING_CHOOSER] = 2; @@ -2157,12 +2165,12 @@ void SetMoveEffect(bool8 primary, u8 certain) break; case STATUS_BURN: if (gBattleMons[gEffectBank].ability == ABILITY_WATER_VEIL - && (primary == 1 || certain == 0x80)) + && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) { gLastUsedAbility = ABILITY_WATER_VEIL; RecordAbilityBattle(gEffectBank, ABILITY_WATER_VEIL); - b_movescr_stack_push(gBattlescriptCurrInstr + 1); + BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_BRNPrevention; if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) { @@ -2178,9 +2186,9 @@ void SetMoveEffect(bool8 primary, u8 certain) if ((gBattleMons[gEffectBank].type1 == TYPE_FIRE || gBattleMons[gEffectBank].type2 == TYPE_FIRE) && (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) - && (primary == 1 || certain == 0x80)) + && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) { - b_movescr_stack_push(gBattlescriptCurrInstr + 1); + BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_BRNPrevention; gBattleCommunication[MULTISTRING_CHOOSER] = 2; @@ -2217,12 +2225,12 @@ void SetMoveEffect(bool8 primary, u8 certain) case STATUS_PARALYSIS: if (gBattleMons[gEffectBank].ability == ABILITY_LIMBER) { - if (primary == TRUE || certain == 0x80) + if (primary == TRUE || certain == MOVE_EFFECT_CERTAIN) { gLastUsedAbility = ABILITY_LIMBER; RecordAbilityBattle(gEffectBank, ABILITY_LIMBER); - b_movescr_stack_push(gBattlescriptCurrInstr + 1); + BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_PRLZPrevention; if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) @@ -2245,12 +2253,12 @@ void SetMoveEffect(bool8 primary, u8 certain) statusChanged = TRUE; break; case STATUS_TOXIC_POISON: - if (gBattleMons[gEffectBank].ability == ABILITY_IMMUNITY && (primary == 1 || certain == 0x80)) + if (gBattleMons[gEffectBank].ability == ABILITY_IMMUNITY && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) { gLastUsedAbility = ABILITY_IMMUNITY; RecordAbilityBattle(gEffectBank, ABILITY_IMMUNITY); - b_movescr_stack_push(gBattlescriptCurrInstr + 1); + BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_PSNPrevention; if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) @@ -2267,9 +2275,9 @@ void SetMoveEffect(bool8 primary, u8 certain) if ((gBattleMons[gEffectBank].type1 == TYPE_POISON || gBattleMons[gEffectBank].type2 == TYPE_POISON || gBattleMons[gEffectBank].type1 == TYPE_STEEL || gBattleMons[gEffectBank].type2 == TYPE_STEEL) && (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) - && (primary == TRUE || certain == 0x80)) + && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) { - b_movescr_stack_push(gBattlescriptCurrInstr + 1); + BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_PSNPrevention; gBattleCommunication[MULTISTRING_CHOOSER] = 2; @@ -2299,7 +2307,7 @@ void SetMoveEffect(bool8 primary, u8 certain) } if (statusChanged == TRUE) { - b_movescr_stack_push(gBattlescriptCurrInstr + 1); + BattleScriptPush(gBattlescriptCurrInstr + 1); if (gStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]] == STATUS_SLEEP) gBattleMons[gEffectBank].status1 |= ((Random() & 3) + 2); @@ -2341,6 +2349,7 @@ void SetMoveEffect(bool8 primary, u8 certain) gBattlescriptCurrInstr++; return; } + return; } else { @@ -2351,7 +2360,7 @@ void SetMoveEffect(bool8 primary, u8 certain) else { u8 side; - switch (gStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]) + switch (gBattleCommunication[MOVE_EFFECT_BYTE]) { case MOVE_EFFECT_CONFUSION: if (gBattleMons[gEffectBank].ability == ABILITY_OWN_TEMPO @@ -2363,47 +2372,46 @@ void SetMoveEffect(bool8 primary, u8 certain) { gBattleMons[gEffectBank].status2 |= (((Random()) % 0x4)) + 2; - b_movescr_stack_push(gBattlescriptCurrInstr + 1); + BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = gMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; } break; case MOVE_EFFECT_FLINCH: if (gBattleMons[gEffectBank].ability == ABILITY_INNER_FOCUS) { - if (primary == 1 || certain == 0x80) + if (primary == TRUE || certain == MOVE_EFFECT_CERTAIN) { gLastUsedAbility = ABILITY_INNER_FOCUS; RecordAbilityBattle(gEffectBank, ABILITY_INNER_FOCUS); gBattlescriptCurrInstr = BattleScript_FlinchPrevention; - RESET_RETURN } else { gBattlescriptCurrInstr++; - break; } } else { if (BankGetTurnOrder(gEffectBank) > gCurrentMoveTurn) gBattleMons[gEffectBank].status2 |= gStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]; - INCREMENT_RESET_RETURN + gBattlescriptCurrInstr++; } break; case MOVE_EFFECT_UPROAR: - if (gBattleMons[gEffectBank].status2 & STATUS2_UPROAR) - { - gBattlescriptCurrInstr++; - } - else + if (!(gBattleMons[gEffectBank].status2 & STATUS2_UPROAR)) { + gBattleMons[gEffectBank].status2 |= STATUS2_MULTIPLETURNS; gLockedMoves[gEffectBank] = gCurrentMove; gBattleMons[gEffectBank].status2 |= ((Random() & 3) + 2) << 4; - b_movescr_stack_push(gBattlescriptCurrInstr + 1); + BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = gMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; } + else + { + gBattlescriptCurrInstr++; + } break; case MOVE_EFFECT_PAYDAY: if (GET_BANK_SIDE(gBankAttacker) == SIDE_PLAYER) @@ -2413,7 +2421,7 @@ void SetMoveEffect(bool8 primary, u8 certain) if (PayDay > gPaydayMoney) gPaydayMoney = 0xFFFF; } - b_movescr_stack_push(gBattlescriptCurrInstr + 1); + BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = gMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; break; case MOVE_EFFECT_TRI_ATTACK: @@ -2440,18 +2448,20 @@ void SetMoveEffect(bool8 primary, u8 certain) } else { - gBattleMons[gEffectBank].status2 |= ((Random() & 3) + 2) << 0xD; + gBattleMons[gEffectBank].status2 |= ((Random() & 3) + 3) << 0xD; *(gBattleStruct->wrappedMove + gEffectBank * 2 + 0) = gCurrentMove; *(gBattleStruct->wrappedMove + gEffectBank * 2 + 1) = gCurrentMove >> 8; *(gBattleStruct->wrappedBy + gEffectBank) = gBankAttacker; - b_movescr_stack_push(gBattlescriptCurrInstr + 1); + BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = gMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; - for (gBattleCommunication[MULTISTRING_CHOOSER] = 0; gBattleCommunication[MULTISTRING_CHOOSER] <= 4; gBattleCommunication[MULTISTRING_CHOOSER]++) + for (gBattleCommunication[MULTISTRING_CHOOSER] = 0; ; gBattleCommunication[MULTISTRING_CHOOSER]++) { - if (gCurrentMove == gTrappingMoves[gBattleCommunication[MULTISTRING_CHOOSER]]) + if (gBattleCommunication[MULTISTRING_CHOOSER] > 4) + break; + if (gTrappingMoves[gBattleCommunication[MULTISTRING_CHOOSER]] == gCurrentMove) break; } } @@ -2461,58 +2471,90 @@ void SetMoveEffect(bool8 primary, u8 certain) if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; - b_movescr_stack_push(gBattlescriptCurrInstr + 1); + BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = gMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; break; - case 15 ... 21: // stat + 1 - if (ChangeStatBuffs(0x10, gBattleCommunication[MOVE_EFFECT_BYTE] + 0xF2, affectsUser, 0)) + case MOVE_EFFECT_ATK_PLUS_1: + case MOVE_EFFECT_DEF_PLUS_1: + case MOVE_EFFECT_SPD_PLUS_1: + case MOVE_EFFECT_SP_ATK_PLUS_1: + case MOVE_EFFECT_SP_DEF_PLUS_1: + case MOVE_EFFECT_ACC_PLUS_1: + case MOVE_EFFECT_EVS_PLUS_1: + if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(1), + gBattleCommunication[MOVE_EFFECT_BYTE] - MOVE_EFFECT_ATK_PLUS_1 + 1, + affectsUser, 0)) { gBattlescriptCurrInstr++; } else { - gBattleScripting.animArg1 = gBattleCommunication[MOVE_EFFECT_BYTE] & 0x3F; + gBattleScripting.animArg1 = gBattleCommunication[MOVE_EFFECT_BYTE] & ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); gBattleScripting.animArg2 = 0; - b_movescr_stack_push(gBattlescriptCurrInstr + 1); + BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_StatUp; } break; - case 22 ... 28: // stat - 1 - if (ChangeStatBuffs(~(0x6f), gBattleCommunication[MOVE_EFFECT_BYTE] + 0xEB, affectsUser, 0)) + case MOVE_EFFECT_ATK_MINUS_1: + case MOVE_EFFECT_DEF_MINUS_1: + case MOVE_EFFECT_SPD_MINUS_1: + case MOVE_EFFECT_SP_ATK_MINUS_1: + case MOVE_EFFECT_SP_DEF_MINUS_1: + case MOVE_EFFECT_ACC_MINUS_1: + case MOVE_EFFECT_EVS_MINUS_1: + if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(1) | STAT_BUFF_NEGATIVE, + gBattleCommunication[MOVE_EFFECT_BYTE] - MOVE_EFFECT_ATK_MINUS_1 + 1, + affectsUser, 0)) { gBattlescriptCurrInstr++; } else { - gBattleScripting.animArg1 = gBattleCommunication[MOVE_EFFECT_BYTE] & 0x3F; + gBattleScripting.animArg1 = gBattleCommunication[MOVE_EFFECT_BYTE] & ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); gBattleScripting.animArg2 = 0; - b_movescr_stack_push(gBattlescriptCurrInstr + 1); + BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_StatDown; } break; - case 39 ... 45: // stat + 2 - if (ChangeStatBuffs(0x20, gBattleCommunication[MOVE_EFFECT_BYTE] + 0xDA, affectsUser, 0)) + case MOVE_EFFECT_ATK_PLUS_2: + case MOVE_EFFECT_DEF_PLUS_2: + case MOVE_EFFECT_SPD_PLUS_2: + case MOVE_EFFECT_SP_ATK_PLUS_2: + case MOVE_EFFECT_SP_DEF_PLUS_2: + case MOVE_EFFECT_ACC_PLUS_2: + case MOVE_EFFECT_EVS_PLUS_2: + if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(2), + gBattleCommunication[MOVE_EFFECT_BYTE] - MOVE_EFFECT_ATK_PLUS_2 + 1, + affectsUser, 0)) { gBattlescriptCurrInstr++; } else { - gBattleScripting.animArg1 = gBattleCommunication[MOVE_EFFECT_BYTE] & 0x3F; + gBattleScripting.animArg1 = gBattleCommunication[MOVE_EFFECT_BYTE] & ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); gBattleScripting.animArg2 = 0; - b_movescr_stack_push(gBattlescriptCurrInstr + 1); + BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_StatUp; } break; - case 46 ... 52: // stat - 2 - if (ChangeStatBuffs(~(0x5f), gBattleCommunication[MOVE_EFFECT_BYTE] + 0xD3, affectsUser, 0)) + case MOVE_EFFECT_ATK_MINUS_2: + case MOVE_EFFECT_DEF_MINUS_2: + case MOVE_EFFECT_SPD_MINUS_2: + case MOVE_EFFECT_SP_ATK_MINUS_2: + case MOVE_EFFECT_SP_DEF_MINUS_2: + case MOVE_EFFECT_ACC_MINUS_2: + case MOVE_EFFECT_EVS_MINUS_2: + if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(2) | STAT_BUFF_NEGATIVE, + gBattleCommunication[MOVE_EFFECT_BYTE] - MOVE_EFFECT_ATK_MINUS_2 + 1, + affectsUser, 0)) { gBattlescriptCurrInstr++; } else { - gBattleScripting.animArg1 = gBattleCommunication[MOVE_EFFECT_BYTE] & 0x3F; + gBattleScripting.animArg1 = gBattleCommunication[MOVE_EFFECT_BYTE] & ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); gBattleScripting.animArg2 = 0; - b_movescr_stack_push(gBattlescriptCurrInstr + 1); + BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_StatDown; } break; @@ -2544,9 +2586,8 @@ void SetMoveEffect(bool8 primary, u8 certain) | BATTLE_TYPE_SECRET_BASE))) { gBattlescriptCurrInstr++; - break; } - if (!(gBattleTypeFlags & + else if (!(gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_FRONTIER | BATTLE_TYPE_LINK @@ -2555,57 +2596,51 @@ void SetMoveEffect(bool8 primary, u8 certain) && (gWishFutureKnock.knockedOffPokes[side] & gBitTable[gBattlePartyID[gBankAttacker]])) { gBattlescriptCurrInstr++; - break; } - if (gBattleMons[gBankTarget].item + else if (gBattleMons[gBankTarget].item && gBattleMons[gBankTarget].ability == ABILITY_STICKY_HOLD) { - b_movescr_stack_push_cursor(); + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_NoItemSteal; gLastUsedAbility = gBattleMons[gBankTarget].ability; RecordAbilityBattle(gBankTarget, gLastUsedAbility); - - break; - } - if (gBattleMons[gBankAttacker].item) - { - gBattlescriptCurrInstr++; - break; - } - if (gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY) - { - gBattlescriptCurrInstr++; - break; } - if (gBattleMons[gBankTarget].item > 0x78 - && gBattleMons[gBankTarget].item < (0x79 + 12)) + else if (gBattleMons[gBankAttacker].item + || gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY + || (gBattleMons[gBankTarget].item > 0x78 && gBattleMons[gBankTarget].item < 0x85) + || gBattleMons[gBankTarget].item == 0) { gBattlescriptCurrInstr++; - break; } - if (gBattleMons[gBankTarget].item == 0) + else { - gBattlescriptCurrInstr++; - break; - } + // This is a leftover from R/S direct use of ewram addresses + void** memes1 = (void**)(&gBattleStruct); + void* memes2 = (void*)((u32)(gBankAttacker * 2 + offsetof(struct BattleStruct, field_D0))); + u16* memes3 = (u16*)(((void*)(*memes1) + (u32)(memes2))); + gLastUsedItem = *memes3 = gBattleMons[gBankTarget].item; - *(u16*)((u8*)((gBattleStruct->field_D0) + gBankAttacker * 2)) = gLastUsedItem = gBattleMons[gBankTarget].item; - gBattleMons[gBankTarget].item = 0; + // A sane representation of this would simply be: + // gLastUsedItem = gBattleStruct->field_D0[gBankAttacker] = gBattleMons[gBankTarget].item; - gActiveBank = gBankAttacker; - EmitSetAttributes(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gLastUsedItem); - MarkBufferBankForExecution(gBankAttacker); + gBattleMons[gBankTarget].item = 0; - gActiveBank = gBankTarget; - EmitSetAttributes(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gBankTarget].item); - MarkBufferBankForExecution(gBankTarget); + gActiveBank = gBankAttacker; + EmitSetAttributes(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gLastUsedItem); + MarkBufferBankForExecution(gBankAttacker); - b_movescr_stack_push(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_ItemSteal; + gActiveBank = gBankTarget; + EmitSetAttributes(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gBankTarget].item); + MarkBufferBankForExecution(gBankTarget); + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_ItemSteal; + + *(u8*)((u8*)(&gBattleStruct->choicedMove[gBankTarget]) + 0) = 0; + *(u8*)((u8*)(&gBattleStruct->choicedMove[gBankTarget]) + 1) = 0; + } - *(u8*)((u8*)(&gBattleStruct->choicedMove[gBankTarget]) + 0) = 0; - *(u8*)((u8*)(&gBattleStruct->choicedMove[gBankTarget]) + 1) = 0; } break; case MOVE_EFFECT_PREVENT_ESCAPE: @@ -2618,11 +2653,11 @@ void SetMoveEffect(bool8 primary, u8 certain) gBattlescriptCurrInstr++; break; case MOVE_EFFECT_ALL_STATS_UP: - b_movescr_stack_push(gBattlescriptCurrInstr + 1); + BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_AllStatsUp; break; case MOVE_EFFECT_RAPIDSPIN: - b_movescr_stack_push(gBattlescriptCurrInstr + 1); + BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_RapidSpinAway; break; case MOVE_EFFECT_REMOVE_PARALYSIS: // Smelling salts @@ -2635,15 +2670,15 @@ void SetMoveEffect(bool8 primary, u8 certain) gBattleMons[gBankTarget].status1 &= ~(STATUS_PARALYSIS); gActiveBank = gBankTarget; - EmitSetAttributes(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gBankTarget].status1); + EmitSetAttributes(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); MarkBufferBankForExecution(gActiveBank); - b_movescr_stack_push(gBattlescriptCurrInstr + 1); + BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_TargetPRLZHeal; } break; case MOVE_EFFECT_ATK_DEF_DOWN: // SuperPower - b_movescr_stack_push(gBattlescriptCurrInstr + 1); + BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_AtkDefDown; break; case MOVE_EFFECT_RECOIL_33_PARALYSIS: // Volt Tackle @@ -2651,7 +2686,7 @@ void SetMoveEffect(bool8 primary, u8 certain) if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; - b_movescr_stack_push(gBattlescriptCurrInstr + 1); + BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = gMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; break; case MOVE_EFFECT_THRASH: @@ -2676,16 +2711,12 @@ void SetMoveEffect(bool8 primary, u8 certain) else { gLastUsedAbility = ABILITY_STICKY_HOLD; - gBattlescriptCurrInstr = BattleScript_NoItemSteal; + gBattlescriptCurrInstr = BattleScript_StickyHoldOnKnockOff; RecordAbilityBattle(gEffectBank, ABILITY_STICKY_HOLD); } break; } - if (gBattleMons[gEffectBank].item == 0) - { - gBattlescriptCurrInstr++; - } - else + if (gBattleMons[gEffectBank].item) { side = GetBankSide(gEffectBank); @@ -2693,18 +2724,19 @@ void SetMoveEffect(bool8 primary, u8 certain) gBattleMons[gEffectBank].item = 0; gWishFutureKnock.knockedOffPokes[side] |= gBitTable[gBattlePartyID[gEffectBank]]; - b_movescr_stack_push(gBattlescriptCurrInstr + 1); + BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_KnockedOff; *(u8*)((u8*)(&gBattleStruct->choicedMove[gEffectBank]) + 0) = 0; *(u8*)((u8*)(&gBattleStruct->choicedMove[gEffectBank]) + 1) = 0; } - break; - default: - gBattlescriptCurrInstr++; + else + { + gBattlescriptCurrInstr++; + } break; case MOVE_EFFECT_SP_ATK_TWO_DOWN: // Overheat - b_movescr_stack_push(gBattlescriptCurrInstr + 1); + BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_SAtkDown2; break; } @@ -2713,3 +2745,1615 @@ void SetMoveEffect(bool8 primary, u8 certain) gBattleCommunication[MOVE_EFFECT_BYTE] = 0; } + +void atk15_seteffectwithchancetarget(void) +{ + u32 percentChance; + + if (gBattleMons[gBankAttacker].ability == ABILITY_SERENE_GRACE) + percentChance = gBattleMoves[gCurrentMove].secondaryEffectChance * 2; + else + percentChance = gBattleMoves[gCurrentMove].secondaryEffectChance; + + if (gBattleCommunication[MOVE_EFFECT_BYTE] & MOVE_EFFECT_CERTAIN + && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + gBattleCommunication[MOVE_EFFECT_BYTE] &= ~(MOVE_EFFECT_CERTAIN); + SetMoveEffect(0, MOVE_EFFECT_CERTAIN); + } + else if (Random() % 100 < percentChance + && gBattleCommunication[MOVE_EFFECT_BYTE] + && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + if (percentChance >= 100) + SetMoveEffect(0, MOVE_EFFECT_CERTAIN); + else + SetMoveEffect(0, 0); + } + else + { + gBattlescriptCurrInstr++; + } + + gBattleCommunication[MOVE_EFFECT_BYTE] = 0; + gBattleScripting.field_16 = 0; +} + +void atk16_seteffectprimary(void) +{ + SetMoveEffect(TRUE, 0); +} + +void atk17_seteffectsecondary(void) +{ + SetMoveEffect(FALSE, 0); +} + +void atk18_status_effect_clear(void) +{ + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + + if (gBattleCommunication[MOVE_EFFECT_BYTE] <= MOVE_EFFECT_TOXIC) + gBattleMons[gActiveBank].status1 &= (~gStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]); + else + gBattleMons[gActiveBank].status2 &= (~gStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]); + + gBattleCommunication[MOVE_EFFECT_BYTE] = 0; + gBattlescriptCurrInstr += 2; + gBattleScripting.field_16 = 0; +} + +void atk19_faint_pokemon(void) +{ + const u8 *BS_ptr; + + if (gBattlescriptCurrInstr[2] != 0) + { + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + if (gHitMarker & HITMARKER_FAINTED(gActiveBank)) + { + BS_ptr = BSScriptReadPtr(gBattlescriptCurrInstr + 3); + + BattleScriptPop(); + gBattlescriptCurrInstr = BS_ptr; + gSideAffecting[GetBankSide(gActiveBank)] &= ~(SIDE_STATUS_SPIKES_DAMAGED); + } + else + { + gBattlescriptCurrInstr += 7; + } + } + else + { + u8 bank; + + if (gBattlescriptCurrInstr[1] == BS_GET_ATTACKER) + { + gActiveBank = gBankAttacker; + bank = gBankTarget; + BS_ptr = BattleScript_FaintAttacker; + } + else + { + gActiveBank = gBankTarget; + bank = gBankAttacker; + BS_ptr = BattleScript_FaintTarget; + } + if (!(gAbsentBankFlags & gBitTable[gActiveBank]) + && gBattleMons[gActiveBank].hp == 0) + { + gHitMarker |= HITMARKER_FAINTED(gActiveBank); + BattleScriptPush(gBattlescriptCurrInstr + 7); + gBattlescriptCurrInstr = BS_ptr; + if (GetBankSide(gActiveBank) == SIDE_PLAYER) + { + gHitMarker |= HITMARKER_x400000; + if (gBattleResults.playerFaintCounter < 0xFF) + gBattleResults.playerFaintCounter++; + AdjustFriendshipOnBattleFaint(gActiveBank); + } + else + { + if (gBattleResults.opponentFaintCounter < 0xFF) + gBattleResults.opponentFaintCounter++; + gBattleResults.lastOpponentSpecies = GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES, NULL); + } + if ((gHitMarker & HITMARKER_DESTINYBOND) && gBattleMons[gBankAttacker].hp != 0) + { + gHitMarker &= ~(HITMARKER_DESTINYBOND); + BattleScriptPush(gBattlescriptCurrInstr); + gBattleMoveDamage = gBattleMons[bank].hp; + gBattlescriptCurrInstr = BattleScript_DestinyBondTakesLife; + } + if ((gStatuses3[gBankTarget] & STATUS3_GRUDGE) + && !(gHitMarker & HITMARKER_GRUDGE) + && GetBankSide(gBankAttacker) != GetBankSide(gBankTarget) + && gBattleMons[gBankAttacker].hp != 0 + && gCurrentMove != MOVE_STRUGGLE) + { + u8 moveIndex = *(gBattleStruct->chosenMovesIds + gBankAttacker); + + gBattleMons[gBankAttacker].pp[moveIndex] = 0; + BattleScriptPush(gBattlescriptCurrInstr); + gBattlescriptCurrInstr = BattleScript_GrudgeTakesPp; + gActiveBank = gBankAttacker; + EmitSetAttributes(0, moveIndex + REQUEST_PPMOVE1_BATTLE, 0, 1, &gBattleMons[gActiveBank].pp[moveIndex]); + MarkBufferBankForExecution(gActiveBank); + + gBattleTextBuff1[0] = PLACEHOLDER_BEGIN; + gBattleTextBuff1[1] = 2; + gBattleTextBuff1[2] = gBattleMons[gBankAttacker].moves[moveIndex]; + gBattleTextBuff1[3] = gBattleMons[gBankAttacker].moves[moveIndex] >> 8; + gBattleTextBuff1[4] = EOS; + } + } + else + { + gBattlescriptCurrInstr += 7; + } + } +} + +void atk1A_faint_animation(void) +{ + if (gBattleExecBuffer == 0) + { + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + EmitFaintAnimation(0); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 2; + } +} + +void atk1B_faint_effects_clear(void) +{ + if (gBattleExecBuffer == 0) + { + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + + if (!(gBattleTypeFlags & BATTLE_TYPE_ARENA) || gBattleMons[gActiveBank].hp == 0) + { + gBattleMons[gActiveBank].status1 = 0; + EmitSetAttributes(0, REQUEST_STATUS_BATTLE, 0, 0x4, &gBattleMons[gActiveBank].status1); + MarkBufferBankForExecution(gActiveBank); + } + + UndoEffectsAfterFainting(); // Effects like attractions, trapping, etc. + gBattlescriptCurrInstr += 2; + } +} + +void atk1C_jumpifstatus(void) +{ + u8 bank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + u32 flags = BS2ScriptRead32(gBattlescriptCurrInstr + 2); + const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 6); + + if (gBattleMons[bank].status1 & flags && gBattleMons[bank].hp) + gBattlescriptCurrInstr = jumpPtr; + else + gBattlescriptCurrInstr += 10; +} + +void atk1D_jumpifstatus2(void) +{ + u8 bank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + u32 flags = BS2ScriptRead32(gBattlescriptCurrInstr + 2); + const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 6); + + if (gBattleMons[bank].status2 & flags && gBattleMons[bank].hp) + gBattlescriptCurrInstr = jumpPtr; + else + gBattlescriptCurrInstr += 10; +} + +void atk1E_jumpifability(void) +{ + u8 bank; + u8 ability = BSScriptRead8(gBattlescriptCurrInstr + 2); + const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 3); + + if (BSScriptRead8(gBattlescriptCurrInstr + 1) == BS_GET_ATTACKER_SIDE) + { + bank = AbilityBattleEffects(ABILITYEFFECT_CHECK_BANK_SIDE, gBankAttacker, ability, 0, 0); + if (bank) + { + gLastUsedAbility = ability; + gBattlescriptCurrInstr = jumpPtr; + RecordAbilityBattle(bank - 1, gLastUsedAbility); + gBattleScripting.field_15 = bank - 1; + } + else + gBattlescriptCurrInstr += 7; + } + else if (BSScriptRead8(gBattlescriptCurrInstr + 1) == BS_GET_NOT_ATTACKER_SIDE) + { + bank = AbilityBattleEffects(ABILITYEFFECT_CHECK_OTHER_SIDE, gBankAttacker, ability, 0, 0); + if (bank) + { + gLastUsedAbility = ability; + gBattlescriptCurrInstr = jumpPtr; + RecordAbilityBattle(bank - 1, gLastUsedAbility); + gBattleScripting.field_15 = bank - 1; + } + else + gBattlescriptCurrInstr += 7; + } + else + { + bank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + if (gBattleMons[bank].ability == ability) + { + gLastUsedAbility = ability; + gBattlescriptCurrInstr = jumpPtr; + RecordAbilityBattle(bank, gLastUsedAbility); + gBattleScripting.field_15 = bank; + } + else + gBattlescriptCurrInstr += 7; + } +} + +void atk1F_jumpifsideaffecting(void) +{ + u8 side; + u16 flags; + const u8* jumpPtr; + + if (BSScriptRead8(gBattlescriptCurrInstr + 1) == BS_GET_ATTACKER) + side = GET_BANK_SIDE(gBankAttacker); + else + side = GET_BANK_SIDE(gBankTarget); + + flags = BS2ScriptRead16(gBattlescriptCurrInstr + 2); + jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 4); + + if (gSideAffecting[side] & flags) + gBattlescriptCurrInstr = jumpPtr; + else + gBattlescriptCurrInstr += 8; +} + +void atk20_jumpifstat(void) +{ + u8 ret = 0; + u8 bank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + u8 value = gBattleMons[bank].statStages[BSScriptRead8(gBattlescriptCurrInstr + 3)]; + + switch (BSScriptRead8(gBattlescriptCurrInstr + 2)) + { + case CMP_EQUAL: + if (value == BSScriptRead8(gBattlescriptCurrInstr + 4)) + ret++; + break; + case CMP_NOT_EQUAL: + if (value != BSScriptRead8(gBattlescriptCurrInstr + 4)) + ret++; + break; + case CMP_GREATER_THAN: + if (value > BSScriptRead8(gBattlescriptCurrInstr + 4)) + ret++; + break; + case CMP_LESS_THAN: + if (value < BSScriptRead8(gBattlescriptCurrInstr + 4)) + ret++; + break; + case CMP_COMMON_BITS: + if (value & BSScriptRead8(gBattlescriptCurrInstr + 4)) + ret++; + break; + case CMP_NO_COMMON_BITS: + if (!(value & BSScriptRead8(gBattlescriptCurrInstr + 4))) + ret++; + break; + } + + if (ret) + gBattlescriptCurrInstr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5); + else + gBattlescriptCurrInstr += 9; +} + +void atk21_jumpifstatus3(void) +{ + u32 flags; + const u8* jumpPtr; + + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + flags = BS2ScriptRead32(gBattlescriptCurrInstr + 2); + jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 7); + + if (BSScriptRead8(gBattlescriptCurrInstr + 6)) + { + if ((gStatuses3[gActiveBank] & flags) != 0) + gBattlescriptCurrInstr += 11; + else + gBattlescriptCurrInstr = jumpPtr; + } + else + { + if ((gStatuses3[gActiveBank] & flags) != 0) + gBattlescriptCurrInstr = jumpPtr; + else + gBattlescriptCurrInstr += 11; + } +} + +void atk22_jumpiftype(void) +{ + u8 bank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + u8 type = BSScriptRead8(gBattlescriptCurrInstr + 2); + const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 3); + + if (gBattleMons[bank].type1 == type || gBattleMons[bank].type2 == type) + gBattlescriptCurrInstr = jumpPtr; + else + gBattlescriptCurrInstr += 7; +} + +void atk23_getexp(void) +{ + u16 item; + s32 i; // also used as stringId + u8 holdEffect; + s32 sentIn; + + s32 viaExpShare = 0; + u16* exp = &gBattleStruct->expValue; + + gBank1 = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + sentIn = gSentPokesToOpponent[(gBank1 & 2) >> 1]; + + switch (gBattleScripting.atk23_state) + { + case 0: // check if should receive exp at all + if (GetBankSide(gBank1) != SIDE_OPPONENT || (gBattleTypeFlags & + (BATTLE_TYPE_LINK + | BATTLE_TYPE_x2000000 + | BATTLE_TYPE_x4000000 + | BATTLE_TYPE_FRONTIER + | BATTLE_TYPE_SAFARI + | BATTLE_TYPE_BATTLE_TOWER + | BATTLE_TYPE_EREADER_TRAINER))) + { + gBattleScripting.atk23_state = 6; // goto last case + } + else + { + gBattleScripting.atk23_state++; + gBattleStruct->field_DF |= gBitTable[gBattlePartyID[gBank1]]; + } + break; + case 1: // calculate experience points to redistribute + { + u16 calculatedExp; + s32 viaSentIn; + + for (viaSentIn = 0, i = 0; i < 6; i++) + { + if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) == SPECIES_NONE || GetMonData(&gPlayerParty[i], MON_DATA_HP) == 0) + continue; + if (gBitTable[i] & sentIn) + viaSentIn++; + + item = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM); + + if (item == ITEM_ENIGMA_BERRY) + holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect; + else + holdEffect = ItemId_GetHoldEffect(item); + + if (holdEffect == HOLD_EFFECT_EXP_SHARE) + viaExpShare++; + } + + calculatedExp = gBaseStats[gBattleMons[gBank1].species].expYield * gBattleMons[gBank1].level / 7; + + if (viaExpShare) // at least one mon is getting exp via exp share + { + *exp = calculatedExp / 2 / viaSentIn; + if (*exp == 0) + *exp = 1; + + gExpShareExp = calculatedExp / 2 / viaExpShare; + if (gExpShareExp == 0) + gExpShareExp = 1; + } + else + { + *exp = calculatedExp / viaSentIn; + if (*exp == 0) + *exp = 1; + gExpShareExp = 0; + } + + gBattleScripting.atk23_state++; + gBattleStruct->expGetterId = 0; + gBattleStruct->sentInPokes = sentIn; + } + // fall through + case 2: // set exp value to the poke in expgetter_id and print message + if (gBattleExecBuffer == 0) + { + item = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_HELD_ITEM); + + if (item == ITEM_ENIGMA_BERRY) + holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect; + else + holdEffect = ItemId_GetHoldEffect(item); + + if (holdEffect != HOLD_EFFECT_EXP_SHARE && !(gBattleStruct->sentInPokes & 1)) + { + *(&gBattleStruct->sentInPokes) >>= 1; + gBattleScripting.atk23_state = 5; + gBattleMoveDamage = 0; // used for exp + } + else if (GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL) == MAX_MON_LEVEL) + { + *(&gBattleStruct->sentInPokes) >>= 1; + gBattleScripting.atk23_state = 5; + gBattleMoveDamage = 0; // used for exp + } + else + { + // music change in wild battle after fainting a poke + if (!(gBattleTypeFlags & BATTLE_TYPE_TRAINER) && gBattleMons[0].hp && !gBattleStruct->wildVictorySong) + { + BattleMusicStop(); + PlayBGM(0x161); + gBattleStruct->wildVictorySong++; + } + + if (GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_HP)) + { + if (gBattleStruct->sentInPokes & 1) + gBattleMoveDamage = *exp; + else + gBattleMoveDamage = 0; + + if (holdEffect == HOLD_EFFECT_EXP_SHARE) + gBattleMoveDamage += gExpShareExp; + if (holdEffect == HOLD_EFFECT_LUCKY_EGG) + gBattleMoveDamage = (gBattleMoveDamage * 150) / 100; + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + gBattleMoveDamage = (gBattleMoveDamage * 150) / 100; + + if (IsTradedMon(&gPlayerParty[gBattleStruct->expGetterId])) + { + // check if the pokemon doesn't belong to the player + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gBattleStruct->expGetterId >= 3) + { + i = 0x149; + } + else + { + gBattleMoveDamage = (gBattleMoveDamage * 150) / 100; + i = 0x14A; + } + } + else + { + i = 0x149; + } + + // get exp getter bank + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + if (!(gBattlePartyID[2] != gBattleStruct->expGetterId) && !(gAbsentBankFlags & gBitTable[2])) + gBattleStruct->expGetterBank = 2; + else + { + if (!(gAbsentBankFlags & gBitTable[0])) + gBattleStruct->expGetterBank = 0; + else + gBattleStruct->expGetterBank = 2; + } + } + else + gBattleStruct->expGetterBank = 0; + + // buffer poke name + gBattleTextBuff1[0] = PLACEHOLDER_BEGIN; + gBattleTextBuff1[1] = 4; + gBattleTextBuff1[2] = gBattleStruct->expGetterBank; + gBattleTextBuff1[3] = gBattleStruct->expGetterId; + gBattleTextBuff1[4] = EOS; + + // buffer 'gained' or 'gained a boosted' + gBattleTextBuff2[0] = PLACEHOLDER_BEGIN; + gBattleTextBuff2[1] = 0; + gBattleTextBuff2[2] = i; + gBattleTextBuff2[3] = (i & 0xFF00) >> 8; + gBattleTextBuff2[4] = EOS; + + // buffer exp number + gBattleTextBuff3[0] = PLACEHOLDER_BEGIN; + gBattleTextBuff3[1] = 1; + gBattleTextBuff3[2] = 4; // word + gBattleTextBuff3[3] = 5; // max digits + gBattleTextBuff3[4] = gBattleMoveDamage; + gBattleTextBuff3[5] = (gBattleMoveDamage & 0x0000FF00) >> 8; + gBattleTextBuff3[6] = (gBattleMoveDamage & 0x00FF0000) >> 16; + gBattleTextBuff3[7] = (gBattleMoveDamage & 0xFF000000) >> 24; + gBattleTextBuff3[8] = EOS; + + PrepareStringBattle(0xD, gBattleStruct->expGetterBank); + MonGainEVs(&gPlayerParty[gBattleStruct->expGetterId], gBattleMons[gBank1].species); + } + gBattleStruct->sentInPokes >>= 1; + gBattleScripting.atk23_state++; + } + } + break; + case 3: // Set stats and give exp + if (gBattleExecBuffer == 0) + { + gBattleBufferB[gBattleStruct->expGetterBank][0] = 0; + if (GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_HP) && GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL) != MAX_MON_LEVEL) + { + BATTLE_LVLUP_STATS->hp = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_MAX_HP); + BATTLE_LVLUP_STATS->atk = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_ATK); + BATTLE_LVLUP_STATS->def = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_DEF); + BATTLE_LVLUP_STATS->spd = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPD); + BATTLE_LVLUP_STATS->spAtk = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPATK); + BATTLE_LVLUP_STATS->spDef = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPDEF); + + gActiveBank = gBattleStruct->expGetterBank; + EmitExpUpdate(0, gBattleStruct->expGetterId, gBattleMoveDamage); + MarkBufferBankForExecution(gActiveBank); + } + gBattleScripting.atk23_state++; + } + break; + case 4: // lvl up if necessary + if (gBattleExecBuffer == 0) + { + gActiveBank = gBattleStruct->expGetterBank; + if (gBattleBufferB[gActiveBank][0] == 0x21 && gBattleBufferB[gActiveBank][1] == 0xB) + { + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && gBattlePartyID[gActiveBank] == gBattleStruct->expGetterId) + sub_805E990(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank); + + // buff poke name + gBattleTextBuff1[0] = PLACEHOLDER_BEGIN; + gBattleTextBuff1[1] = 4; + gBattleTextBuff1[2] = gActiveBank; + gBattleTextBuff1[3] = gBattleStruct->expGetterId; + gBattleTextBuff1[4] = EOS; + + // buff level + gBattleTextBuff2[0] = PLACEHOLDER_BEGIN; + gBattleTextBuff2[1] = 1; + gBattleTextBuff2[2] = 1; + gBattleTextBuff2[3] = 3; + gBattleTextBuff2[4] = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL); + gBattleTextBuff2[5] = EOS; + + BattleScriptPushCursor(); + gLeveledUpInBattle |= gBitTable[gBattleStruct->expGetterId]; + gBattlescriptCurrInstr = BattleScript_LevelUp; + gBattleMoveDamage = (gBattleBufferB[gActiveBank][2] | (gBattleBufferB[gActiveBank][3] << 8)); + AdjustFriendship(&gPlayerParty[gBattleStruct->expGetterId], 0); + + // update battle mon structure after level up + if (gBattlePartyID[0] == gBattleStruct->expGetterId && gBattleMons[0].hp) + { + gBattleMons[0].level = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL); + gBattleMons[0].hp = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_HP); + gBattleMons[0].maxHP = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_MAX_HP); + gBattleMons[0].attack = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_ATK); + gBattleMons[0].defense = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_DEF); + // Why is this duplicated? + gBattleMons[0].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPD); + gBattleMons[0].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPD); + + gBattleMons[0].spAttack = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPATK); + gBattleMons[0].spDefense = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPDEF); + } + // What is else if? + if (gBattlePartyID[2] == gBattleStruct->expGetterId && gBattleMons[2].hp && (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + { + gBattleMons[2].level = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL); + gBattleMons[2].hp = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_HP); + gBattleMons[2].maxHP = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_MAX_HP); + gBattleMons[2].attack = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_ATK); + gBattleMons[2].defense = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_DEF); + // Duplicated again, but this time there's no Sp Defense + gBattleMons[2].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPD); + gBattleMons[2].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPD); + + gBattleMons[2].spAttack = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPATK); + } + gBattleScripting.atk23_state = 5; + } + else + { + gBattleMoveDamage = 0; + gBattleScripting.atk23_state = 5; + } + } + break; + case 5: // looper increment + if (gBattleMoveDamage) // there is exp to give, goto case 3 that gives exp + gBattleScripting.atk23_state = 3; + else + { + gBattleStruct->expGetterId++; + if (gBattleStruct->expGetterId <= 5) + gBattleScripting.atk23_state = 2; // loop again + else + gBattleScripting.atk23_state = 6; // we're done + } + break; + case 6: // increment instruction + if (gBattleExecBuffer == 0) + { + // not sure why gf clears the item and ability here + gBattleMons[gBank1].item = 0; + gBattleMons[gBank1].ability = 0; + gBattlescriptCurrInstr += 2; + } + break; + } +} + +#ifdef NONMATCHING +void atk24(void) +{ + u16 HP_count = 0; + s32 i; + + if (gBattleExecBuffer) + return; + + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gPartnerTrainerId == STEVEN_PARTNER_ID) + { + for (i = 0; i < 3; i++) + { + if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) && !GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG)) + HP_count += GetMonData(&gPlayerParty[i], MON_DATA_HP); + } + } + else + { + for (i = 0; i < 6; i++) + { + if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) && !GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG) + && (!(gBattleTypeFlags & BATTLE_TYPE_ARENA) || !(gBattleStruct->field_2A0 & gBitTable[i]))) + { + HP_count += GetMonData(&gPlayerParty[i], MON_DATA_HP); + } + } + } + + if (HP_count == 0) + gBattleOutcome |= BATTLE_LOST; + + for (HP_count = 0, i = 0; i < 6; i++) + { + if (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES) && !GetMonData(&gEnemyParty[i], MON_DATA_IS_EGG) + && (!(gBattleTypeFlags & BATTLE_TYPE_ARENA) || !(gBattleStruct->field_2A1 & gBitTable[i]))) + { + HP_count += GetMonData(&gEnemyParty[i], MON_DATA_HP); + } + } + + if (HP_count == 0) + gBattleOutcome |= BATTLE_WON; + + if (gBattleOutcome == 0 && (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000))) + { + s32 foundPlayer; + s32 foundOpponent; + + // Impossible to decompile loops. + for (foundPlayer = 0, i = 0; i < gNoOfAllBanks; i += 2) + { + if (HITMARKER_UNK(i) & gHitMarker && !gSpecialStatuses[i].flag40) + foundPlayer++; + } + + for (foundOpponent = 0, i = 1; i < gNoOfAllBanks; i += 2) + { + if (HITMARKER_UNK(i) & gHitMarker && !gSpecialStatuses[i].flag40) + foundOpponent++; + } + + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + if (foundOpponent + foundPlayer > 1) + gBattlescriptCurrInstr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + else + gBattlescriptCurrInstr += 5; + } + else + { + if (foundOpponent != 0 && foundPlayer != 0) + gBattlescriptCurrInstr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + else + gBattlescriptCurrInstr += 5; + } + } + else + { + gBattlescriptCurrInstr += 5; + } +} +#else +__attribute__((naked)) +void atk24(void) +{ + asm("\n\ + .syntax unified\n\ + push {r4-r7,lr}\n\ + mov r7, r8\n\ + push {r7}\n\ + movs r6, 0\n\ + ldr r0, =gBattleExecBuffer\n\ + ldr r0, [r0]\n\ + cmp r0, 0\n\ + beq _0804ACE2\n\ + b _0804AF22\n\ + _0804ACE2:\n\ + ldr r0, =gBattleTypeFlags\n\ + ldr r0, [r0]\n\ + movs r1, 0x80\n\ + lsls r1, 15\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _0804AD48\n\ + ldr r0, =gPartnerTrainerId\n\ + ldrh r1, [r0]\n\ + ldr r0, =0x00000c03\n\ + cmp r1, r0\n\ + bne _0804AD48\n\ + movs r5, 0\n\ + _0804ACFC:\n\ + movs r0, 0x64\n\ + adds r1, r5, 0\n\ + muls r1, r0\n\ + ldr r0, =gPlayerParty\n\ + adds r4, r1, r0\n\ + adds r0, r4, 0\n\ + movs r1, 0xB\n\ + bl GetMonData\n\ + cmp r0, 0\n\ + beq _0804AD2C\n\ + adds r0, r4, 0\n\ + movs r1, 0x2D\n\ + bl GetMonData\n\ + cmp r0, 0\n\ + bne _0804AD2C\n\ + adds r0, r4, 0\n\ + movs r1, 0x39\n\ + bl GetMonData\n\ + adds r0, r6, r0\n\ + lsls r0, 16\n\ + lsrs r6, r0, 16\n\ + _0804AD2C:\n\ + adds r5, 0x1\n\ + cmp r5, 0x2\n\ + ble _0804ACFC\n\ + b _0804ADA8\n\ + .pool\n\ + _0804AD48:\n\ + movs r5, 0\n\ + _0804AD4A:\n\ + movs r0, 0x64\n\ + adds r1, r5, 0\n\ + muls r1, r0\n\ + ldr r0, =gPlayerParty\n\ + adds r4, r1, r0\n\ + adds r0, r4, 0\n\ + movs r1, 0xB\n\ + bl GetMonData\n\ + cmp r0, 0\n\ + beq _0804ADA2\n\ + adds r0, r4, 0\n\ + movs r1, 0x2D\n\ + bl GetMonData\n\ + cmp r0, 0\n\ + bne _0804ADA2\n\ + ldr r0, =gBattleTypeFlags\n\ + ldr r0, [r0]\n\ + movs r1, 0x80\n\ + lsls r1, 11\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _0804AD94\n\ + ldr r0, =gBattleStruct\n\ + ldr r0, [r0]\n\ + movs r1, 0xA8\n\ + lsls r1, 2\n\ + adds r0, r1\n\ + ldrb r1, [r0]\n\ + ldr r2, =gBitTable\n\ + lsls r0, r5, 2\n\ + adds r0, r2\n\ + ldr r0, [r0]\n\ + ands r1, r0\n\ + cmp r1, 0\n\ + bne _0804ADA2\n\ + _0804AD94:\n\ + adds r0, r4, 0\n\ + movs r1, 0x39\n\ + bl GetMonData\n\ + adds r0, r6, r0\n\ + lsls r0, 16\n\ + lsrs r6, r0, 16\n\ + _0804ADA2:\n\ + adds r5, 0x1\n\ + cmp r5, 0x5\n\ + ble _0804AD4A\n\ + _0804ADA8:\n\ + cmp r6, 0\n\ + bne _0804ADB6\n\ + ldr r0, =gBattleOutcome\n\ + ldrb r1, [r0]\n\ + movs r2, 0x2\n\ + orrs r1, r2\n\ + strb r1, [r0]\n\ + _0804ADB6:\n\ + movs r6, 0\n\ + movs r5, 0\n\ + _0804ADBA:\n\ + movs r0, 0x64\n\ + adds r1, r5, 0\n\ + muls r1, r0\n\ + ldr r0, =gEnemyParty\n\ + adds r4, r1, r0\n\ + adds r0, r4, 0\n\ + movs r1, 0xB\n\ + bl GetMonData\n\ + cmp r0, 0\n\ + beq _0804AE10\n\ + adds r0, r4, 0\n\ + movs r1, 0x2D\n\ + bl GetMonData\n\ + cmp r0, 0\n\ + bne _0804AE10\n\ + ldr r0, =gBattleTypeFlags\n\ + ldr r0, [r0]\n\ + movs r1, 0x80\n\ + lsls r1, 11\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _0804AE02\n\ + ldr r0, =gBattleStruct\n\ + ldr r0, [r0]\n\ + ldr r1, =0x000002a1\n\ + adds r0, r1\n\ + ldrb r1, [r0]\n\ + ldr r2, =gBitTable\n\ + lsls r0, r5, 2\n\ + adds r0, r2\n\ + ldr r0, [r0]\n\ + ands r1, r0\n\ + cmp r1, 0\n\ + bne _0804AE10\n\ + _0804AE02:\n\ + adds r0, r4, 0\n\ + movs r1, 0x39\n\ + bl GetMonData\n\ + adds r0, r6, r0\n\ + lsls r0, 16\n\ + lsrs r6, r0, 16\n\ + _0804AE10:\n\ + adds r5, 0x1\n\ + cmp r5, 0x5\n\ + ble _0804ADBA\n\ + ldr r2, =gBattleOutcome\n\ + cmp r6, 0\n\ + bne _0804AE24\n\ + ldrb r0, [r2]\n\ + movs r1, 0x1\n\ + orrs r0, r1\n\ + strb r0, [r2]\n\ + _0804AE24:\n\ + ldrb r0, [r2]\n\ + cmp r0, 0\n\ + bne _0804AF1A\n\ + ldr r0, =gBattleTypeFlags\n\ + ldr r1, [r0]\n\ + ldr r2, =0x02000002\n\ + ands r1, r2\n\ + mov r8, r0\n\ + cmp r1, 0\n\ + beq _0804AF1A\n\ + movs r3, 0\n\ + movs r5, 0\n\ + ldr r0, =gNoOfAllBanks\n\ + ldrb r1, [r0]\n\ + mov r12, r0\n\ + ldr r7, =gBattlescriptCurrInstr\n\ + cmp r3, r1\n\ + bge _0804AE70\n\ + ldr r0, =gHitMarker\n\ + movs r6, 0x80\n\ + lsls r6, 21\n\ + ldr r4, [r0]\n\ + adds r2, r1, 0\n\ + ldr r1, =gSpecialStatuses\n\ + _0804AE54:\n\ + adds r0, r6, 0\n\ + lsls r0, r5\n\ + ands r0, r4\n\ + cmp r0, 0\n\ + beq _0804AE68\n\ + ldrb r0, [r1]\n\ + lsls r0, 25\n\ + cmp r0, 0\n\ + blt _0804AE68\n\ + adds r3, 0x1\n\ + _0804AE68:\n\ + adds r1, 0x28\n\ + adds r5, 0x2\n\ + cmp r5, r2\n\ + blt _0804AE54\n\ + _0804AE70:\n\ + movs r2, 0\n\ + movs r5, 0x1\n\ + mov r4, r12\n\ + ldrb r1, [r4]\n\ + cmp r5, r1\n\ + bge _0804AEAA\n\ + ldr r0, =gHitMarker\n\ + movs r4, 0x80\n\ + lsls r4, 21\n\ + mov r12, r4\n\ + ldr r6, [r0]\n\ + ldr r0, =gSpecialStatuses\n\ + adds r4, r1, 0\n\ + adds r1, r0, 0\n\ + adds r1, 0x14\n\ + _0804AE8E:\n\ + mov r0, r12\n\ + lsls r0, r5\n\ + ands r0, r6\n\ + cmp r0, 0\n\ + beq _0804AEA2\n\ + ldrb r0, [r1]\n\ + lsls r0, 25\n\ + cmp r0, 0\n\ + blt _0804AEA2\n\ + adds r2, 0x1\n\ + _0804AEA2:\n\ + adds r1, 0x28\n\ + adds r5, 0x2\n\ + cmp r5, r4\n\ + blt _0804AE8E\n\ + _0804AEAA:\n\ + mov r1, r8\n\ + ldr r0, [r1]\n\ + movs r1, 0x40\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _0804AEF0\n\ + adds r0, r2, r3\n\ + cmp r0, 0x1\n\ + bgt _0804AEF8\n\ + b _0804AF12\n\ + .pool\n\ + _0804AEF0:\n\ + cmp r2, 0\n\ + beq _0804AF12\n\ + cmp r3, 0\n\ + beq _0804AF12\n\ + _0804AEF8:\n\ + ldr r2, [r7]\n\ + ldrb r1, [r2, 0x1]\n\ + ldrb r0, [r2, 0x2]\n\ + lsls r0, 8\n\ + adds r1, r0\n\ + ldrb r0, [r2, 0x3]\n\ + lsls r0, 16\n\ + adds r1, r0\n\ + ldrb r0, [r2, 0x4]\n\ + lsls r0, 24\n\ + adds r1, r0\n\ + str r1, [r7]\n\ + b _0804AF22\n\ + _0804AF12:\n\ + ldr r0, [r7]\n\ + adds r0, 0x5\n\ + str r0, [r7]\n\ + b _0804AF22\n\ + _0804AF1A:\n\ + ldr r1, =gBattlescriptCurrInstr\n\ + ldr r0, [r1]\n\ + adds r0, 0x5\n\ + str r0, [r1]\n\ + _0804AF22:\n\ + pop {r3}\n\ + mov r8, r3\n\ + pop {r4-r7}\n\ + pop {r0}\n\ + bx r0\n\ + .pool\n\ + .syntax divided"); +} + +#endif // NONMATCHING + +void MoveValuesCleanUp(void) +{ + gBattleMoveFlags = 0; + gBattleScripting.dmgMultiplier = 1; + gCritMultiplier = 1; + gBattleCommunication[MOVE_EFFECT_BYTE] = 0; + gBattleCommunication[6] = 0; + gHitMarker &= ~(HITMARKER_DESTINYBOND); + gHitMarker &= ~(HITMARKER_SYNCHRONISE_EFFECT); +} + +void atk25_move_values_cleanup(void) +{ + MoveValuesCleanUp(); + gBattlescriptCurrInstr += 1; +} + +void atk26_set_multihit(void) +{ + gMultiHitCounter = BSScriptRead8(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr += 2; +} + +void atk27_decrement_multihit(void) +{ + if (--gMultiHitCounter == 0) + gBattlescriptCurrInstr += 5; + else + gBattlescriptCurrInstr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); +} + +void atk28_goto(void) +{ + gBattlescriptCurrInstr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); +} + +void atk29_jumpifbyte(void) +{ + u8 caseID = BSScriptRead8(gBattlescriptCurrInstr + 1); + const u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 2); + u8 value = BSScriptRead8(gBattlescriptCurrInstr + 6); + const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 7); + + gBattlescriptCurrInstr += 11; + + switch (caseID) + { + case CMP_EQUAL: + if (*memByte == value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_NOT_EQUAL: + if (*memByte != value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_GREATER_THAN: + if (*memByte > value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_LESS_THAN: + if (*memByte < value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_COMMON_BITS: + if (*memByte & value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_NO_COMMON_BITS: + if (!(*memByte & value)) + gBattlescriptCurrInstr = jumpPtr; + break; + } +} + +void atk2A_jumpifhalfword(void) +{ + u8 caseID = BSScriptRead8(gBattlescriptCurrInstr + 1); + const u16* memHword = BS2ScriptReadPtr(gBattlescriptCurrInstr + 2); + u16 value = BS2ScriptRead16(gBattlescriptCurrInstr + 6); + const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 8); + + gBattlescriptCurrInstr += 12; + + switch (caseID) + { + case CMP_EQUAL: + if (*memHword == value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_NOT_EQUAL: + if (*memHword != value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_GREATER_THAN: + if (*memHword > value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_LESS_THAN: + if (*memHword < value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_COMMON_BITS: + if (*memHword & value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_NO_COMMON_BITS: + if (!(*memHword & value)) + gBattlescriptCurrInstr = jumpPtr; + break; + } +} + +void atk2B_jumpifword(void) +{ + u8 caseID = BSScriptRead8(gBattlescriptCurrInstr + 1); + const u32* memWord = BS2ScriptReadPtr(gBattlescriptCurrInstr + 2); + u32 value = BSScriptRead32(gBattlescriptCurrInstr + 6); + const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 10); + + gBattlescriptCurrInstr += 14; + + switch (caseID) + { + case CMP_EQUAL: + if (*memWord == value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_NOT_EQUAL: + if (*memWord != value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_GREATER_THAN: + if (*memWord > value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_LESS_THAN: + if (*memWord < value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_COMMON_BITS: + if (*memWord & value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_NO_COMMON_BITS: + if (!(*memWord & value)) + gBattlescriptCurrInstr = jumpPtr; + break; + } +} + +void atk2C_jumpifarrayequal(void) +{ + const u8* mem1 = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + const u8* mem2 = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5); + u32 size = BSScriptRead8(gBattlescriptCurrInstr + 9); + const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 10); + + u8 i; + for (i = 0; i < size; i++) + { + if (*mem1 != *mem2) + { + gBattlescriptCurrInstr += 14; + break; + } + mem1++, mem2++; + } + + if (i == size) + gBattlescriptCurrInstr = jumpPtr; +} + +void atk2D_jumpifarraynotequal(void) +{ + u8 equalBytes = 0; + const u8* mem1 = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + const u8* mem2 = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5); + u32 size = BSScriptRead8(gBattlescriptCurrInstr + 9); + const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 10); + + u8 i; + for (i = 0; i < size; i++) + { + if (*mem1 == *mem2) + { + equalBytes++; + } + mem1++, mem2++; + } + + if (equalBytes != size) + gBattlescriptCurrInstr = jumpPtr; + else + gBattlescriptCurrInstr += 14; +} + +void atk2E_setbyte(void) +{ + u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + *memByte = BSScriptRead8(gBattlescriptCurrInstr + 5); + + gBattlescriptCurrInstr += 6; +} + +void atk2F_addbyte(void) +{ + u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + *memByte += BSScriptRead8(gBattlescriptCurrInstr + 5); + gBattlescriptCurrInstr += 6; +} + +void atk30_subbyte(void) +{ + u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + *memByte -= BSScriptRead8(gBattlescriptCurrInstr + 5); + gBattlescriptCurrInstr += 6; +} + +void atk31_copyarray(void) +{ + u8* dest = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + const u8* src = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5); + s32 size = BSScriptRead8(gBattlescriptCurrInstr + 9); + + s32 i; + for (i = 0; i < size; i++) + { + dest[i] = src[i]; + } + + gBattlescriptCurrInstr += 10; +} + +void atk32_copyarray_withindex(void) +{ + u8* dest = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + const u8* src = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5); + const u8* index = BS2ScriptReadPtr(gBattlescriptCurrInstr + 9); + s32 size = BSScriptRead8(gBattlescriptCurrInstr + 13); + + s32 i; + for (i = 0; i < size; i++) + { + dest[i] = src[i + *index]; + } + + gBattlescriptCurrInstr += 14; +} + +void atk33_orbyte(void) +{ + u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + *memByte |= BSScriptRead8(gBattlescriptCurrInstr + 5); + gBattlescriptCurrInstr += 6; +} + +void atk34_orhalfword(void) +{ + u16* memHword = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + u16 val = BS2ScriptRead16(gBattlescriptCurrInstr + 5); + + *memHword |= val; + gBattlescriptCurrInstr += 7; +} + +void atk35_orword(void) +{ + u32* memWord = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + u32 val = BS2ScriptRead32(gBattlescriptCurrInstr + 5); + + *memWord |= val; + gBattlescriptCurrInstr += 9; +} + +void atk36_bicbyte(void) +{ + u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + *memByte &= ~(BSScriptRead8(gBattlescriptCurrInstr + 5)); + gBattlescriptCurrInstr += 6; +} + +void atk37_bichalfword(void) +{ + u16* memHword = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + u16 val = BS2ScriptRead16(gBattlescriptCurrInstr + 5); + + *memHword &= ~val; + gBattlescriptCurrInstr += 7; +} + +void atk38_bicword(void) +{ + u32* memWord = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + u32 val = BS2ScriptRead32(gBattlescriptCurrInstr + 5); + + *memWord &= ~val; + gBattlescriptCurrInstr += 9; +} + +void atk39_pause(void) +{ + if (gBattleExecBuffer == 0) + { + u16 value = BS2ScriptRead16(gBattlescriptCurrInstr + 1); + if (++gPauseCounterBattle >= value) + { + gPauseCounterBattle = 0; + gBattlescriptCurrInstr += 3; + } + } +} + +void atk3A_waitstate(void) +{ + if (gBattleExecBuffer == 0) + gBattlescriptCurrInstr++; +} + +void atk3B_healthbar_update(void) +{ + if (BSScriptRead8(gBattlescriptCurrInstr + 1) == BS_GET_TARGET) + gActiveBank = gBankTarget; + else + gActiveBank = gBankAttacker; + + EmitHealthBarUpdate(0, gBattleMoveDamage); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 2; +} + +void atk3C_return(void) +{ + BattleScriptPop(); +} + +void atk3D_end(void) +{ + if (gBattleTypeFlags & BATTLE_TYPE_ARENA) + sub_81A5718(gBankAttacker); + + gBattleMoveFlags = 0; + gActiveBank = 0; + gFightStateTracker = 0xB; +} + +void atk3E_end2(void) +{ + gActiveBank = 0; + gFightStateTracker = 0xB; +} + +void atk3F_end3(void) // pops the main function stack +{ + BattleScriptPop(); + if (BATTLE_CALLBACKS_STACK->size) + BATTLE_CALLBACKS_STACK->size--; + gBattleMainFunc = BATTLE_CALLBACKS_STACK->function[BATTLE_CALLBACKS_STACK->size]; +} + +void atk41_call(void) +{ + BattleScriptPush(gBattlescriptCurrInstr + 5); + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); +} + +void atk42_jumpiftype2(void) +{ + u8 bank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + + if (BSScriptRead8(gBattlescriptCurrInstr + 2) == gBattleMons[bank].type1 || BSScriptRead8(gBattlescriptCurrInstr + 2) == gBattleMons[bank].type2) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 3); + else + gBattlescriptCurrInstr += 7; +} + +void atk43_jumpifabilitypresent(void) +{ + if (AbilityBattleEffects(ABILITYEFFECT_CHECK_ON_FIELD, 0, BSScriptRead8(gBattlescriptCurrInstr + 1), 0, 0)) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + else + gBattlescriptCurrInstr += 6; +} + +void atk44(void) +{ + *(gBankAttacker + gBattleStruct->field_54) = 1; +} + +void atk45_playanimation(void) +{ + const u16* argumentPtr; + + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + argumentPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 3); + + if (gBattlescriptCurrInstr[2] == B_ANIM_STATS_CHANGE + || gBattlescriptCurrInstr[2] == B_ANIM_SNATCH_MOVE + || gBattlescriptCurrInstr[2] == B_ANIM_SUBSTITUTE_FADE) + { + EmitBattleAnimation(0, gBattlescriptCurrInstr[2], *argumentPtr); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 7; + } + else if (gHitMarker & HITMARKER_NO_ANIMATIONS) + { + BattleScriptPush(gBattlescriptCurrInstr + 7); + gBattlescriptCurrInstr = BattleScript_Pausex20; + } + else if (gBattlescriptCurrInstr[2] == B_ANIM_RAIN_CONTINUES + || gBattlescriptCurrInstr[2] == B_ANIM_SUN_CONTINUES + || gBattlescriptCurrInstr[2] == B_ANIM_SANDSTORM_CONTINUES + || gBattlescriptCurrInstr[2] == B_ANIM_HAIL_CONTINUES) + { + EmitBattleAnimation(0, gBattlescriptCurrInstr[2], *argumentPtr); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 7; + } + else if (gStatuses3[gActiveBank] & STATUS3_SEMI_INVULNERABLE) + { + gBattlescriptCurrInstr += 7; + } + else + { + EmitBattleAnimation(0, gBattlescriptCurrInstr[2], *argumentPtr); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 7; + } +} + +void atk46_playanimation2(void) // animation Id is stored in the first pointer +{ + const u16* argumentPtr; + const u8* animationIdPtr; + + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + animationIdPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 2); + argumentPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 6); + + if (*animationIdPtr == B_ANIM_STATS_CHANGE + || *animationIdPtr == B_ANIM_SNATCH_MOVE + || *animationIdPtr == B_ANIM_SUBSTITUTE_FADE) + { + EmitBattleAnimation(0, *animationIdPtr, *argumentPtr); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 10; + } + else if (gHitMarker & HITMARKER_NO_ANIMATIONS) + { + gBattlescriptCurrInstr += 10; + } + else if (*animationIdPtr == B_ANIM_RAIN_CONTINUES + || *animationIdPtr == B_ANIM_SUN_CONTINUES + || *animationIdPtr == B_ANIM_SANDSTORM_CONTINUES + || *animationIdPtr == B_ANIM_HAIL_CONTINUES) + { + EmitBattleAnimation(0, *animationIdPtr, *argumentPtr); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 10; + } + else if (gStatuses3[gActiveBank] & STATUS3_SEMI_INVULNERABLE) + { + gBattlescriptCurrInstr += 10; + } + else + { + EmitBattleAnimation(0, *animationIdPtr, *argumentPtr); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 10; + } +} + +void atk47_setgraphicalstatchangevalues(void) +{ + u8 value = 0; + switch (gBattleScripting.statChanger & 0xF0) + { + case 0x10: // +1 + value = 0xF; + break; + case 0x20: // +2 + value = 0x27; + break; + case 0x90: // -1 + value = 0x16; + break; + case 0xA0: // -2 + value = 0x2E; + break; + } + gBattleScripting.animArg1 = (gBattleScripting.statChanger & 0xF) + value - 1; + gBattleScripting.animArg2 = 0; + gBattlescriptCurrInstr++; +} + +void atk48_playstatchangeanimation(void) +{ + s32 currStat = 0; + s16 statAnimId = 0; + s32 checkingStatAnimId = 0; + s32 changeableStats = 0; + u32 statsToCheck = 0; + + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + statsToCheck = BSScriptRead8(gBattlescriptCurrInstr + 2); + + if (gBattlescriptCurrInstr[3] & 1) // goes down + { + for (checkingStatAnimId = (gBattlescriptCurrInstr[3] & 0x2) ? 0x2D : 0x15; + statsToCheck != 0; + statsToCheck >>= 1, checkingStatAnimId += 1, currStat++) + { + if (!(statsToCheck & 1)) + continue; + if (!(gBattlescriptCurrInstr[3] & 8)) + { + if (gBattleMons[gActiveBank].statStages[currStat] > 0) + { + statAnimId = checkingStatAnimId; + changeableStats++; + } + } + else if (!gSideTimers[GET_BANK_SIDE(gActiveBank)].mistTimer + && gBattleMons[gActiveBank].ability != ABILITY_CLEAR_BODY + && gBattleMons[gActiveBank].ability != ABILITY_WHITE_SMOKE + && !(gBattleMons[gActiveBank].ability == ABILITY_KEEN_EYE && currStat == STAT_STAGE_ACC) + && !(gBattleMons[gActiveBank].ability == ABILITY_HYPER_CUTTER && currStat == STAT_STAGE_ATK)) + { + if (gBattleMons[gActiveBank].statStages[currStat] > 0) + { + statAnimId = checkingStatAnimId; + changeableStats++; + } + } + } + + if (changeableStats > 1) // more than one stat, so the color is gray + { + if (gBattlescriptCurrInstr[3] & 2) + statAnimId = 0x3A; + else + statAnimId = 0x39; + } + } + else // goes up + { + for (checkingStatAnimId = (gBattlescriptCurrInstr[3] & 0x2) ? 0x26 : 0xE; + statsToCheck != 0; + statsToCheck >>= 1, checkingStatAnimId += 1, currStat++) + { + if (statsToCheck & 1 && gBattleMons[gActiveBank].statStages[currStat] < 0xC) + { + statAnimId = checkingStatAnimId; + changeableStats++; + } + } + + if (changeableStats > 1) // more than one stat, so the color is gray + { + if (gBattlescriptCurrInstr[3] & 2) + statAnimId = 0x38; + else + statAnimId = 0x37; + } + } + + if (gBattlescriptCurrInstr[3] & 4 && changeableStats < 2) + { + gBattlescriptCurrInstr += 4; + } + else if (changeableStats != 0 && gBattleScripting.field_1B == 0) + { + EmitBattleAnimation(0, B_ANIM_STATS_CHANGE, statAnimId); + MarkBufferBankForExecution(gActiveBank); + if (gBattlescriptCurrInstr[3] & 4 && changeableStats > 1) + gBattleScripting.field_1B = 1; + gBattlescriptCurrInstr += 4; + } + else + { + gBattlescriptCurrInstr += 4; + } +} -- cgit v1.2.3 From fc57c6c817bcb8bed4469b5114ced17129bdca81 Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Sat, 23 Sep 2017 00:06:52 +0200 Subject: atk 48 is really troublesome --- src/battle_4.c | 63 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 32 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/battle_4.c b/src/battle_4.c index 8e0be22c2..ec84d1a5c 100644 --- a/src/battle_4.c +++ b/src/battle_4.c @@ -4271,48 +4271,49 @@ void atk47_setgraphicalstatchangevalues(void) void atk48_playstatchangeanimation(void) { - s32 currStat = 0; + u32 currStat = 0; s16 statAnimId = 0; - s32 checkingStatAnimId = 0; + s16 checkingStatAnimId = 0; s32 changeableStats = 0; u32 statsToCheck = 0; - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); - statsToCheck = BSScriptRead8(gBattlescriptCurrInstr + 2); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + statsToCheck = gBattlescriptCurrInstr[2]; - if (gBattlescriptCurrInstr[3] & 1) // goes down + if (gBattlescriptCurrInstr[3] & ATK48_STAT_NEGATIVE) // goes down { - for (checkingStatAnimId = (gBattlescriptCurrInstr[3] & 0x2) ? 0x2D : 0x15; - statsToCheck != 0; - statsToCheck >>= 1, checkingStatAnimId += 1, currStat++) + checkingStatAnimId = (gBattlescriptCurrInstr[3] & ATK48_STAT_BY_TWO) ? 0x2D : 0x15; + while (statsToCheck != 0) { - if (!(statsToCheck & 1)) - continue; - if (!(gBattlescriptCurrInstr[3] & 8)) + if (statsToCheck & 1) { - if (gBattleMons[gActiveBank].statStages[currStat] > 0) + if (!(gBattlescriptCurrInstr[3] & ATK48_LOWER_FAIL_CHECK)) { - statAnimId = checkingStatAnimId; - changeableStats++; + if (gBattleMons[gActiveBank].statStages[currStat] > 0) + { + statAnimId = checkingStatAnimId; + changeableStats++; + } } - } - else if (!gSideTimers[GET_BANK_SIDE(gActiveBank)].mistTimer - && gBattleMons[gActiveBank].ability != ABILITY_CLEAR_BODY - && gBattleMons[gActiveBank].ability != ABILITY_WHITE_SMOKE - && !(gBattleMons[gActiveBank].ability == ABILITY_KEEN_EYE && currStat == STAT_STAGE_ACC) - && !(gBattleMons[gActiveBank].ability == ABILITY_HYPER_CUTTER && currStat == STAT_STAGE_ATK)) - { - if (gBattleMons[gActiveBank].statStages[currStat] > 0) + else if (!gSideTimers[GET_BANK_SIDE(gActiveBank)].mistTimer + && gBattleMons[gActiveBank].ability != ABILITY_CLEAR_BODY + && gBattleMons[gActiveBank].ability != ABILITY_WHITE_SMOKE + && !(gBattleMons[gActiveBank].ability == ABILITY_KEEN_EYE && currStat == STAT_STAGE_ACC) + && !(gBattleMons[gActiveBank].ability == ABILITY_HYPER_CUTTER && currStat == STAT_STAGE_ATK)) { - statAnimId = checkingStatAnimId; - changeableStats++; + if (gBattleMons[gActiveBank].statStages[currStat] > 0) + { + statAnimId = checkingStatAnimId; + changeableStats++; + } } } + statsToCheck >>= 1, checkingStatAnimId++, currStat++; } if (changeableStats > 1) // more than one stat, so the color is gray { - if (gBattlescriptCurrInstr[3] & 2) + if (gBattlescriptCurrInstr[3] & ATK48_STAT_BY_TWO) statAnimId = 0x3A; else statAnimId = 0x39; @@ -4320,27 +4321,27 @@ void atk48_playstatchangeanimation(void) } else // goes up { - for (checkingStatAnimId = (gBattlescriptCurrInstr[3] & 0x2) ? 0x26 : 0xE; - statsToCheck != 0; - statsToCheck >>= 1, checkingStatAnimId += 1, currStat++) + checkingStatAnimId = (gBattlescriptCurrInstr[3] & ATK48_STAT_BY_TWO) ? 0x26 : 0xE; + while (statsToCheck != 0) { if (statsToCheck & 1 && gBattleMons[gActiveBank].statStages[currStat] < 0xC) { statAnimId = checkingStatAnimId; changeableStats++; } + statsToCheck >>= 1, checkingStatAnimId += 1, currStat++; } if (changeableStats > 1) // more than one stat, so the color is gray { - if (gBattlescriptCurrInstr[3] & 2) + if (gBattlescriptCurrInstr[3] & ATK48_STAT_BY_TWO) statAnimId = 0x38; else statAnimId = 0x37; } } - if (gBattlescriptCurrInstr[3] & 4 && changeableStats < 2) + if (gBattlescriptCurrInstr[3] & ATK48_BIT_x4 && changeableStats < 2) { gBattlescriptCurrInstr += 4; } @@ -4348,7 +4349,7 @@ void atk48_playstatchangeanimation(void) { EmitBattleAnimation(0, B_ANIM_STATS_CHANGE, statAnimId); MarkBufferBankForExecution(gActiveBank); - if (gBattlescriptCurrInstr[3] & 4 && changeableStats > 1) + if (gBattlescriptCurrInstr[3] & ATK48_BIT_x4 && changeableStats > 1) gBattleScripting.field_1B = 1; gBattlescriptCurrInstr += 4; } -- cgit v1.2.3 From 601fc9e85b383792819768c31728e4855e854f32 Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Sat, 23 Sep 2017 20:13:45 +0200 Subject: atk49 is matching baby WOHOHOHOHO --- src/battle_3.c | 5 +- src/battle_4.c | 570 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 564 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/battle_3.c b/src/battle_3.c index 1b62e3bb8..4453545d3 100644 --- a/src/battle_3.c +++ b/src/battle_3.c @@ -186,7 +186,6 @@ extern void b_call_bc_move_exec(const u8 *); extern void BattleTurnPassed(void); extern void SetMoveEffect(bool8 primary, u8 certainArg); extern bool8 UproarWakeUpCheck(u8 bank); -extern u8 sub_803F90C(u8 bank); extern void sub_803F9EC(); extern bool8 sub_80423F4(u8 bank, u8, u8); extern u8 sub_806D864(u8); @@ -848,7 +847,7 @@ u8 TurnBasedEffects(void) { gBankAttacker = gActiveBank; gBattleMons[gActiveBank].status2 -= 0x10; // uproar timer goes down - if (sub_803F90C(gActiveBank)) + if (HasMoveFailed(gActiveBank)) { CancelMultiTurnMoves(gActiveBank); gBattleCommunication[MULTISTRING_CHOOSER] = 1; @@ -874,7 +873,7 @@ u8 TurnBasedEffects(void) if (gBattleMons[gActiveBank].status2 & STATUS2_LOCK_CONFUSE) { gBattleMons[gActiveBank].status2 -= 0x400; - if (sub_803F90C(gActiveBank)) + if (HasMoveFailed(gActiveBank)) CancelMultiTurnMoves(gActiveBank); else if (!(gBattleMons[gActiveBank].status2 & STATUS2_LOCK_CONFUSE) && (gBattleMons[gActiveBank].status2 & STATUS2_MULTIPLETURNS)) diff --git a/src/battle_4.c b/src/battle_4.c index ec84d1a5c..f896cd806 100644 --- a/src/battle_4.c +++ b/src/battle_4.c @@ -57,6 +57,8 @@ extern u8 gBattleMoveFlags; extern u8 gBattleCommunication[]; extern u16 gUnknown_02024250[4]; extern u16 gUnknown_02024258[4]; +extern u16 gUnknown_02024260[4]; +extern u8 gUnknown_02024270[4]; extern u8 gStringBank; extern u16 gDynamicBasePower; extern u16 gLastUsedItem; @@ -78,6 +80,9 @@ extern u8 gCurrentMoveTurn; extern u8 gBattleBufferB[BATTLE_BANKS_COUNT][0x200]; extern u16 gLockedMoves[BATTLE_BANKS_COUNT]; extern u16 gPartnerTrainerId; +extern u16 gLastUsedMove; +extern u16 gUnknownMovesUsedByBanks[BATTLE_BANKS_COUNT]; +extern u16 gLastUsedMovesByBanks[BATTLE_BANKS_COUNT]; extern const struct BattleMove gBattleMoves[]; extern const struct BaseStats gBaseStats[]; @@ -85,6 +90,7 @@ extern const u8 gTypeEffectiveness[]; extern const u16 gMissStringIds[]; extern const u16 gTrappingMoves[]; extern const u8 gTrainerMoney[]; +extern const u8* const gBattleScriptsForMoveEffects[]; // functions extern void sub_81A5718(u8 bank); // battle frontier 2 @@ -132,6 +138,9 @@ extern const u8 BattleScript_FaintAttacker[]; extern const u8 BattleScript_FaintTarget[]; extern const u8 BattleScript_DestinyBondTakesLife[]; extern const u8 BattleScript_GrudgeTakesPp[]; +extern const u8 BattleScript_RageIsBuilding[]; +extern const u8 BattleScript_DefrostedViaFireMove[]; +extern const u8 gUnknown_082DB87D[]; // read via orr #define BSScriptRead32(ptr) ((ptr)[0] | (ptr)[1] << 8 | (ptr)[2] << 16 | (ptr)[3] << 24) @@ -145,7 +154,7 @@ extern const u8 BattleScript_GrudgeTakesPp[]; #define TARGET_PROTECT_AFFECTED ((gProtectStructs[gBankTarget].protected && gBattleMoves[gCurrentMove].flags & FLAG_PROTECT_AFFECTED)) -#define TARGET_TURN_DAMAGED (((gSpecialStatuses[gBankTarget].moveturnLostHP_physical || gSpecialStatuses[gBankTarget].moveturnLostHP_physical.moveturnLostHP_special))) +#define TARGET_TURN_DAMAGED (((gSpecialStatuses[gBankTarget].moveturnLostHP_physical || gSpecialStatuses[gBankTarget].moveturnLostHP_special))) // this file's functions bool8 IsTwoTurnsMove(u16 move); @@ -227,7 +236,7 @@ void atk45_playanimation(void); void atk46_playanimation2(void); void atk47_setgraphicalstatchangevalues(void); void atk48_playstatchangeanimation(void); -void atk49_moveendturn(void); +void atk49_moveend(void); void atk4A_typecalc2(void); void atk4B_return_atk_to_ball(void); void atk4C_copy_poke_data(void); @@ -479,7 +488,7 @@ void (* const gBattleScriptingCommandsTable[])(void) = atk46_playanimation2, atk47_setgraphicalstatchangevalues, atk48_playstatchangeanimation, - atk49_moveendturn, + atk49_moveend, atk4A_typecalc2, atk4B_return_atk_to_ball, atk4C_copy_poke_data, @@ -2616,13 +2625,12 @@ void SetMoveEffect(bool8 primary, u8 certain) else { // This is a leftover from R/S direct use of ewram addresses - void** memes1 = (void**)(&gBattleStruct); - void* memes2 = (void*)((u32)(gBankAttacker * 2 + offsetof(struct BattleStruct, field_D0))); - u16* memes3 = (u16*)(((void*)(*memes1) + (u32)(memes2))); - gLastUsedItem = *memes3 = gBattleMons[gBankTarget].item; + u16* changedItem; + GET_CHANGED_ITEM_PTR_VIA_MEME_ACCESS(gBankAttacker, changedItem); + gLastUsedItem = *changedItem = gBattleMons[gBankTarget].item; // A sane representation of this would simply be: - // gLastUsedItem = gBattleStruct->field_D0[gBankAttacker] = gBattleMons[gBankTarget].item; + // gLastUsedItem = gBattleStruct->changedItems[gBankAttacker] = gBattleMons[gBankTarget].item; gBattleMons[gBankTarget].item = 0; @@ -4269,6 +4277,7 @@ void atk47_setgraphicalstatchangevalues(void) gBattlescriptCurrInstr++; } +#ifdef NONMATCHING void atk48_playstatchangeanimation(void) { u32 currStat = 0; @@ -4358,3 +4367,548 @@ void atk48_playstatchangeanimation(void) gBattlescriptCurrInstr += 4; } } +#else +__attribute__((naked)) +void atk48_playstatchangeanimation(void) +{ + asm("\n\ + .syntax unified\n\ + push {r4-r7,lr}\n\ + mov r7, r10\n\ + mov r6, r9\n\ + mov r5, r8\n\ + push {r5-r7}\n\ + sub sp, 0x4\n\ + movs r7, 0\n\ + movs r0, 0\n\ + mov r8, r0\n\ + movs r3, 0\n\ + ldr r5, =gBattlescriptCurrInstr\n\ + ldr r0, [r5]\n\ + ldrb r0, [r0, 0x1]\n\ + str r3, [sp]\n\ + bl GetBattleBank\n\ + ldr r2, =gActiveBank\n\ + strb r0, [r2]\n\ + ldr r0, [r5]\n\ + ldrb r4, [r0, 0x2]\n\ + ldrb r1, [r0, 0x3]\n\ + movs r0, 0x1\n\ + ands r0, r1\n\ + ldr r3, [sp]\n\ + cmp r0, 0\n\ + beq _0804BAEC\n\ + movs r0, 0x2\n\ + ands r0, r1\n\ + movs r1, 0x15\n\ + cmp r0, 0\n\ + beq _0804BA18\n\ + movs r1, 0x2D\n\ +_0804BA18:\n\ + cmp r4, 0\n\ + beq _0804BAC0\n\ + movs r0, 0x1\n\ + mov r10, r0\n\ + ldr r0, =gBattleMons + 0x18\n\ + mov r9, r0\n\ + lsls r5, r1, 16\n\ +_0804BA26:\n\ + adds r0, r4, 0\n\ + mov r1, r10\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _0804BAB2\n\ + ldr r0, =gBattlescriptCurrInstr\n\ + ldr r0, [r0]\n\ + ldrb r1, [r0, 0x3]\n\ + movs r0, 0x8\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _0804BA58\n\ + ldr r0, =gActiveBank\n\ + ldrb r1, [r0]\n\ + movs r0, 0x58\n\ + muls r0, r1\n\ + adds r0, r7, r0\n\ + b _0804BAA0\n\ + .pool\n\ +_0804BA58:\n\ + ldr r6, =gActiveBank\n\ + ldrb r0, [r6]\n\ + str r3, [sp]\n\ + bl GetBankIdentity\n\ + mov r1, r10\n\ + ands r1, r0\n\ + lsls r0, r1, 1\n\ + adds r0, r1\n\ + lsls r0, 2\n\ + ldr r1, =gSideTimers\n\ + adds r0, r1\n\ + ldrb r0, [r0, 0x4]\n\ + ldr r3, [sp]\n\ + cmp r0, 0\n\ + bne _0804BAB2\n\ + ldr r0, =gBattleMons\n\ + ldrb r2, [r6]\n\ + movs r1, 0x58\n\ + muls r2, r1\n\ + adds r0, r2, r0\n\ + adds r0, 0x20\n\ + ldrb r0, [r0]\n\ + cmp r0, 0x1D\n\ + beq _0804BAB2\n\ + cmp r0, 0x49\n\ + beq _0804BAB2\n\ + cmp r0, 0x33\n\ + bne _0804BA96\n\ + cmp r7, 0x6\n\ + beq _0804BAB2\n\ +_0804BA96:\n\ + cmp r0, 0x34\n\ + bne _0804BA9E\n\ + cmp r7, 0x1\n\ + beq _0804BAB2\n\ +_0804BA9E:\n\ + adds r0, r7, r2\n\ +_0804BAA0:\n\ + add r0, r9\n\ + ldrb r0, [r0]\n\ + lsls r0, 24\n\ + asrs r0, 24\n\ + cmp r0, 0\n\ + ble _0804BAB2\n\ + lsrs r0, r5, 16\n\ + mov r8, r0\n\ + adds r3, 0x1\n\ +_0804BAB2:\n\ + lsrs r4, 1\n\ + movs r1, 0x80\n\ + lsls r1, 9\n\ + adds r5, r1\n\ + adds r7, 0x1\n\ + cmp r4, 0\n\ + bne _0804BA26\n\ +_0804BAC0:\n\ + ldr r0, =gBattlescriptCurrInstr\n\ + mov r9, r0\n\ + cmp r3, 0x1\n\ + ble _0804BB4E\n\ + ldr r0, [r0]\n\ + ldrb r1, [r0, 0x3]\n\ + movs r0, 0x2\n\ + ands r0, r1\n\ + movs r1, 0x39\n\ + mov r8, r1\n\ + cmp r0, 0\n\ + beq _0804BB4E\n\ + movs r0, 0x3A\n\ + b _0804BB4C\n\ + .pool\n\ +_0804BAEC:\n\ + movs r0, 0x2\n\ + ands r0, r1\n\ + movs r1, 0xE\n\ + cmp r0, 0\n\ + beq _0804BAF8\n\ + movs r1, 0x26\n\ +_0804BAF8:\n\ + mov r9, r5\n\ + cmp r4, 0\n\ + beq _0804BB34\n\ + ldr r6, =gBattleMons + 0x18\n\ + adds r5, r2, 0\n\ + lsls r2, r1, 16\n\ +_0804BB04:\n\ + movs r0, 0x1\n\ + ands r0, r4\n\ + cmp r0, 0\n\ + beq _0804BB26\n\ + ldrb r1, [r5]\n\ + movs r0, 0x58\n\ + muls r0, r1\n\ + adds r0, r7, r0\n\ + adds r0, r6\n\ + ldrb r0, [r0]\n\ + lsls r0, 24\n\ + asrs r0, 24\n\ + cmp r0, 0xB\n\ + bgt _0804BB26\n\ + lsrs r1, r2, 16\n\ + mov r8, r1\n\ + adds r3, 0x1\n\ +_0804BB26:\n\ + lsrs r4, 1\n\ + movs r0, 0x80\n\ + lsls r0, 9\n\ + adds r2, r0\n\ + adds r7, 0x1\n\ + cmp r4, 0\n\ + bne _0804BB04\n\ +_0804BB34:\n\ + cmp r3, 0x1\n\ + ble _0804BB4E\n\ + mov r1, r9\n\ + ldr r0, [r1]\n\ + ldrb r1, [r0, 0x3]\n\ + movs r0, 0x2\n\ + ands r0, r1\n\ + movs r1, 0x37\n\ + mov r8, r1\n\ + cmp r0, 0\n\ + beq _0804BB4E\n\ + movs r0, 0x38\n\ +_0804BB4C:\n\ + mov r8, r0\n\ +_0804BB4E:\n\ + mov r1, r9\n\ + ldr r2, [r1]\n\ + ldrb r1, [r2, 0x3]\n\ + movs r0, 0x4\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _0804BB6C\n\ + cmp r3, 0x1\n\ + bgt _0804BB6C\n\ + adds r0, r2, 0x4\n\ + mov r1, r9\n\ + b _0804BBBA\n\ + .pool\n\ +_0804BB6C:\n\ + cmp r3, 0\n\ + beq _0804BBB4\n\ + ldr r4, =gBattleScripting\n\ + ldrb r0, [r4, 0x1B]\n\ + cmp r0, 0\n\ + bne _0804BBB4\n\ + movs r0, 0\n\ + movs r1, 0x1\n\ + mov r2, r8\n\ + str r3, [sp]\n\ + bl EmitBattleAnimation\n\ + ldr r0, =gActiveBank\n\ + ldrb r0, [r0]\n\ + bl MarkBufferBankForExecution\n\ + ldr r0, =gBattlescriptCurrInstr\n\ + ldr r0, [r0]\n\ + ldrb r1, [r0, 0x3]\n\ + movs r0, 0x4\n\ + ands r0, r1\n\ + ldr r3, [sp]\n\ + cmp r0, 0\n\ + beq _0804BBA4\n\ + cmp r3, 0x1\n\ + ble _0804BBA4\n\ + movs r0, 0x1\n\ + strb r0, [r4, 0x1B]\n\ +_0804BBA4:\n\ + ldr r1, =gBattlescriptCurrInstr\n\ + b _0804BBB6\n\ + .pool\n\ +_0804BBB4:\n\ + mov r1, r9\n\ +_0804BBB6:\n\ + ldr r0, [r1]\n\ + adds r0, 0x4\n\ +_0804BBBA:\n\ + str r0, [r1]\n\ + add sp, 0x4\n\ + pop {r3-r5}\n\ + mov r8, r3\n\ + mov r9, r4\n\ + mov r10, r5\n\ + pop {r4-r7}\n\ + pop {r0}\n\ + bx r0\n\ + .syntax divided"); +} +#endif // NONMATCHING + +#define ATK49_LAST_CASE 17 + +void atk49_moveend(void) +{ + s32 i; + bool32 effect; + u8 moveType; + u8 holdEffectAtk; + u16 *choicedMoveAtk; + u8 arg1, arg2; + u16 lastMove; + + effect = FALSE; + + if (gLastUsedMove == 0xFFFF) + lastMove = 0; + else + lastMove = gLastUsedMove; + + arg1 = gBattlescriptCurrInstr[1]; + arg2 = gBattlescriptCurrInstr[2]; + + if (gBattleMons[gBankAttacker].item == ITEM_ENIGMA_BERRY) + holdEffectAtk = gEnigmaBerries[gBankAttacker].holdEffect; + else + holdEffectAtk = ItemId_GetHoldEffect(gBattleMons[gBankAttacker].item); + + choicedMoveAtk = &gBattleStruct->choicedMove[gBankAttacker]; + + GET_MOVE_TYPE(gCurrentMove, moveType); + + do + { + switch (gBattleScripting.atk49_state) + { + case 0: // rage check + if (gBattleMons[gBankTarget].status2 & STATUS2_RAGE + && gBattleMons[gBankTarget].hp != 0 && gBankAttacker != gBankTarget + && GetBankSide(gBankAttacker) != GetBankSide(gBankTarget) + && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT) && TARGET_TURN_DAMAGED + && gBattleMoves[gCurrentMove].power && gBattleMons[gBankTarget].statStages[STAT_STAGE_ATK] <= 0xB) + { + gBattleMons[gBankTarget].statStages[STAT_STAGE_ATK]++; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_RageIsBuilding; + effect = TRUE; + } + gBattleScripting.atk49_state++; + break; + case 1: // defrosting check + if (gBattleMons[gBankTarget].status1 & STATUS_FREEZE + && gBattleMons[gBankTarget].hp != 0 && gBankAttacker != gBankTarget + && gSpecialStatuses[gBankTarget].moveturnLostHP_special + && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT) && moveType == TYPE_FIRE) + { + gBattleMons[gBankTarget].status1 &= ~(STATUS_FREEZE); + gActiveBank = gBankTarget; + EmitSetAttributes(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gBankTarget].status1); + MarkBufferBankForExecution(gActiveBank); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_DefrostedViaFireMove; + effect = TRUE; + } + gBattleScripting.atk49_state++; + break; + case 2: // target synchronize + if (AbilityBattleEffects(ABILITYEFFECT_SYNCHRONIZE, gBankTarget, 0, 0, 0)) + effect = TRUE; + gBattleScripting.atk49_state++; + break; + case 3: // contact abilities + if (AbilityBattleEffects(ABILITYEFFECT_CONTACT, gBankTarget, 0, 0, 0)) + effect = TRUE; + gBattleScripting.atk49_state++; + break; + case 4: // status immunities + if (AbilityBattleEffects(ABILITYEFFECT_IMMUNITY, 0, 0, 0, 0)) + effect = TRUE; // it loops through all banks, so we increment after its done with all banks + else + gBattleScripting.atk49_state++; + break; + case 5: // attacker synchronize + if (AbilityBattleEffects(ABILITYEFFECT_ATK_SYNCHRONIZE, gBankAttacker, 0, 0, 0)) + effect = TRUE; + gBattleScripting.atk49_state++; + break; + case 6: // update choice band move + if (!(gHitMarker & HITMARKER_OBEYS) || holdEffectAtk != HOLD_EFFECT_CHOICE_BAND + || gLastUsedMove == MOVE_STRUGGLE || (*choicedMoveAtk != 0 && *choicedMoveAtk != 0xFFFF)) + goto LOOP; + if (gLastUsedMove == MOVE_BATON_PASS && !(gBattleMoveFlags & MOVESTATUS_FAILED)) + { + gBattleScripting.atk49_state++; + break; + } + *choicedMoveAtk = gLastUsedMove; + LOOP: + { + for (i = 0; i < 4; i++) + { + if (gBattleMons[gBankAttacker].moves[i] == *choicedMoveAtk) + break; + } + if (i == 4) + *choicedMoveAtk = 0; + + gBattleScripting.atk49_state++; + } + break; + case 7: // changed held items + for (i = 0; i < gNoOfAllBanks; i++) + { + u16* changedItem; + GET_CHANGED_ITEM_PTR_VIA_MEME_ACCESS(i, changedItem); + if (*changedItem != 0) + { + gBattleMons[i].item = *changedItem; + *changedItem = 0; + } + } + gBattleScripting.atk49_state++; + break; + case 11: // item effects for all banks + if (ItemBattleEffects(3, 0, FALSE)) + effect = TRUE; + else + gBattleScripting.atk49_state++; + break; + case 12: // king's rock and shell bell + if (ItemBattleEffects(4, 0, FALSE)) + effect = TRUE; + gBattleScripting.atk49_state++; + break; + case 8: // make attacker sprite invisible + if (gStatuses3[gBankAttacker] & (STATUS3_SEMI_INVULNERABLE) + && gHitMarker & HITMARKER_NO_ANIMATIONS) + { + gActiveBank = gBankAttacker; + EmitSpriteInvisibility(0, TRUE); + MarkBufferBankForExecution(gActiveBank); + gBattleScripting.atk49_state++; + return; + } + gBattleScripting.atk49_state++; + break; + case 9: // make attacker sprite visible + if (gBattleMoveFlags & MOVESTATUS_NOEFFECT + || !(gStatuses3[gBankAttacker] & (STATUS3_SEMI_INVULNERABLE)) + || HasMoveFailed(gBankAttacker)) + { + gActiveBank = gBankAttacker; + EmitSpriteInvisibility(0, FALSE); + MarkBufferBankForExecution(gActiveBank); + gStatuses3[gBankAttacker] &= ~(STATUS3_SEMI_INVULNERABLE); + gSpecialStatuses[gBankAttacker].restoredBankSprite = 1; + gBattleScripting.atk49_state++; + return; + } + gBattleScripting.atk49_state++; + break; + case 10: // make target sprite visible + if (!gSpecialStatuses[gBankTarget].restoredBankSprite && gBankTarget < gNoOfAllBanks + && !(gStatuses3[gBankTarget] & STATUS3_SEMI_INVULNERABLE)) + { + gActiveBank = gBankTarget; + EmitSpriteInvisibility(0, FALSE); + MarkBufferBankForExecution(gActiveBank); + gStatuses3[gBankTarget] &= ~(STATUS3_SEMI_INVULNERABLE); + gBattleScripting.atk49_state++; + return; + } + gBattleScripting.atk49_state++; + break; + case 13: // update substitute + for (i = 0; i < gNoOfAllBanks; i++) + { + if (gDisableStructs[i].substituteHP == 0) + gBattleMons[i].status2 &= ~(STATUS2_SUBSTITUTE); + } + gBattleScripting.atk49_state++; + break; + case 14: // This case looks interesting, although I am not certain what it does. Probably fine tunes edge cases. + if (gHitMarker & HITMARKER_PURSUIT_TRAP) + { + gActiveBank = gBankAttacker; + gBankAttacker = gBankTarget; + gBankTarget = gActiveBank; + gHitMarker &= ~(HITMARKER_PURSUIT_TRAP); + } + if (gHitMarker & HITMARKER_ATTACKSTRING_PRINTED) + { + gUnknownMovesUsedByBanks[gBankAttacker] = gLastUsedMove; + } + if (!(gAbsentBankFlags & gBitTable[gBankAttacker]) + && !(gBattleStruct->field_91 & gBitTable[gBankAttacker]) + && gBattleMoves[lastMove].effect != EFFECT_BATON_PASS) + { + if (gHitMarker & HITMARKER_OBEYS) + { + gLastUsedMovesByBanks[gBankAttacker] = gLastUsedMove; + gUnknown_02024260[gBankAttacker] = gCurrentMove; + } + else + { + gLastUsedMovesByBanks[gBankAttacker] = 0xFFFF; + gUnknown_02024260[gBankAttacker] = 0xFFFF; + } + + if (!(gHitMarker & HITMARKER_FAINTED(gBankTarget))) + gUnknown_02024270[gBankTarget] = gBankAttacker; + + if (gHitMarker & HITMARKER_OBEYS && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + if (gLastUsedMove == 0xFFFF) + { + gUnknown_02024250[gBankTarget] = gLastUsedMove; + } + else + { + gUnknown_02024250[gBankTarget] = gCurrentMove; + GET_MOVE_TYPE(gCurrentMove, gUnknown_02024258[gBankTarget]); + } + } + else + { + gUnknown_02024250[gBankTarget] = 0xFFFF; + } + } + gBattleScripting.atk49_state++; + break; + case 15: // mirror move + if (!(gAbsentBankFlags & gBitTable[gBankAttacker]) && !(gBattleStruct->field_91 & gBitTable[gBankAttacker]) + && gBattleMoves[lastMove].flags & FLAG_MIRROR_MOVE_AFFECTED && gHitMarker & HITMARKER_OBEYS + && gBankAttacker != gBankTarget && !(gHitMarker & HITMARKER_FAINTED(gBankTarget)) + && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + u8 target, attacker; + + *(gBattleStruct->mirrorMoves + gBankTarget * 2 + 0) = gLastUsedMove; + *(gBattleStruct->mirrorMoves + gBankTarget * 2 + 1) = gLastUsedMove >> 8; + + target = gBankTarget; + attacker = gBankAttacker; + *(attacker * 2 + target * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = gLastUsedMove; + + target = gBankTarget; + attacker = gBankAttacker; + *(attacker * 2 + target * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) = gLastUsedMove >> 8; + } + gBattleScripting.atk49_state++; + break; + case 16: // + if (!(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) && gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && !gProtectStructs[gBankAttacker].chargingTurn && gBattleMoves[gCurrentMove].target == MOVE_TARGET_BOTH + && !(gHitMarker & HITMARKER_NO_ATTACKSTRING)) + { + u8 bank = GetBankByPlayerAI(GetBankIdentity(gBankTarget) ^ 2); + if (gBattleMons[bank].hp != 0) + { + gBankTarget = bank; + gHitMarker |= HITMARKER_NO_ATTACKSTRING; + gBattleScripting.atk49_state = 0; + MoveValuesCleanUp(); + BattleScriptPush(gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]); + gBattlescriptCurrInstr = gUnknown_082DB87D; + return; + } + else + { + gHitMarker |= HITMARKER_NO_ATTACKSTRING; + } + } + gBattleScripting.atk49_state++; + break; + case ATK49_LAST_CASE: + break; + } + + if (arg1 == 1 && effect == FALSE) + gBattleScripting.atk49_state = ATK49_LAST_CASE; + if (arg1 == 2 && arg2 == gBattleScripting.atk49_state) + gBattleScripting.atk49_state = ATK49_LAST_CASE; + + } while (gBattleScripting.atk49_state != ATK49_LAST_CASE && effect == FALSE); + + if (gBattleScripting.atk49_state == ATK49_LAST_CASE && effect == FALSE) + gBattlescriptCurrInstr += 3; +} + -- cgit v1.2.3 From 898d0b20ad524e2837079a50f33f6fae0e72b685 Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Sun, 24 Sep 2017 00:29:52 +0200 Subject: up to x50 --- src/battle_3.c | 2 - src/battle_4.c | 368 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/pokemon_3.c | 4 +- 3 files changed, 370 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/battle_3.c b/src/battle_3.c index 4453545d3..1b443118d 100644 --- a/src/battle_3.c +++ b/src/battle_3.c @@ -188,8 +188,6 @@ extern void SetMoveEffect(bool8 primary, u8 certainArg); extern bool8 UproarWakeUpCheck(u8 bank); extern void sub_803F9EC(); extern bool8 sub_80423F4(u8 bank, u8, u8); -extern u8 sub_806D864(u8); -extern u8 sub_806D82C(u8); extern u8 weather_get_current(void); extern void sub_803E08C(void); extern void bc_move_exec_returning(void); diff --git a/src/battle_4.c b/src/battle_4.c index f896cd806..db6d7fe53 100644 --- a/src/battle_4.c +++ b/src/battle_4.c @@ -17,6 +17,7 @@ #include "songs.h" #include "text.h" #include "sound.h" +#include "pokedex.h" // variables @@ -94,6 +95,7 @@ extern const u8* const gBattleScriptsForMoveEffects[]; // functions extern void sub_81A5718(u8 bank); // battle frontier 2 +extern void sub_81A56B4(void); // battle frontier 2 // BattleScripts extern const u8 BattleScript_MoveEnd[]; @@ -4912,3 +4914,369 @@ void atk49_moveend(void) gBattlescriptCurrInstr += 3; } +void atk4A_typecalc2(void) +{ + u8 flags = 0; + s32 i = 0; + u8 moveType = gBattleMoves[gCurrentMove].type; + + if (gBattleMons[gBankTarget].ability == ABILITY_LEVITATE && moveType == TYPE_GROUND) + { + gLastUsedAbility = gBattleMons[gBankTarget].ability; + gBattleMoveFlags |= (MOVESTATUS_MISSED | MOVESTATUS_NOTAFFECTED); + gUnknown_02024250[gBankTarget] = 0; + gBattleCommunication[6] = moveType; + RecordAbilityBattle(gBankTarget, gLastUsedAbility); + } + else + { + while (gTypeEffectiveness[i]!= TYPE_ENDTABLE) + { + if (gTypeEffectiveness[i] == TYPE_FORESIGHT) + { + if (gBattleMons[gBankTarget].status2 & STATUS2_FORESIGHT) + { + break; + } + else + { + i += 3; + continue; + } + } + + if (gTypeEffectiveness[i] == moveType) + { + // check type1 + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type1) + { + if (gTypeEffectiveness[i + 2] == 0) + { + gBattleMoveFlags |= MOVESTATUS_NOTAFFECTED; + break; + } + if (gTypeEffectiveness[i + 2] == 5) + { + flags |= MOVESTATUS_NOTVERYEFFECTIVE; + } + if (gTypeEffectiveness[i + 2] == 20) + { + flags |= MOVESTATUS_SUPEREFFECTIVE; + } + } + // check type2 + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type2) + { + if (gBattleMons[gBankTarget].type1 != gBattleMons[gBankTarget].type2 + && gTypeEffectiveness[i + 2] == 0) + { + gBattleMoveFlags |= MOVESTATUS_NOTAFFECTED; + break; + } + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type2 + && gBattleMons[gBankTarget].type1 != gBattleMons[gBankTarget].type2 + && gTypeEffectiveness[i + 2] == 5) + { + flags |= MOVESTATUS_NOTVERYEFFECTIVE; + } + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type2 + && gBattleMons[gBankTarget].type1 != gBattleMons[gBankTarget].type2 + && gTypeEffectiveness[i + 2] == 20) + { + flags |= MOVESTATUS_SUPEREFFECTIVE; + } + } + } + i += 3; + } + } + + if (gBattleMons[gBankTarget].ability == ABILITY_WONDER_GUARD + && !(flags & MOVESTATUS_NOEFFECT) + && AttacksThisTurn(gBankAttacker, gCurrentMove) == 2 + && (!(flags & MOVESTATUS_SUPEREFFECTIVE) || ((flags & (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE)) == (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE))) + && gBattleMoves[gCurrentMove].power) + { + gLastUsedAbility = ABILITY_WONDER_GUARD; + gBattleMoveFlags |= MOVESTATUS_MISSED; + gUnknown_02024250[gBankTarget] = 0; + gBattleCommunication[6] = 3; + RecordAbilityBattle(gBankTarget, gLastUsedAbility); + } + if (gBattleMoveFlags & MOVESTATUS_NOTAFFECTED) + gProtectStructs[gBankAttacker].notEffective = 1; + + gBattlescriptCurrInstr++; +} + +void atk4B_return_atk_to_ball(void) +{ + gActiveBank = gBankAttacker; + if (!(gHitMarker & HITMARKER_FAINTED(gActiveBank))) + { + EmitReturnPokeToBall(0, 0); + MarkBufferBankForExecution(gActiveBank); + } + gBattlescriptCurrInstr++; +} + +void atk4C_copy_poke_data(void) +{ + if (gBattleExecBuffer) + return; + + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + + gBattlePartyID[gActiveBank] = *(gBattleStruct->field_5C + gActiveBank); + + EmitGetAttributes(0, 0, gBitTable[gBattlePartyID[gActiveBank]]); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 2; +} + +void atk4D_switch_data_update(void) +{ + struct BattlePokemon oldData; + s32 i; + u8 *monData; + + if (gBattleExecBuffer) + return; + + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + oldData = gBattleMons[gActiveBank]; + monData = (u8*)(&gBattleMons[gActiveBank]); + + for (i = 0; i < sizeof(struct BattlePokemon); i++) + { + monData[i] = gBattleBufferB[gActiveBank][4 + i]; + } + + gBattleMons[gActiveBank].type1 = gBaseStats[gBattleMons[gActiveBank].species].type1; + gBattleMons[gActiveBank].type2 = gBaseStats[gBattleMons[gActiveBank].species].type2; + gBattleMons[gActiveBank].ability = GetAbilityBySpecies(gBattleMons[gActiveBank].species, gBattleMons[gActiveBank].altAbility); + + // check knocked off item + i = GetBankSide(gActiveBank); + if (gWishFutureKnock.knockedOffPokes[i] & gBitTable[gBattlePartyID[gActiveBank]]) + { + gBattleMons[gActiveBank].item = 0; + } + + if (gBattleMoves[gCurrentMove].effect == EFFECT_BATON_PASS) + { + for (i = 0; i < 8; i++) + { + gBattleMons[gActiveBank].statStages[i] = oldData.statStages[i]; + } + gBattleMons[gActiveBank].status2 = oldData.status2; + } + + SwitchInClearStructs(); + + if (gBattleTypeFlags & BATTLE_TYPE_PALACE && gBattleMons[gActiveBank].maxHP / 2 >= gBattleMons[gActiveBank].hp + && gBattleMons[gActiveBank].hp != 0 && !(gBattleMons[gActiveBank].status1 & STATUS_SLEEP)) + { + gBattleStruct->field_92 |= gBitTable[gActiveBank]; + } + + gBattleScripting.bank = gActiveBank; + gBattleTextBuff1[0] = PLACEHOLDER_BEGIN; + gBattleTextBuff1[1] = 7; + gBattleTextBuff1[2] = gActiveBank; + gBattleTextBuff1[3] = gBattlePartyID[gActiveBank]; + gBattleTextBuff1[4] = EOS; + + gBattlescriptCurrInstr += 2; +} + +void atk4E_switchin_anim(void) +{ + if (gBattleExecBuffer) + return; + + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + + if (GetBankSide(gActiveBank) == SIDE_OPPONENT + && !(gBattleTypeFlags & (BATTLE_TYPE_LINK + | BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_x2000000 + | BATTLE_TYPE_x4000000 + | BATTLE_TYPE_FRONTIER))) + HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gActiveBank].species), FLAG_SET_SEEN, gBattleMons[gActiveBank].personality); + + gAbsentBankFlags &= ~(gBitTable[gActiveBank]); + + EmitSwitchInAnim(0, gBattlePartyID[gActiveBank], gBattlescriptCurrInstr[2]); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 3; + + if (gBattleTypeFlags & BATTLE_TYPE_ARENA) + sub_81A56B4(); +} + +void atk4F_jump_if_cannot_switch(void) +{ + s32 val = 0; + s32 compareVar = 0; + struct Pokemon *party = NULL; + s32 r7 = 0; + + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1] & ~(ATK4F_DONT_CHECK_STATUSES)); + + if (!(gBattlescriptCurrInstr[1] & ATK4F_DONT_CHECK_STATUSES) + && ((gBattleMons[gActiveBank].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION)) + || (gStatuses3[gActiveBank] & STATUS3_ROOTED))) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + } + else if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + { + #ifndef NONMATCHING + asm("":::"r5"); + #endif // NONMATCHING + if (GetBankSide(gActiveBank) == SIDE_OPPONENT) + party = gEnemyParty; + else + party = gPlayerParty; + + val = 0; + if (2 & gActiveBank) + val = 3; + + for (compareVar = val + 3; val < compareVar; val++) + { + if (GetMonData(&party[val], MON_DATA_SPECIES) != SPECIES_NONE + && !GetMonData(&party[val], MON_DATA_IS_EGG) + && GetMonData(&party[val], MON_DATA_HP) != 0 + && gBattlePartyID[gActiveBank] != val) + break; + } + + if (val == compareVar) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + else + gBattlescriptCurrInstr += 6; + } + else if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + if (gBattleTypeFlags & BATTLE_TYPE_x800000) + { + if (GetBankSide(gActiveBank) == SIDE_PLAYER) + { + party = gPlayerParty; + + val = 0; + if (sub_806D82C(sub_806D864(gActiveBank)) == TRUE) + val = 3; + } + else + { + party = gEnemyParty; + + if (gActiveBank == 1) + val = 0; + else + val = 3; + } + } + else + { + if (GetBankSide(gActiveBank) == SIDE_OPPONENT) + party = gEnemyParty; + else + party = gPlayerParty; + + + val = 0; + if (sub_806D82C(sub_806D864(gActiveBank)) == TRUE) + val = 3; + } + + for (compareVar = val + 3; val < compareVar; val++) + { + if (GetMonData(&party[val], MON_DATA_SPECIES) != SPECIES_NONE + && !GetMonData(&party[val], MON_DATA_IS_EGG) + && GetMonData(&party[val], MON_DATA_HP) != 0 + && gBattlePartyID[gActiveBank] != val) + break; + } + + if (val == compareVar) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + else + gBattlescriptCurrInstr += 6; + } + else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS && GetBankSide(gActiveBank) == SIDE_OPPONENT) + { + party = gEnemyParty; + + val = 0; + if (gActiveBank == 3) + val = 3; + + for (compareVar = val + 3; val < compareVar; val++) + { + if (GetMonData(&party[val], MON_DATA_SPECIES) != SPECIES_NONE + && !GetMonData(&party[val], MON_DATA_IS_EGG) + && GetMonData(&party[val], MON_DATA_HP) != 0 + && gBattlePartyID[gActiveBank] != val) + break; + } + + if (val == compareVar) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + else + gBattlescriptCurrInstr += 6; + } + else + { + if (GetBankSide(gActiveBank) == SIDE_OPPONENT) + { + r7 = GetBankByPlayerAI(1); + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + compareVar = GetBankByPlayerAI(3); + else + compareVar = r7; + + party = gEnemyParty; + } + else + { + r7 = GetBankByPlayerAI(0); + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + compareVar = GetBankByPlayerAI(2); + else + compareVar = r7; + + party = gPlayerParty; + } + for (val = 0; val < 6; val++) + { + if (GetMonData(&party[val], MON_DATA_HP) != 0 + && GetMonData(&party[val], MON_DATA_SPECIES) != SPECIES_NONE + && !GetMonData(&party[val], MON_DATA_IS_EGG) + && val != gBattlePartyID[r7] && val != gBattlePartyID[compareVar]) + break; + } + + if (val == 6) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + else + gBattlescriptCurrInstr += 6; + } +} + +void sub_804CF10(u8 arg0) +{ + *(gBattleStruct->field_58 + gActiveBank) = gBattlePartyID[gActiveBank]; + *(gBattleStruct->field_5C + gActiveBank) = 6; + gBattleStruct->field_93 &= ~(gBitTable[gActiveBank]); + + EmitChoosePokemon(0, 1, arg0, 0, gBattleStruct->field_60[gActiveBank]); + MarkBufferBankForExecution(gActiveBank); +} diff --git a/src/pokemon_3.c b/src/pokemon_3.c index 603732a34..2bc06c580 100644 --- a/src/pokemon_3.c +++ b/src/pokemon_3.c @@ -601,9 +601,9 @@ bool8 sub_806D7EC(void) return retVal; } -bool8 sub_806D82C(u8 id) +bool16 sub_806D82C(u8 id) { - bool8 retVal = FALSE; + bool16 retVal = FALSE; switch (gLinkPlayers[id].lp_field_18) { case 0: -- cgit v1.2.3 From 52a951276f8d4b79195a0d4889503e4a7f096024 Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Mon, 25 Sep 2017 00:09:13 +0200 Subject: battle 4, up to x69 --- src/battle_4.c | 1143 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- src/pokemon_3.c | 2 +- 2 files changed, 1091 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/src/battle_4.c b/src/battle_4.c index db6d7fe53..77a4393c4 100644 --- a/src/battle_4.c +++ b/src/battle_4.c @@ -18,6 +18,12 @@ #include "text.h" #include "sound.h" #include "pokedex.h" +#include "recorded_battle.h" +#include "window.h" +#include "reshow_battle_screen.h" +#include "main.h" +#include "palette.h" +#include "money.h" // variables @@ -32,7 +38,7 @@ extern u32 gBattleExecBuffer; extern u8 gNoOfAllBanks; extern u16 gBattlePartyID[BATTLE_BANKS_COUNT]; extern u8 gTurnOrder[BATTLE_BANKS_COUNT]; -extern u8 gUnknown_02024A76[BATTLE_BANKS_COUNT]; +extern u8 gUnknown_0202407A[BATTLE_BANKS_COUNT]; extern u16 gCurrentMove; extern u8 gLastUsedAbility; extern u16 gBattleWeather; @@ -47,7 +53,6 @@ extern u16 gPaydayMoney; extern u16 gRandomTurnNumber; extern u8 gBattleOutcome; extern u8 gBattleTerrain; -extern u16 gTrainerBattleOpponent; extern u8 gBankAttacker; extern u8 gBankTarget; extern const u8* gBattlescriptCurrInstr; @@ -84,18 +89,29 @@ extern u16 gPartnerTrainerId; extern u16 gLastUsedMove; extern u16 gUnknownMovesUsedByBanks[BATTLE_BANKS_COUNT]; extern u16 gLastUsedMovesByBanks[BATTLE_BANKS_COUNT]; +extern u16 gTrainerBattleOpponent_A; +extern u16 gTrainerBattleOpponent_B; + +struct TrainerMoney +{ + u8 classId; + u8 value; +}; extern const struct BattleMove gBattleMoves[]; extern const struct BaseStats gBaseStats[]; extern const u8 gTypeEffectiveness[]; extern const u16 gMissStringIds[]; extern const u16 gTrappingMoves[]; -extern const u8 gTrainerMoney[]; +extern const struct TrainerMoney gTrainerMoneyTable[]; extern const u8* const gBattleScriptsForMoveEffects[]; // functions extern void sub_81A5718(u8 bank); // battle frontier 2 extern void sub_81A56B4(void); // battle frontier 2 +extern void sub_81BFA38(struct Pokemon* party, u8 monPartyId, u8 monCount, void (*callback)(void), u16 move); // pokemon summary screen +extern u8 sub_81C1B94(void); // pokemon summary screen +extern void IncrementGameStat(u8 statId); // rom_4 // BattleScripts extern const u8 BattleScript_MoveEnd[]; @@ -143,6 +159,12 @@ extern const u8 BattleScript_GrudgeTakesPp[]; extern const u8 BattleScript_RageIsBuilding[]; extern const u8 BattleScript_DefrostedViaFireMove[]; extern const u8 gUnknown_082DB87D[]; +extern const u8 gUnknown_082DAE90[]; +extern const u8 gUnknown_082DAE59[]; +extern const u8 gUnknown_082DAEC7[]; + +// strings +extern const u8 gText_BattleYesNoChoice[]; // read via orr #define BSScriptRead32(ptr) ((ptr)[0] | (ptr)[1] << 8 | (ptr)[2] << 16 | (ptr)[3] << 24) @@ -164,6 +186,7 @@ void DestinyBondFlagUpdate(void); u8 AttacksThisTurn(u8 bank, u16 move); // Note: returns 1 if it's a charging turn, otherwise 2. static void CheckWonderGuardAndLevitate(void); u8 ChangeStatBuffs(s8 statValue, u8 statId, u8, const u8* BS_ptr); +void sub_8056A3C(u8 arg0, u8 arg1, u8 arg2, u8 arg3, u8 arg4); void atk00_attackcanceler(void); void atk01_accuracycheck(void); @@ -255,8 +278,8 @@ void atk56_fainting_cry(void); void atk57(void); void atk58_return_to_ball(void); void atk59_learnmove_inbattle(void); -void atk5A(void); -void atk5B_80256E0(void); +void atk5A_yesnoboxlearnmove(void); +void atk5B_yesnoboxstoplearningmove(void); void atk5C_hitanimation(void); void atk5D_getmoneyreward(void); void atk5E_8025A70(void); @@ -268,9 +291,9 @@ void atk63_jumptorandomattack(void); void atk64_statusanimation(void); void atk65_status2animation(void); void atk66_chosenstatusanimation(void); -void atk67_8025ECC(void); +void atk67_yesnobox(void); void atk68_80246A0(void); -void atk69_dmg_adjustment2(void); +void atk69_dmg_adjustment3(void); void atk6A_removeitem(void); void atk6B_atknameinbuff1(void); void atk6C_lvlbox_display(void); @@ -507,8 +530,8 @@ void (* const gBattleScriptingCommandsTable[])(void) = atk57, atk58_return_to_ball, atk59_learnmove_inbattle, - atk5A, - atk5B_80256E0, + atk5A_yesnoboxlearnmove, + atk5B_yesnoboxstoplearningmove, atk5C_hitanimation, atk5D_getmoneyreward, atk5E_8025A70, @@ -520,9 +543,9 @@ void (* const gBattleScriptingCommandsTable[])(void) = atk64_statusanimation, atk65_status2animation, atk66_chosenstatusanimation, - atk67_8025ECC, + atk67_yesnobox, atk68_80246A0, - atk69_dmg_adjustment2, + atk69_dmg_adjustment3, atk6A_removeitem, atk6B_atknameinbuff1, atk6C_lvlbox_display, @@ -758,7 +781,7 @@ const u32 gStatusFlagsForMoveEffects[] = 0x00000000 }; -extern const u8* gMoveEffectBS_Ptrs[]; +extern const u8* const gMoveEffectBS_Ptrs[]; void atk00_attackcanceler(void) { @@ -2890,11 +2913,7 @@ void atk19_faint_pokemon(void) EmitSetAttributes(0, moveIndex + REQUEST_PPMOVE1_BATTLE, 0, 1, &gBattleMons[gActiveBank].pp[moveIndex]); MarkBufferBankForExecution(gActiveBank); - gBattleTextBuff1[0] = PLACEHOLDER_BEGIN; - gBattleTextBuff1[1] = 2; - gBattleTextBuff1[2] = gBattleMons[gBankAttacker].moves[moveIndex]; - gBattleTextBuff1[3] = gBattleMons[gBankAttacker].moves[moveIndex] >> 8; - gBattleTextBuff1[4] = EOS; + PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleMons[gBankAttacker].moves[moveIndex]) } } else @@ -3262,30 +3281,12 @@ void atk23_getexp(void) else gBattleStruct->expGetterBank = 0; - // buffer poke name - gBattleTextBuff1[0] = PLACEHOLDER_BEGIN; - gBattleTextBuff1[1] = 4; - gBattleTextBuff1[2] = gBattleStruct->expGetterBank; - gBattleTextBuff1[3] = gBattleStruct->expGetterId; - gBattleTextBuff1[4] = EOS; + PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBattleStruct->expGetterBank, gBattleStruct->expGetterId) // buffer 'gained' or 'gained a boosted' - gBattleTextBuff2[0] = PLACEHOLDER_BEGIN; - gBattleTextBuff2[1] = 0; - gBattleTextBuff2[2] = i; - gBattleTextBuff2[3] = (i & 0xFF00) >> 8; - gBattleTextBuff2[4] = EOS; - - // buffer exp number - gBattleTextBuff3[0] = PLACEHOLDER_BEGIN; - gBattleTextBuff3[1] = 1; - gBattleTextBuff3[2] = 4; // word - gBattleTextBuff3[3] = 5; // max digits - gBattleTextBuff3[4] = gBattleMoveDamage; - gBattleTextBuff3[5] = (gBattleMoveDamage & 0x0000FF00) >> 8; - gBattleTextBuff3[6] = (gBattleMoveDamage & 0x00FF0000) >> 16; - gBattleTextBuff3[7] = (gBattleMoveDamage & 0xFF000000) >> 24; - gBattleTextBuff3[8] = EOS; + PREPARE_STRING_BUFFER(gBattleTextBuff2, i) + + PREPARE_WORD_NUMBER_BUFFER(gBattleTextBuff3, 5, gBattleMoveDamage) PrepareStringBattle(0xD, gBattleStruct->expGetterBank); MonGainEVs(&gPlayerParty[gBattleStruct->expGetterId], gBattleMons[gBank1].species); @@ -3324,20 +3325,9 @@ void atk23_getexp(void) if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && gBattlePartyID[gActiveBank] == gBattleStruct->expGetterId) sub_805E990(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank); - // buff poke name - gBattleTextBuff1[0] = PLACEHOLDER_BEGIN; - gBattleTextBuff1[1] = 4; - gBattleTextBuff1[2] = gActiveBank; - gBattleTextBuff1[3] = gBattleStruct->expGetterId; - gBattleTextBuff1[4] = EOS; - - // buff level - gBattleTextBuff2[0] = PLACEHOLDER_BEGIN; - gBattleTextBuff2[1] = 1; - gBattleTextBuff2[2] = 1; - gBattleTextBuff2[3] = 3; - gBattleTextBuff2[4] = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL); - gBattleTextBuff2[5] = EOS; + PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gActiveBank, gBattleStruct->expGetterId) + + PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff2, 3, GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL)) BattleScriptPushCursor(); gLeveledUpInBattle |= gBitTable[gBattleStruct->expGetterId]; @@ -5280,3 +5270,1050 @@ void sub_804CF10(u8 arg0) EmitChoosePokemon(0, 1, arg0, 0, gBattleStruct->field_60[gActiveBank]); MarkBufferBankForExecution(gActiveBank); } + +void atk50_openpartyscreen(void) +{ + u32 flags; + u8 hitmarkerFaintBits; + u8 bank; + const u8 *jumpPtr; + + bank = 0; + flags = 0; + jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + + if (gBattlescriptCurrInstr[1] == 5) + { + if ((gBattleTypeFlags & (BATTLE_TYPE_DOUBLE | BATTLE_TYPE_MULTI)) != BATTLE_TYPE_DOUBLE) + { + for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++) + { + if (gHitMarker & HITMARKER_FAINTED(gActiveBank)) + { + if (sub_80423F4(gActiveBank, 6, 6)) + { + gAbsentBankFlags |= gBitTable[gActiveBank]; + gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + } + else if (!gSpecialStatuses[gActiveBank].flag40) + { + sub_804CF10(6); + gSpecialStatuses[gActiveBank].flag40 = 1; + } + } + else + { + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + } + } + } + else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + u8 flag40_0, flag40_1, flag40_2, flag40_3; + + hitmarkerFaintBits = gHitMarker >> 0x1C; + + if (gBitTable[0] & hitmarkerFaintBits) + { + gActiveBank = 0; + if (sub_80423F4(0, 6, 6)) + { + gAbsentBankFlags |= gBitTable[gActiveBank]; + gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); + Emit_x2A(0); + MarkBufferBankForExecution(gActiveBank); + } + else if (!gSpecialStatuses[gActiveBank].flag40) + { + sub_804CF10(gBattleStruct->field_5C[2]); + gSpecialStatuses[gActiveBank].flag40 = 1; + } + else + { + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + flags |= 1; + } + } + if (gBitTable[2] & hitmarkerFaintBits && !(gBitTable[0] & hitmarkerFaintBits)) + { + gActiveBank = 2; + if (sub_80423F4(2, 6, 6)) + { + gAbsentBankFlags |= gBitTable[gActiveBank]; + gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); + Emit_x2A(0); + MarkBufferBankForExecution(gActiveBank); + } + else if (!gSpecialStatuses[gActiveBank].flag40) + { + sub_804CF10(gBattleStruct->field_5C[0]); + gSpecialStatuses[gActiveBank].flag40 = 1; + } + else if (!(flags & 1)) + { + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + } + } + if (gBitTable[1] & hitmarkerFaintBits) + { + gActiveBank = 1; + if (sub_80423F4(1, 6, 6)) + { + gAbsentBankFlags |= gBitTable[gActiveBank]; + gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); + Emit_x2A(0); + MarkBufferBankForExecution(gActiveBank); + } + else if (!gSpecialStatuses[gActiveBank].flag40) + { + sub_804CF10(gBattleStruct->field_5C[3]); + gSpecialStatuses[gActiveBank].flag40 = 1; + } + else + { + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + flags |= 2; + } + } + if (gBitTable[3] & hitmarkerFaintBits && !(gBitTable[1] & hitmarkerFaintBits)) + { + gActiveBank = 3; + if (sub_80423F4(3, 6, 6)) + { + gAbsentBankFlags |= gBitTable[gActiveBank]; + gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); + Emit_x2A(0); + MarkBufferBankForExecution(gActiveBank); + } + else if (!gSpecialStatuses[gActiveBank].flag40) + { + sub_804CF10(gBattleStruct->field_5C[1]); + gSpecialStatuses[gActiveBank].flag40 = 1; + } + else if (!(flags & 2)) + { + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + } + } + + flag40_0 = gSpecialStatuses[0].flag40; + if (!flag40_0) + { + flag40_2 = gSpecialStatuses[2].flag40; + if (!flag40_2 && hitmarkerFaintBits != 0) + { + if (gAbsentBankFlags & gBitTable[0]) + gActiveBank = 2; + else + gActiveBank = 0; + + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + } + + } + flag40_1 = gSpecialStatuses[1].flag40; + if (!flag40_1) + { + flag40_3 = gSpecialStatuses[3].flag40; + if (!flag40_3 && hitmarkerFaintBits != 0) + { + if (gAbsentBankFlags & gBitTable[1]) + gActiveBank = 3; + else + gActiveBank = 1; + + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + } + } + } + gBattlescriptCurrInstr += 6; + } + else if (gBattlescriptCurrInstr[1] == 6) + { + if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI)) + { + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + hitmarkerFaintBits = gHitMarker >> 0x1C; + if (gBitTable[2] & hitmarkerFaintBits && gBitTable[0] & hitmarkerFaintBits) + { + gActiveBank = 2; + if (sub_80423F4(2, gBattleBufferB[0][1], 6)) + { + gAbsentBankFlags |= gBitTable[gActiveBank]; + gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); + Emit_x2A(0); + MarkBufferBankForExecution(gActiveBank); + } + else if (!gSpecialStatuses[gActiveBank].flag40) + { + sub_804CF10(gBattleStruct->field_5C[0]); + gSpecialStatuses[gActiveBank].flag40 = 1; + } + } + if (gBitTable[3] & hitmarkerFaintBits && hitmarkerFaintBits & gBitTable[1]) + { + gActiveBank = 3; + if (sub_80423F4(3, gBattleBufferB[1][1], 6)) + { + gAbsentBankFlags |= gBitTable[gActiveBank]; + gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); + Emit_x2A(0); + MarkBufferBankForExecution(gActiveBank); + } + else if (!gSpecialStatuses[gActiveBank].flag40) + { + sub_804CF10(gBattleStruct->field_5C[1]); + gSpecialStatuses[gActiveBank].flag40 = 1; + } + } + gBattlescriptCurrInstr += 6; + } + else + { + gBattlescriptCurrInstr += 6; + } + } + else + { + gBattlescriptCurrInstr += 6; + } + + hitmarkerFaintBits = gHitMarker >> 0x1C; + + gBank1 = 0; + while (1) + { + if (gBitTable[gBank1] & hitmarkerFaintBits) + break; + if (gBank1 >= gNoOfAllBanks) + break; + gBank1++; + } + + if (gBank1 == gNoOfAllBanks) + gBattlescriptCurrInstr = jumpPtr; + } + else + { + if (gBattlescriptCurrInstr[1] & 0x80) + hitmarkerFaintBits = 0; // used here as the caseId for the EmitChoose function + else + hitmarkerFaintBits = 1; + + bank = GetBattleBank(gBattlescriptCurrInstr[1] & ~(0x80)); + if (gSpecialStatuses[bank].flag40) + { + gBattlescriptCurrInstr += 6; + } + else if (sub_80423F4(bank, 6, 6)) + { + gActiveBank = bank; + gAbsentBankFlags |= gBitTable[gActiveBank]; + gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); + gBattlescriptCurrInstr = jumpPtr; + } + else + { + gActiveBank = bank; + *(gBattleStruct->field_58 + gActiveBank) = gBattlePartyID[gActiveBank]; + *(gBattleStruct->field_5C + gActiveBank) = 6; + gBattleStruct->field_93 &= ~(gBitTable[gActiveBank]); + + EmitChoosePokemon(0, hitmarkerFaintBits, *(gBattleStruct->field_5C + (gActiveBank ^ 2)), 0, gBattleStruct->field_60[gActiveBank]); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 6; + + if (GetBankIdentity(gActiveBank) == 0 && gBattleResults.playerSwitchesCounter < 0xFF) + gBattleResults.playerSwitchesCounter++; + + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++) + { + if (gActiveBank != bank) + { + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + } + } + } + else + { + gActiveBank = GetBankByPlayerAI(GetBankIdentity(bank) ^ 1); + if (gAbsentBankFlags & gBitTable[gActiveBank]) + gActiveBank ^= 2; + + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + } + } + } +} + +void atk51_switch_handle_order(void) +{ + s32 i; + if (gBattleExecBuffer) + return; + + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + + switch (BSScriptRead8(gBattlescriptCurrInstr + 2)) + { + case 0: + for (i = 0; i < gNoOfAllBanks; i++) + { + if (gBattleBufferB[i][0] == 0x22) + { + *(gBattleStruct->field_5C + i) = gBattleBufferB[i][1]; + if (!(gBattleStruct->field_93 & gBitTable[i])) + { + RecordedBattle_SetBankAction(i, gBattleBufferB[i][1]); + gBattleStruct->field_93 |= gBitTable[i]; + } + } + } + break; + case 1: + if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI)) + sub_803BDA0(gActiveBank); + break; + case 2: + if (!(gBattleStruct->field_93 & gBitTable[gActiveBank])) + { + RecordedBattle_SetBankAction(gActiveBank, gBattleBufferB[gActiveBank][1]); + gBattleStruct->field_93 |= gBitTable[gActiveBank]; + } + // fall through + case 3: + gBattleCommunication[0] = gBattleBufferB[gActiveBank][1]; + *(gBattleStruct->field_5C + gActiveBank) = gBattleBufferB[gActiveBank][1]; + + if ((gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_LINK)) == (BATTLE_TYPE_MULTI | BATTLE_TYPE_LINK)) + { + *(gActiveBank * 3 + (u8*)(gBattleStruct->field_60) + 0) &= 0xF; + *(gActiveBank * 3 + (u8*)(gBattleStruct->field_60) + 0) |= (gBattleBufferB[gActiveBank][2] & 0xF0); + *(gActiveBank * 3 + (u8*)(gBattleStruct->field_60) + 1) = gBattleBufferB[gActiveBank][3]; + + *((gActiveBank ^ 2) * 3 + (u8*)(gBattleStruct->field_60) + 0) &= (0xF0); + *((gActiveBank ^ 2) * 3 + (u8*)(gBattleStruct->field_60) + 0) |= (gBattleBufferB[gActiveBank][2] & 0xF0) >> 4; + *((gActiveBank ^ 2) * 3 + (u8*)(gBattleStruct->field_60) + 2) = gBattleBufferB[gActiveBank][3]; + } + else if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + { + sub_80571DC(gActiveBank, *(gBattleStruct->field_5C + gActiveBank)); + } + else + { + sub_803BDA0(gActiveBank); + } + + PREPARE_SPECIES_BUFFER(gBattleTextBuff1, gBattleMons[gBankAttacker].species) + PREPARE_MON_NICK_BUFFER(gBattleTextBuff2, gActiveBank, gBattleBufferB[gActiveBank][1]) + + break; + } + + gBattlescriptCurrInstr += 3; +} + +void atk52_switch_in_effects(void) +{ + s32 i; + + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + sub_803FA70(gActiveBank); + + gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); + gSpecialStatuses[gActiveBank].flag40 = 0; + + if (!(gSideAffecting[GetBankSide(gActiveBank)] & SIDE_STATUS_SPIKES_DAMAGED) + && (gSideAffecting[GetBankSide(gActiveBank)] & SIDE_STATUS_SPIKES) + && gBattleMons[gActiveBank].type1 != TYPE_FLYING + && gBattleMons[gActiveBank].type2 != TYPE_FLYING + && gBattleMons[gActiveBank].ability != ABILITY_LEVITATE) + { + u8 spikesDmg; + + gSideAffecting[GetBankSide(gActiveBank)] |= SIDE_STATUS_SPIKES_DAMAGED; + + gBattleMons[gActiveBank].status2 &= ~(STATUS2_DESTINY_BOND); + gHitMarker &= ~(HITMARKER_DESTINYBOND); + + spikesDmg = (5 - gSideTimers[GetBankSide(gActiveBank)].spikesAmount) * 2; + gBattleMoveDamage = gBattleMons[gActiveBank].maxHP / (spikesDmg); + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + + gBattleScripting.bank = gActiveBank; + BattleScriptPushCursor(); + + if (BSScriptRead8(gBattlescriptCurrInstr + 1) == 0) + gBattlescriptCurrInstr = gUnknown_082DAE90; + else if (BSScriptRead8(gBattlescriptCurrInstr + 1) == 1) + gBattlescriptCurrInstr = gUnknown_082DAE59; + else + gBattlescriptCurrInstr = gUnknown_082DAEC7; + } + else + { + if (gBattleMons[gActiveBank].ability == ABILITY_TRUANT && !gDisableStructs[gActiveBank].truantUnknownBit) + gDisableStructs[gActiveBank].truantCounter = 1; + + gDisableStructs[gActiveBank].truantUnknownBit = 0; + + if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, gActiveBank, 0, 0, 0) == 0 && + ItemBattleEffects(0, gActiveBank, 0) == 0) + { + gSideAffecting[GetBankSide(gActiveBank)] &= ~(SIDE_STATUS_SPIKES_DAMAGED); + + for (i = 0; i < gNoOfAllBanks; i++) + { + if (gTurnOrder[i] == gActiveBank) + gUnknown_0202407A[i] = 0xC; + } + + for (i = 0; i < gNoOfAllBanks; i++) + { + u16* hpOnSwitchout; + GET_HP_SWITCHOUT_PTR_VIA_MEME_ACCESS(GetBankSide(i), hpOnSwitchout) + *hpOnSwitchout = gBattleMons[i].hp; + } + + if (BSScriptRead8(gBattlescriptCurrInstr + 1) == 5) + { + u32 hitmarkerFaintBits = gHitMarker >> 0x1C; + + gBank1++; + while (1) + { + if (hitmarkerFaintBits & gBitTable[gBank1] && !(gAbsentBankFlags & gBitTable[gBank1])) + break; + if (gBank1 >= gNoOfAllBanks) + break; + gBank1++; + } + } + gBattlescriptCurrInstr += 2; + } + } +} + +void atk53_trainer_slide(void) +{ + gActiveBank = GetBankByPlayerAI(gBattlescriptCurrInstr[1]); + EmitTrainerSlide(0); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 2; +} + +void atk54_effectiveness_sound(void) +{ + gActiveBank = gBankAttacker; + EmitEffectivenessSound(0, BS2ScriptRead16(gBattlescriptCurrInstr + 1)); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 3; +} + +void atk55_play_sound(void) +{ + gActiveBank = gBankAttacker; + EmitPlaySound(0, BS2ScriptRead16(gBattlescriptCurrInstr + 1), 0); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 3; +} + +void atk56_fainting_cry(void) +{ + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + EmitFaintingCry(0); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 2; +} + +void atk57(void) +{ + gActiveBank = GetBankByPlayerAI(0); + Emit_x37(0, gBattleOutcome); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 1; +} + +void atk58_return_to_ball(void) +{ + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + EmitReturnPokeToBall(0, 1); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 2; +} + +void atk59_learnmove_inbattle(void) +{ + const u8* jumpPtr1 = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + const u8* jumpPtr2 = BSScriptReadPtr(gBattlescriptCurrInstr + 5); + + u16 ret = MonTryLearningNewMove(&gPlayerParty[gBattleStruct->expGetterId], BSScriptRead8(gBattlescriptCurrInstr + 9)); + while (ret == 0xFFFE) + ret = MonTryLearningNewMove(&gPlayerParty[gBattleStruct->expGetterId], 0); + + if (ret == 0) + { + gBattlescriptCurrInstr = jumpPtr2; + } + else if (ret == 0xFFFF) + { + gBattlescriptCurrInstr += 10; + } + else + { + gActiveBank = GetBankByPlayerAI(0); + + if (gBattlePartyID[gActiveBank] == gBattleStruct->expGetterId + && !(gBattleMons[gActiveBank].status2 & STATUS2_TRANSFORMED)) + { + GiveMoveToBattleMon(&gBattleMons[gActiveBank], ret); + } + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + gActiveBank = GetBankByPlayerAI(2); + if (gBattlePartyID[gActiveBank] == gBattleStruct->expGetterId + && !(gBattleMons[gActiveBank].status2 & STATUS2_TRANSFORMED)) + { + GiveMoveToBattleMon(&gBattleMons[gActiveBank], ret); + } + } + + gBattlescriptCurrInstr = jumpPtr1; + } +} + +void atk5A_yesnoboxlearnmove(void) +{ + gActiveBank = 0; + + switch (gBattleScripting.learnMoveState) + { + case 0: + sub_8056A3C(0x18, 8, 0x1D, 0xD, 0); + sub_814F9EC(gText_BattleYesNoChoice, 0xC); + gBattleScripting.learnMoveState++; + gBattleCommunication[CURSOR_POSITION] = 0; + BattleCreateCursorAt(0); + break; + case 1: + if (gMain.newKeys & DPAD_UP && gBattleCommunication[CURSOR_POSITION] != 0) + { + PlaySE(SE_SELECT); + BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); + gBattleCommunication[CURSOR_POSITION] = 0; + BattleCreateCursorAt(0); + } + if (gMain.newKeys & DPAD_DOWN && gBattleCommunication[CURSOR_POSITION] == 0) + { + PlaySE(SE_SELECT); + BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); + gBattleCommunication[CURSOR_POSITION] = 1; + BattleCreateCursorAt(1); + } + if (gMain.newKeys & A_BUTTON) + { + PlaySE(SE_SELECT); + if (gBattleCommunication[1] == 0) + { + sub_8056A3C(0x18, 0x8, 0x1D, 0xD, 1); + BeginNormalPaletteFade(-1, 0, 0, 0x10, 0); + gBattleScripting.learnMoveState++; + } + else + { + gBattleScripting.learnMoveState = 5; + } + } + else if (gMain.newKeys & B_BUTTON) + { + PlaySE(SE_SELECT); + gBattleScripting.learnMoveState = 5; + } + break; + case 2: + if (!gPaletteFade.active) + { + FreeAllWindowBuffers(); + sub_81BFA38(gPlayerParty, gBattleStruct->expGetterId, gPlayerPartyCount - 1, ReshowBattleScreenAfterMenu, gMoveToLearn); + gBattleScripting.learnMoveState++; + } + break; + case 3: + if (!gPaletteFade.active && gMain.callback2 == BattleMainCB2) + { + gBattleScripting.learnMoveState++; + } + break; + case 4: + if (!gPaletteFade.active && gMain.callback2 == BattleMainCB2) + { + u8 movePosition = sub_81C1B94(); + if (movePosition == 4) + { + gBattleScripting.learnMoveState = 5; + } + else + { + u16 moveId = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_MOVE1 + movePosition); + if (IsHMMove2(moveId)) + { + PrepareStringBattle(0x13F, gActiveBank); + gBattleScripting.learnMoveState = 6; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + + PREPARE_MOVE_BUFFER(gBattleTextBuff2, moveId) + + RemoveMonPPBonus(&gPlayerParty[gBattleStruct->expGetterId], movePosition); + SetMonMoveSlot(&gPlayerParty[gBattleStruct->expGetterId], gMoveToLearn, movePosition); + + if (gBattlePartyID[0] == gBattleStruct->expGetterId + && !(gBattleMons[0].status2 & STATUS2_TRANSFORMED) + && !(gDisableStructs[0].unk18_b & gBitTable[movePosition])) + { + RemoveBattleMonPPBonus(&gBattleMons[0], movePosition); + SetBattleMonMoveSlot(&gBattleMons[0], gMoveToLearn, movePosition); + } + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && gBattlePartyID[2] == gBattleStruct->expGetterId + && !(gBattleMons[2].status2 & STATUS2_TRANSFORMED) + && !(gDisableStructs[2].unk18_b & gBitTable[movePosition])) + { + RemoveBattleMonPPBonus(&gBattleMons[2], movePosition); + SetBattleMonMoveSlot(&gBattleMons[2], gMoveToLearn, movePosition); + } + } + } + } + break; + case 5: + sub_8056A3C(0x18, 8, 0x1D, 0xD, 1); + gBattlescriptCurrInstr += 5; + break; + case 6: + if (gBattleExecBuffer == 0) + { + gBattleScripting.learnMoveState = 2; + } + break; + } +} + +void atk5B_yesnoboxstoplearningmove(void) +{ + switch (gBattleScripting.learnMoveState) + { + case 0: + sub_8056A3C(0x18, 8, 0x1D, 0xD, 0); + sub_814F9EC(gText_BattleYesNoChoice, 0xC); + gBattleScripting.learnMoveState++; + gBattleCommunication[CURSOR_POSITION] = 0; + BattleCreateCursorAt(0); + break; + case 1: + if (gMain.newKeys & DPAD_UP && gBattleCommunication[CURSOR_POSITION] != 0) + { + PlaySE(SE_SELECT); + BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); + gBattleCommunication[CURSOR_POSITION] = 0; + BattleCreateCursorAt(0); + } + if (gMain.newKeys & DPAD_DOWN && gBattleCommunication[CURSOR_POSITION] == 0) + { + PlaySE(SE_SELECT); + BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); + gBattleCommunication[CURSOR_POSITION] = 1; + BattleCreateCursorAt(1); + } + if (gMain.newKeys & A_BUTTON) + { + PlaySE(SE_SELECT); + + if (gBattleCommunication[1] != 0) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + else + gBattlescriptCurrInstr += 5; + + sub_8056A3C(0x18, 0x8, 0x1D, 0xD, 1); + } + else if (gMain.newKeys & B_BUTTON) + { + PlaySE(SE_SELECT); + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + sub_8056A3C(0x18, 0x8, 0x1D, 0xD, 1); + } + break; + } +} + +void atk5C_hitanimation(void) +{ + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + + if (gBattleMoveFlags & MOVESTATUS_NOEFFECT) + { + gBattlescriptCurrInstr += 2; + } + else if (!(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE) || !(gBattleMons[gActiveBank].status2 & STATUS2_SUBSTITUTE) || gDisableStructs[gActiveBank].substituteHP == 0) + { + EmitHitAnimation(0); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 2; + } + else + { + gBattlescriptCurrInstr += 2; + } +} + +static u32 GetTrainerMoneyToGive(u16 trainerId) +{ + u32 i = 0; + u32 lastMonLevel = 0; + u32 moneyReward = 0; + + if (trainerId == SECRET_BASE_OPPONENT) + { + moneyReward = 20 * gBattleResources->secretBase->partyLevels[0] * gBattleStruct->moneyMultiplier; + } + else + { + switch (gTrainers[trainerId].partyFlags) + { + case 0: + { + const struct TrainerMonNoItemDefaultMoves *party = gTrainers[trainerId].party.NoItemDefaultMoves; + lastMonLevel = party[gTrainers[trainerId].partySize - 1].lvl; + } + break; + case PARTY_FLAG_CUSTOM_MOVES: + { + const struct TrainerMonNoItemCustomMoves *party = gTrainers[trainerId].party.NoItemCustomMoves; + lastMonLevel = party[gTrainers[trainerId].partySize - 1].lvl; + } + break; + case PARTY_FLAG_HAS_ITEM: + { + const struct TrainerMonItemDefaultMoves *party = gTrainers[trainerId].party.ItemDefaultMoves; + lastMonLevel = party[gTrainers[trainerId].partySize - 1].lvl; + } + break; + case PARTY_FLAG_CUSTOM_MOVES | PARTY_FLAG_HAS_ITEM: + { + const struct TrainerMonItemCustomMoves *party = gTrainers[trainerId].party.ItemCustomMoves; + lastMonLevel = party[gTrainers[trainerId].partySize - 1].lvl; + } + break; + } + + for (; gTrainerMoneyTable[i].classId != 0xFF; i++) + { + if (gTrainerMoneyTable[i].classId == gTrainers[trainerId].trainerClass) + break; + } + + if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + moneyReward = 4 * lastMonLevel * gBattleStruct->moneyMultiplier * gTrainerMoneyTable[i].value; + else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + moneyReward = 4 * lastMonLevel * gBattleStruct->moneyMultiplier * 2 * gTrainerMoneyTable[i].value; + else + moneyReward = 4 * lastMonLevel * gBattleStruct->moneyMultiplier * gTrainerMoneyTable[i].value; + } + + return moneyReward; +} + +void atk5D_getmoneyreward(void) +{ + u32 moneyReward = GetTrainerMoneyToGive(gTrainerBattleOpponent_A); + if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + moneyReward += GetTrainerMoneyToGive(gTrainerBattleOpponent_B); + + AddMoney(&gSaveBlock1Ptr->money, moneyReward); + + PREPARE_WORD_NUMBER_BUFFER(gBattleTextBuff1, 5, moneyReward) + + gBattlescriptCurrInstr++; +} + +void atk5E_8025A70(void) +{ + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + + switch (gBattleCommunication[0]) + { + case 0: + EmitGetAttributes(0, REQUEST_ALL_BATTLE, 0); + MarkBufferBankForExecution(gActiveBank); + gBattleCommunication[0]++; + break; + case 1: + if (gBattleExecBuffer == 0) + { + s32 i; + struct BattlePokemon* bufferPoke = (struct BattlePokemon*) &gBattleBufferB[gActiveBank][4]; + for (i = 0; i < 4; i++) + { + gBattleMons[gActiveBank].moves[i] = bufferPoke->moves[i]; + gBattleMons[gActiveBank].pp[i] = bufferPoke->pp[i]; + } + gBattlescriptCurrInstr += 2; + } + break; + } +} + +void atk5F_8025B24(void) +{ + gActiveBank = gBankAttacker; + gBankAttacker = gBankTarget; + gBankTarget = gActiveBank; + + if (gHitMarker & HITMARKER_PURSUIT_TRAP) + gHitMarker &= ~(HITMARKER_PURSUIT_TRAP); + else + gHitMarker |= HITMARKER_PURSUIT_TRAP; + + gBattlescriptCurrInstr++; +} + +void atk60_increment_gamestat(void) +{ + if (GetBankSide(gBankAttacker) == SIDE_PLAYER) + IncrementGameStat(BSScriptRead8(gBattlescriptCurrInstr + 1)); + + gBattlescriptCurrInstr += 2; +} + +void atk61_8025BA4(void) +{ + s32 i; + struct Pokemon* party; + struct HpAndStatus hpStatuses[6]; + + if (gBattleExecBuffer) + return; + + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + + if (GetBankSide(gActiveBank) == SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + for (i = 0; i < 6; i++) + { + if (GetMonData(&party[i], MON_DATA_SPECIES2) == SPECIES_NONE + || GetMonData(&party[i], MON_DATA_SPECIES2) == SPECIES_EGG) + { + hpStatuses[i].hp = 0xFFFF; + hpStatuses[i].status = 0; + } + else + { + hpStatuses[i].hp = GetMonData(&party[i], MON_DATA_HP); + hpStatuses[i].status = GetMonData(&party[i], MON_DATA_STATUS); + } + } + + EmitCmd48(0, hpStatuses, 1); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 2; +} + +void atk62_08025C6C(void) +{ + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + EmitCmd49(0); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 2; +} + +void atk63_jumptorandomattack(void) +{ + if (BSScriptRead8(gBattlescriptCurrInstr + 1) != 0) + gCurrentMove = gRandomMove; + else + gLastUsedMove = gCurrentMove = gRandomMove; + + gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]; +} + +void atk64_statusanimation(void) +{ + if (gBattleExecBuffer == 0) + { + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + if (!(gStatuses3[gActiveBank] & STATUS3_SEMI_INVULNERABLE) + && gDisableStructs[gActiveBank].substituteHP == 0 + && !(gHitMarker & HITMARKER_NO_ANIMATIONS)) + { + EmitStatusAnimation(0, FALSE, gBattleMons[gActiveBank].status1); + MarkBufferBankForExecution(gActiveBank); + } + gBattlescriptCurrInstr += 2; + } +} + +void atk65_status2animation(void) +{ + u32 wantedToAnimate; + + if (gBattleExecBuffer == 0) + { + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + wantedToAnimate = BSScriptRead32(gBattlescriptCurrInstr + 2); + if (!(gStatuses3[gActiveBank] & STATUS3_SEMI_INVULNERABLE) + && gDisableStructs[gActiveBank].substituteHP == 0 + && !(gHitMarker & HITMARKER_NO_ANIMATIONS)) + { + EmitStatusAnimation(0, TRUE, gBattleMons[gActiveBank].status2 & wantedToAnimate); + MarkBufferBankForExecution(gActiveBank); + } + gBattlescriptCurrInstr += 6; + } +} + +void atk66_chosenstatusanimation(void) +{ + u32 wantedStatus; + + if (gBattleExecBuffer == 0) + { + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + wantedStatus = BSScriptRead32(gBattlescriptCurrInstr + 3); + if (!(gStatuses3[gActiveBank] & STATUS3_SEMI_INVULNERABLE) + && gDisableStructs[gActiveBank].substituteHP == 0 + && !(gHitMarker & HITMARKER_NO_ANIMATIONS)) + { + EmitStatusAnimation(0, BSScriptRead8(gBattlescriptCurrInstr + 2), wantedStatus); + MarkBufferBankForExecution(gActiveBank); + } + gBattlescriptCurrInstr += 7; + } +} + +void atk67_yesnobox(void) +{ + switch (gBattleCommunication[0]) + { + case 0: + sub_8056A3C(0x18, 8, 0x1D, 0xD, 0); + sub_814F9EC(gText_BattleYesNoChoice, 0xC); + gBattleCommunication[0]++; + gBattleCommunication[CURSOR_POSITION] = 0; + BattleCreateCursorAt(0); + break; + case 1: + if (gMain.newKeys & DPAD_UP && gBattleCommunication[CURSOR_POSITION] != 0) + { + PlaySE(SE_SELECT); + BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); + gBattleCommunication[CURSOR_POSITION] = 0; + BattleCreateCursorAt(0); + } + if (gMain.newKeys & DPAD_DOWN && gBattleCommunication[CURSOR_POSITION] == 0) + { + PlaySE(SE_SELECT); + BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); + gBattleCommunication[CURSOR_POSITION] = 1; + BattleCreateCursorAt(1); + } + if (gMain.newKeys & B_BUTTON) + { + gBattleCommunication[CURSOR_POSITION] = 1; + PlaySE(SE_SELECT); + sub_8056A3C(0x18, 8, 0x1D, 0xD, 1); + gBattlescriptCurrInstr++; + } + else if (gMain.newKeys & A_BUTTON) + { + PlaySE(SE_SELECT); + sub_8056A3C(0x18, 8, 0x1D, 0xD, 1); + gBattlescriptCurrInstr++; + } + break; + } +} + +void atk68_80246A0(void) +{ + s32 i; + + for (i = 0; i < gNoOfAllBanks; i++) + gUnknown_0202407A[i] = 0xC; + + gBattlescriptCurrInstr++; +} + +void atk69_dmg_adjustment3(void) // The same as 0x7, except there's no random damage multiplier. +{ + u8 holdEffect, quality; + + if (gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY) + { + holdEffect = gEnigmaBerries[gBankTarget].holdEffect, quality = gEnigmaBerries[gBankTarget].holdEffectParam; + } + else + { + holdEffect = ItemId_GetHoldEffect(gBattleMons[gBankTarget].item); + quality = ItemId_GetHoldEffectParam(gBattleMons[gBankTarget].item); + } + + gStringBank = gBankTarget; + + if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < quality) + { + RecordItemEffectBattle(gBankTarget, holdEffect); + gSpecialStatuses[gBankTarget].focusBanded = 1; + } + if (gBattleMons[gBankTarget].status2 & STATUS2_SUBSTITUTE) + goto END; + if (gBattleMoves[gCurrentMove].effect != EFFECT_FALSE_SWIPE && !gProtectStructs[gBankTarget].endured + && !gSpecialStatuses[gBankTarget].focusBanded) + goto END; + + if (gBattleMons[gBankTarget].hp > gBattleMoveDamage) + goto END; + + gBattleMoveDamage = gBattleMons[gBankTarget].hp - 1; + + if (gProtectStructs[gBankTarget].endured) + { + gBattleMoveFlags |= MOVESTATUS_ENDURED; + } + else if (gSpecialStatuses[gBankTarget].focusBanded) + { + gBattleMoveFlags |= MOVESTATUS_HUNGON; + gLastUsedItem = gBattleMons[gBankTarget].item; + } + + END: + gBattlescriptCurrInstr++; +} diff --git a/src/pokemon_3.c b/src/pokemon_3.c index 2bc06c580..aaa02c5d4 100644 --- a/src/pokemon_3.c +++ b/src/pokemon_3.c @@ -1374,7 +1374,7 @@ void sub_806E994(void) gBattleTextBuff2[2] = gBankInMenu; gBattleTextBuff2[3] = pokemon_order_func(gBattlePartyID[gBankInMenu]); gBattleTextBuff2[4] = EOS; - StrCpyDecodeBattle(gText_PkmnsXPreventsSwitching, gStringVar4); + BattleStringExpandPlaceholders(gText_PkmnsXPreventsSwitching, gStringVar4); } struct PokeItem -- cgit v1.2.3 From d769ec137447c52062b48153851bd2824055b6df Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Tue, 26 Sep 2017 22:39:59 +0200 Subject: battle 4 up to a8 --- src/battle_3.c | 52 +- src/battle_4.c | 2739 ++++++++++++++++++++++++++++++++++++++++++- src/battle_ai.c | 2 +- src/calculate_base_damage.c | 1 - src/pokemon_2.c | 10 +- src/pokemon_3.c | 6 +- src/window.c | 2 +- 7 files changed, 2734 insertions(+), 78 deletions(-) (limited to 'src') diff --git a/src/battle_3.c b/src/battle_3.c index 1b443118d..1fd84a61b 100644 --- a/src/battle_3.c +++ b/src/battle_3.c @@ -831,7 +831,7 @@ u8 TurnBasedEffects(void) gBattleCommunication[MULTISTRING_CHOOSER] = 1; b_call_bc_move_exec(gUnknown_082DB234); gActiveBank = gBankAttacker; - EmitSetAttributes(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); MarkBufferBankForExecution(gActiveBank); break; } @@ -956,7 +956,7 @@ u8 TurnBasedEffects(void) { CancelMultiTurnMoves(gActiveBank); gBattleMons[gActiveBank].status1 |= (Random() & 3) + 2; - EmitSetAttributes(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); MarkBufferBankForExecution(gActiveBank); gEffectBank = gActiveBank; b_call_bc_move_exec(BattleScript_YawnMakesAsleep); @@ -1446,7 +1446,7 @@ u8 AtkCanceller_UnableToUseMove(void) if (effect == 2) { gActiveBank = gBankAttacker; - EmitSetAttributes(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); MarkBufferBankForExecution(gActiveBank); } return effect; @@ -1539,14 +1539,14 @@ bool8 sub_80423F4(u8 bank, u8 r1, u8 r2) { if (GetBankSide(bank) == SIDE_OPPONENT) { - r7 = GetBankByPlayerAI(1); - r6 = GetBankByPlayerAI(3); + r7 = GetBankByIdentity(1); + r6 = GetBankByIdentity(3); party = gEnemyParty; } else { - r7 = GetBankByPlayerAI(0); - r6 = GetBankByPlayerAI(2); + r7 = GetBankByIdentity(0); + r6 = GetBankByIdentity(2); party = gPlayerParty; } if (r1 == 6) @@ -1835,7 +1835,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) gBattleMons[bank].status2 &= ~(STATUS2_NIGHTMARE); // fix nighmare glitch gBattleScripting.bank = gActiveBank = bank; b_push_move_exec(BattleScript_ShedSkinActivates); - EmitSetAttributes(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[bank].status1); + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[bank].status1); MarkBufferBankForExecution(gActiveBank); effect++; } @@ -2156,7 +2156,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) gBattlescriptCurrInstr = gUnknown_082DB68C; gBattleScripting.bank = i; gActiveBank = i; - EmitSetAttributes(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); MarkBufferBankForExecution(gActiveBank); return effect; } @@ -2235,14 +2235,14 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) if (gBattleMons[i].ability == ABILITY_TRACE && (gStatuses3[i] & STATUS3_TRACE)) { u8 opposite = (GetBankIdentity(i) ^ 1) & 1; - u8 target1 = GetBankByPlayerAI(opposite); - u8 target2 = GetBankByPlayerAI(opposite + 2); + u8 target1 = GetBankByIdentity(opposite); + u8 target2 = GetBankByIdentity(opposite + 2); if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) { if (gBattleMons[target1].ability != 0 && gBattleMons[target1].hp != 0 && gBattleMons[target2].ability != 0 && gBattleMons[target2].hp != 0) { - gActiveBank = GetBankByPlayerAI(((Random() & 1) * 2) | opposite); + gActiveBank = GetBankByIdentity(((Random() & 1) * 2) | opposite); gBattleMons[i].ability = gBattleMons[gActiveBank].ability; gLastUsedAbility = gBattleMons[gActiveBank].ability; effect++; @@ -3106,7 +3106,7 @@ _08042E24:\n\ movs r1, 0x28\n\ movs r2, 0\n\ movs r3, 0x4\n\ - bl EmitSetAttributes\n\ + bl EmitSetMonData\n\ ldrb r0, [r4]\n\ bl MarkBufferBankForExecution\n\ bl _080443D0\n\ @@ -4500,7 +4500,7 @@ _08043BFC:\n\ movs r1, 0x28\n\ movs r2, 0\n\ movs r3, 0x4\n\ - bl EmitSetAttributes\n\ + bl EmitSetMonData\n\ ldrb r0, [r4]\n\ bl MarkBufferBankForExecution\n\ bl _0804443A\n\ @@ -4744,11 +4744,11 @@ _08043E42:\n\ eors r5, r1\n\ ands r5, r1\n\ adds r0, r5, 0\n\ - bl GetBankByPlayerAI\n\ + bl GetBankByIdentity\n\ lsls r0, 24\n\ lsrs r6, r0, 24\n\ adds r0, r5, 0x2\n\ - bl GetBankByPlayerAI\n\ + bl GetBankByIdentity\n\ lsls r0, 24\n\ lsrs r7, r0, 24\n\ ldr r0, =gBattleTypeFlags\n\ @@ -4792,7 +4792,7 @@ _08043E74:\n\ lsls r1, 1\n\ orrs r5, r1\n\ adds r0, r5, 0\n\ - bl GetBankByPlayerAI\n\ + bl GetBankByIdentity\n\ mov r2, r8\n\ strb r0, [r2]\n\ ldrb r0, [r2]\n\ @@ -5609,7 +5609,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleTextBuff1[3] = move >> 8; gBattleTextBuff1[4] = 0xFF; b_call_bc_move_exec(BattleScript_BerryPPHealEnd2); - EmitSetAttributes(0, i + REQUEST_PPMOVE1_BATTLE, 0, 1, &changedPP); + EmitSetMonData(0, i + REQUEST_PPMOVE1_BATTLE, 0, 1, &changedPP); MarkBufferBankForExecution(gActiveBank); effect = ITEM_PP_CHANGE; } @@ -5993,7 +5993,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) switch (effect) { case ITEM_STATUS_CHANGE: - EmitSetAttributes(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[bank].status1); + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[bank].status1); MarkBufferBankForExecution(gActiveBank); break; case ITEM_PP_CHANGE: @@ -6148,7 +6148,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleScripting.bank = bank; gStringBank = bank; gActiveBank = bank; - EmitSetAttributes(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); MarkBufferBankForExecution(gActiveBank); break; } @@ -6251,7 +6251,7 @@ u8 GetMoveTarget(u16 move, u8 useMoveTarget) case MOVE_TARGET_BOTH: case MOVE_TARGET_FOES_AND_ALLY: case MOVE_TARGET_OPPONENTS_FIELD: - targetBank = GetBankByPlayerAI((GetBankIdentity(gBankAttacker) & 1) ^ 1); + targetBank = GetBankByIdentity((GetBankIdentity(gBankAttacker) & 1) ^ 1); if (gAbsentBankFlags & gBitTable[targetBank]) targetBank ^= 2; break; @@ -6264,22 +6264,22 @@ u8 GetMoveTarget(u16 move, u8 useMoveTarget) if (GetBankSide(gBankAttacker) == SIDE_PLAYER) { if (Random() & 1) - targetBank = GetBankByPlayerAI(1); + targetBank = GetBankByIdentity(1); else - targetBank = GetBankByPlayerAI(3); + targetBank = GetBankByIdentity(3); } else { if (Random() & 1) - targetBank = GetBankByPlayerAI(0); + targetBank = GetBankByIdentity(0); else - targetBank = GetBankByPlayerAI(2); + targetBank = GetBankByIdentity(2); } if (gAbsentBankFlags & gBitTable[targetBank]) targetBank ^= 2; } else - targetBank = GetBankByPlayerAI((GetBankIdentity(gBankAttacker) & 1) ^ 1); + targetBank = GetBankByIdentity((GetBankIdentity(gBankAttacker) & 1) ^ 1); break; case MOVE_TARGET_USER: case MOVE_TARGET_x10: diff --git a/src/battle_4.c b/src/battle_4.c index 77a4393c4..0f52ee0dd 100644 --- a/src/battle_4.c +++ b/src/battle_4.c @@ -24,6 +24,11 @@ #include "main.h" #include "palette.h" #include "money.h" +#include "bg.h" +#include "string_util.h" +#include "pokemon_icon.h" +#include "pokemon_item_effects.h" +#include "m4a.h" // variables @@ -91,6 +96,7 @@ extern u16 gUnknownMovesUsedByBanks[BATTLE_BANKS_COUNT]; extern u16 gLastUsedMovesByBanks[BATTLE_BANKS_COUNT]; extern u16 gTrainerBattleOpponent_A; extern u16 gTrainerBattleOpponent_B; +extern struct MusicPlayerInfo gMPlay_BGM; struct TrainerMoney { @@ -112,6 +118,15 @@ extern void sub_81A56B4(void); // battle frontier 2 extern void sub_81BFA38(struct Pokemon* party, u8 monPartyId, u8 monCount, void (*callback)(void), u16 move); // pokemon summary screen extern u8 sub_81C1B94(void); // pokemon summary screen extern void IncrementGameStat(u8 statId); // rom_4 +extern void sub_81D388C(struct Pokemon* mon, void* statStoreLocation); // pokenav.s +extern void sub_81D3640(u8 arg0, void* statStoreLocation1, void* statStoreLocation2, u8 arg3, u8 arg4, u8 arg5); // pokenav.s +extern void sub_81D3784(u8 arg0, void* statStoreLocation1, u8 arg2, u8 arg3, u8 arg4); // pokenav.s +extern u8* GetMonNickname(struct Pokemon* mon, u8* dst); // party_menu +extern u8 sub_81A5258(u8* arg0); // battle frontier 2 +extern void sub_81A5BF8(void); // battle frontier 2 +extern void sub_81A5D44(void); // battle frontier 2 +extern void sub_81B8E80(u8 bank, u8, u8); // party menu +extern bool8 sub_81B1250(void); // ? // BattleScripts extern const u8 BattleScript_MoveEnd[]; @@ -162,6 +177,26 @@ extern const u8 gUnknown_082DB87D[]; extern const u8 gUnknown_082DAE90[]; extern const u8 gUnknown_082DAE59[]; extern const u8 gUnknown_082DAEC7[]; +extern const u8 BattleScript_MoveEffectSleep[]; +extern const u8 BattleScript_MoveEffectPoison[]; +extern const u8 BattleScript_MoveEffectBurn[]; +extern const u8 BattleScript_MoveEffectFreeze[]; +extern const u8 BattleScript_MoveEffectParalysis[]; +extern const u8 BattleScript_MoveEffectToxic[]; +extern const u8 BattleScript_MoveEffectConfusion[]; +extern const u8 BattleScript_MoveEffectUproar[]; +extern const u8 BattleScript_MoveEffectPayDay[]; +extern const u8 BattleScript_MoveEffectWrap[]; +extern const u8 BattleScript_MoveEffectRecoil33[]; +extern const u8 BattleScript_DampStopsExplosion[]; +extern const u8 BattleScript_MistProtected[]; +extern const u8 BattleScript_AbilityNoStatLoss[]; +extern const u8 BattleScript_AbilityNoSpecificStatLoss[]; +extern const u8 BattleScript_ButItFailed[]; +extern const u8 gUnknown_082DADD8[]; +extern const u8 BattleScript_PrintPayDayMoneyString[]; +extern const u8 BattleScript_SturdyPreventsOHKO[]; +extern const u8 BattleScript_ObliviousPreventsAttraction[]; // strings extern const u8 gText_BattleYesNoChoice[]; @@ -187,6 +222,14 @@ u8 AttacksThisTurn(u8 bank, u16 move); // Note: returns 1 if it's a charging tur static void CheckWonderGuardAndLevitate(void); u8 ChangeStatBuffs(s8 statValue, u8 statId, u8, const u8* BS_ptr); void sub_8056A3C(u8 arg0, u8 arg1, u8 arg2, u8 arg3, u8 arg4); +bool32 IsMonGettingExpSentOut(void); +void sub_804F17C(void); +bool8 sub_804F1CC(void); +void sub_804F100(void); +void sub_804F144(void); +bool8 sub_804F344(void); +void PutMonIconOnLvlUpBox(void); +void PutLevelAndGenderOnLvlUpBox(void); void atk00_attackcanceler(void); void atk01_accuracycheck(void); @@ -296,23 +339,23 @@ void atk68_80246A0(void); void atk69_dmg_adjustment3(void); void atk6A_removeitem(void); void atk6B_atknameinbuff1(void); -void atk6C_lvlbox_display(void); -void atk6D_set_sentpokes_values(void); +void atk6C_draw_lvlupbox(void); +void atk6D_reset_sentpokes_value(void); void atk6E_set_atk_to_player0(void); void atk6F_set_visible(void); -void atk70_record_ability(void); +void atk70_record_last_used_ability(void); void atk71_buffer_move_to_learn(void); void atk72_jump_if_can_run_frombattle(void); void atk73_hp_thresholds(void); void atk74_hp_thresholds2(void); -void atk75_8026A58(void); +void atk75_item_effect_on_opponent(void); void atk76_various(void); -void atk77_setprotect(void); +void atk77_set_protect_like(void); void atk78_faintifabilitynotdamp(void); void atk79_setatkhptozero(void); void atk7A_jumpwhiletargetvalid(void); void atk7B_healhalfHP_if_possible(void); -void atk7C_8025508(void); +void atk7C_trymirrormove(void); void atk7D_set_rain(void); void atk7E_setreflect(void); void atk7F_setseeded(void); @@ -330,13 +373,13 @@ void atk8A_normalisebuffs(void); void atk8B_setbide(void); void atk8C_confuseifrepeatingattackends(void); void atk8D_setmultihit_counter(void); -void atk8E_prepare_multihit(void); +void atk8E_init_multihit_string(void); void atk8F_forcerandomswitch(void); void atk90_conversion_type_change(void); void atk91_givepaydaymoney(void); void atk92_setlightscreen(void); void atk93_ko_move(void); -void atk94_gethalfcurrentenemyhp(void); +void atk94_damagetohalftargethp(void); void atk95_setsandstorm(void); void atk96_weatherdamage(void); void atk97_try_infatuation(void); @@ -345,7 +388,7 @@ void atk99_setmist(void); void atk9A_set_focusenergy(void); void atk9B_transformdataexecution(void); void atk9C_set_substitute(void); -void atk9D_copyattack(void); +void atk9D_mimicattackcopy(void); void atk9E_metronome(void); void atk9F_dmgtolevel(void); void atkA0_psywavedamageeffect(void); @@ -548,23 +591,23 @@ void (* const gBattleScriptingCommandsTable[])(void) = atk69_dmg_adjustment3, atk6A_removeitem, atk6B_atknameinbuff1, - atk6C_lvlbox_display, - atk6D_set_sentpokes_values, + atk6C_draw_lvlupbox, + atk6D_reset_sentpokes_value, atk6E_set_atk_to_player0, atk6F_set_visible, - atk70_record_ability, + atk70_record_last_used_ability, atk71_buffer_move_to_learn, atk72_jump_if_can_run_frombattle, atk73_hp_thresholds, atk74_hp_thresholds2, - atk75_8026A58, + atk75_item_effect_on_opponent, atk76_various, - atk77_setprotect, + atk77_set_protect_like, atk78_faintifabilitynotdamp, atk79_setatkhptozero, atk7A_jumpwhiletargetvalid, atk7B_healhalfHP_if_possible, - atk7C_8025508, + atk7C_trymirrormove, atk7D_set_rain, atk7E_setreflect, atk7F_setseeded, @@ -582,13 +625,13 @@ void (* const gBattleScriptingCommandsTable[])(void) = atk8B_setbide, atk8C_confuseifrepeatingattackends, atk8D_setmultihit_counter, - atk8E_prepare_multihit, + atk8E_init_multihit_string, atk8F_forcerandomswitch, atk90_conversion_type_change, atk91_givepaydaymoney, atk92_setlightscreen, atk93_ko_move, - atk94_gethalfcurrentenemyhp, + atk94_damagetohalftargethp, atk95_setsandstorm, atk96_weatherdamage, atk97_try_infatuation, @@ -597,7 +640,7 @@ void (* const gBattleScriptingCommandsTable[])(void) = atk9A_set_focusenergy, atk9B_transformdataexecution, atk9C_set_substitute, - atk9D_copyattack, + atk9D_mimicattackcopy, atk9E_metronome, atk9F_dmgtolevel, atkA0_psywavedamageeffect, @@ -781,7 +824,53 @@ const u32 gStatusFlagsForMoveEffects[] = 0x00000000 }; -extern const u8* const gMoveEffectBS_Ptrs[]; +const u8* const gMoveEffectBS_Ptrs[] = +{ + BattleScript_MoveEffectSleep, // 0 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_SLEEP + BattleScript_MoveEffectPoison, // MOVE_EFFECT_POISON + BattleScript_MoveEffectBurn, // MOVE_EFFECT_BURN + BattleScript_MoveEffectFreeze, // MOVE_EFFECT_FREEZE + BattleScript_MoveEffectParalysis, // MOVE_EFFECT_PARALYSIS + BattleScript_MoveEffectToxic, // MOVE_EFFECT_TOXIC + BattleScript_MoveEffectConfusion, // MOVE_EFFECT_CONFUSION + BattleScript_MoveEffectSleep, // MOVE_EFFECT_FLINCH + BattleScript_MoveEffectSleep, // MOVE_EFFECT_TRI_ATTACK + BattleScript_MoveEffectUproar, // MOVE_EFFECT_UPROAR + BattleScript_MoveEffectPayDay, // MOVE_EFFECT_PAYDAY + BattleScript_MoveEffectSleep, // MOVE_EFFECT_CHARGING + BattleScript_MoveEffectWrap, // MOVE_EFFECT_WRAP + BattleScript_MoveEffectRecoil33, // MOVE_EFFECT_RECOIL_25 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_ATK_PLUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_DEF_PLUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_SPD_PLUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_SP_ATK_PLUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_SP_DEF_PLUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_ACC_PLUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_EVS_PLUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_ATK_MINUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_DEF_MINUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_SPD_MINUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_SP_ATK_MINUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_SP_DEF_MINUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_ACC_MINUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_EVS_MINUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_RECHARGE + BattleScript_MoveEffectSleep, // MOVE_EFFECT_RAGE + BattleScript_MoveEffectSleep, // MOVE_EFFECT_STEAL_ITEM + BattleScript_MoveEffectSleep, // MOVE_EFFECT_PREVENT_ESCAPE + BattleScript_MoveEffectSleep, // MOVE_EFFECT_NIGHTMARE + BattleScript_MoveEffectSleep, // MOVE_EFFECT_ALL_STATS_UP + BattleScript_MoveEffectSleep, // MOVE_EFFECT_RAPIDSPIN + BattleScript_MoveEffectSleep, // MOVE_EFFECT_REMOVE_PARALYSIS + BattleScript_MoveEffectSleep, // MOVE_EFFECT_ATK_DEF_DOWN + BattleScript_MoveEffectRecoil33, // MOVE_EFFECT_RECOIL_33_PARALYSIS +}; + +static const struct WindowTemplate sUnusedWinTemplate = {0, 1, 3, 7, 0xF, 0x1F, 0x3F}; + +extern const struct SpriteTemplate SpriteTemplate_MonIconOnLvlUpBox; +extern const u16 sProtectSuccessRates[]; void atk00_attackcanceler(void) { @@ -1110,7 +1199,7 @@ void atk03_ppreduce(void) && !((gDisableStructs[gBankAttacker].unk18_b) & gBitTable[gCurrMovePos])) { gActiveBank = gBankAttacker; - EmitSetAttributes(0, REQUEST_PPMOVE1_BATTLE + gCurrMovePos, 0, 1, &gBattleMons[gBankAttacker].pp[gCurrMovePos]); + EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + gCurrMovePos, 0, 1, &gBattleMons[gBankAttacker].pp[gCurrMovePos]); MarkBufferBankForExecution(gBankAttacker); } } @@ -1828,7 +1917,7 @@ void atk0C_datahpupdate(void) } } gHitMarker &= ~(HITMARKER_x100000); - EmitSetAttributes(0, REQUEST_HP_BATTLE, 0, 2, &gBattleMons[gActiveBank].hp); + EmitSetMonData(0, REQUEST_HP_BATTLE, 0, 2, &gBattleMons[gActiveBank].hp); MarkBufferBankForExecution(gActiveBank); } } @@ -2351,7 +2440,7 @@ void SetMoveEffect(bool8 primary, u8 certain) gBattlescriptCurrInstr = gMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; gActiveBank = gEffectBank; - EmitSetAttributes(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gEffectBank].status1); + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gEffectBank].status1); MarkBufferBankForExecution(gActiveBank); if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) @@ -2660,11 +2749,11 @@ void SetMoveEffect(bool8 primary, u8 certain) gBattleMons[gBankTarget].item = 0; gActiveBank = gBankAttacker; - EmitSetAttributes(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gLastUsedItem); + EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gLastUsedItem); MarkBufferBankForExecution(gBankAttacker); gActiveBank = gBankTarget; - EmitSetAttributes(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gBankTarget].item); + EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gBankTarget].item); MarkBufferBankForExecution(gBankTarget); BattleScriptPush(gBattlescriptCurrInstr + 1); @@ -2703,7 +2792,7 @@ void SetMoveEffect(bool8 primary, u8 certain) gBattleMons[gBankTarget].status1 &= ~(STATUS_PARALYSIS); gActiveBank = gBankTarget; - EmitSetAttributes(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); MarkBufferBankForExecution(gActiveBank); BattleScriptPush(gBattlescriptCurrInstr + 1); @@ -2910,7 +2999,7 @@ void atk19_faint_pokemon(void) BattleScriptPush(gBattlescriptCurrInstr); gBattlescriptCurrInstr = BattleScript_GrudgeTakesPp; gActiveBank = gBankAttacker; - EmitSetAttributes(0, moveIndex + REQUEST_PPMOVE1_BATTLE, 0, 1, &gBattleMons[gActiveBank].pp[moveIndex]); + EmitSetMonData(0, moveIndex + REQUEST_PPMOVE1_BATTLE, 0, 1, &gBattleMons[gActiveBank].pp[moveIndex]); MarkBufferBankForExecution(gActiveBank); PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleMons[gBankAttacker].moves[moveIndex]) @@ -2943,7 +3032,7 @@ void atk1B_faint_effects_clear(void) if (!(gBattleTypeFlags & BATTLE_TYPE_ARENA) || gBattleMons[gActiveBank].hp == 0) { gBattleMons[gActiveBank].status1 = 0; - EmitSetAttributes(0, REQUEST_STATUS_BATTLE, 0, 0x4, &gBattleMons[gActiveBank].status1); + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 0x4, &gBattleMons[gActiveBank].status1); MarkBufferBankForExecution(gActiveBank); } @@ -4672,7 +4761,7 @@ void atk49_moveend(void) { gBattleMons[gBankTarget].status1 &= ~(STATUS_FREEZE); gActiveBank = gBankTarget; - EmitSetAttributes(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gBankTarget].status1); + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gBankTarget].status1); MarkBufferBankForExecution(gActiveBank); BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_DefrostedViaFireMove; @@ -4871,7 +4960,7 @@ void atk49_moveend(void) && !gProtectStructs[gBankAttacker].chargingTurn && gBattleMoves[gCurrentMove].target == MOVE_TARGET_BOTH && !(gHitMarker & HITMARKER_NO_ATTACKSTRING)) { - u8 bank = GetBankByPlayerAI(GetBankIdentity(gBankTarget) ^ 2); + u8 bank = GetBankByIdentity(GetBankIdentity(gBankTarget) ^ BIT_MON); if (gBattleMons[bank].hp != 0) { gBankTarget = bank; @@ -5019,7 +5108,7 @@ void atk4C_copy_poke_data(void) gBattlePartyID[gActiveBank] = *(gBattleStruct->field_5C + gActiveBank); - EmitGetAttributes(0, 0, gBitTable[gBattlePartyID[gActiveBank]]); + EmitGetMonData(0, 0, gBitTable[gBattlePartyID[gActiveBank]]); MarkBufferBankForExecution(gActiveBank); gBattlescriptCurrInstr += 2; @@ -5225,10 +5314,10 @@ void atk4F_jump_if_cannot_switch(void) { if (GetBankSide(gActiveBank) == SIDE_OPPONENT) { - r7 = GetBankByPlayerAI(1); + r7 = GetBankByIdentity(1); if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) - compareVar = GetBankByPlayerAI(3); + compareVar = GetBankByIdentity(3); else compareVar = r7; @@ -5236,10 +5325,10 @@ void atk4F_jump_if_cannot_switch(void) } else { - r7 = GetBankByPlayerAI(0); + r7 = GetBankByIdentity(0); if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) - compareVar = GetBankByPlayerAI(2); + compareVar = GetBankByIdentity(2); else compareVar = r7; @@ -5550,9 +5639,9 @@ void atk50_openpartyscreen(void) } else { - gActiveBank = GetBankByPlayerAI(GetBankIdentity(bank) ^ 1); + gActiveBank = GetBankByIdentity(GetBankIdentity(bank) ^ BIT_SIDE); if (gAbsentBankFlags & gBitTable[gActiveBank]) - gActiveBank ^= 2; + gActiveBank ^= BIT_MON; EmitLinkStandbyMsg(0, 2, 0); MarkBufferBankForExecution(gActiveBank); @@ -5712,7 +5801,7 @@ void atk52_switch_in_effects(void) void atk53_trainer_slide(void) { - gActiveBank = GetBankByPlayerAI(gBattlescriptCurrInstr[1]); + gActiveBank = GetBankByIdentity(gBattlescriptCurrInstr[1]); EmitTrainerSlide(0); MarkBufferBankForExecution(gActiveBank); @@ -5748,7 +5837,7 @@ void atk56_fainting_cry(void) void atk57(void) { - gActiveBank = GetBankByPlayerAI(0); + gActiveBank = GetBankByIdentity(0); Emit_x37(0, gBattleOutcome); MarkBufferBankForExecution(gActiveBank); @@ -5783,7 +5872,7 @@ void atk59_learnmove_inbattle(void) } else { - gActiveBank = GetBankByPlayerAI(0); + gActiveBank = GetBankByIdentity(0); if (gBattlePartyID[gActiveBank] == gBattleStruct->expGetterId && !(gBattleMons[gActiveBank].status2 & STATUS2_TRANSFORMED)) @@ -5792,7 +5881,7 @@ void atk59_learnmove_inbattle(void) } if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) { - gActiveBank = GetBankByPlayerAI(2); + gActiveBank = GetBankByIdentity(2); if (gBattlePartyID[gActiveBank] == gBattleStruct->expGetterId && !(gBattleMons[gActiveBank].status2 & STATUS2_TRANSFORMED)) { @@ -6067,7 +6156,7 @@ void atk5E_8025A70(void) switch (gBattleCommunication[0]) { case 0: - EmitGetAttributes(0, REQUEST_ALL_BATTLE, 0); + EmitGetMonData(0, REQUEST_ALL_BATTLE, 0); MarkBufferBankForExecution(gActiveBank); gBattleCommunication[0]++; break; @@ -6317,3 +6406,2571 @@ void atk69_dmg_adjustment3(void) // The same as 0x7, except there's no random da END: gBattlescriptCurrInstr++; } + +void atk6A_removeitem(void) +{ + u16* usedHeldItem; + + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + + GET_USED_ITEM_PTR_VIA_MEME_ACCESS(gActiveBank, usedHeldItem) + *usedHeldItem = gBattleMons[gActiveBank].item; + gBattleMons[gActiveBank].item = 0; + + EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gActiveBank].item); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 2; +} + +void atk6B_atknameinbuff1(void) +{ + PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, gBankAttacker, gBattlePartyID[gBankAttacker]) + + gBattlescriptCurrInstr++; +} + +extern u16 gBattle_BG1_X; +extern u16 gBattle_BG1_Y; +extern u16 gBattle_BG2_X; +extern u16 gBattle_BG2_Y; + +void atk6C_draw_lvlupbox(void) +{ + if (gBattleScripting.atk6C_state == 0) + { + if (IsMonGettingExpSentOut()) + gBattleScripting.atk6C_state = 3; + else + gBattleScripting.atk6C_state = 1; + } + + switch (gBattleScripting.atk6C_state) + { + case 1: + gBattle_BG2_Y = 0x60; + SetBgAttribute(2, BG_CTRL_ATTR_MOSAIC, 0); + ShowBg(2); + sub_804F17C(); + gBattleScripting.atk6C_state = 2; + break; + case 2: + if (!sub_804F1CC()) + gBattleScripting.atk6C_state = 3; + break; + case 3: + gBattle_BG1_X = 0; + gBattle_BG1_Y = 0x100; + SetBgAttribute(0, BG_CTRL_ATTR_MOSAIC, 1); + SetBgAttribute(1, BG_CTRL_ATTR_MOSAIC, 0); + ShowBg(0); + ShowBg(1); + sub_8056A3C(0x12, 7, 0x1D, 0x13, 0x80); + gBattleScripting.atk6C_state = 4; + break; + case 4: + sub_804F100(); + PutWindowTilemap(13); + CopyWindowToVram(13, 3); + gBattleScripting.atk6C_state++; + break; + case 5: + case 7: + if (!IsDma3ManagerBusyWithBgCopy()) + { + gBattle_BG1_Y = 0; + gBattleScripting.atk6C_state++; + } + break; + case 6: + if (gMain.newKeys != 0) + { + PlaySE(SE_SELECT); + sub_804F144(); + CopyWindowToVram(13, 2); + gBattleScripting.atk6C_state++; + } + break; + case 8: + if (gMain.newKeys != 0) + { + PlaySE(SE_SELECT); + sub_8056A3C(0x12, 7, 0x1D, 0x13, 0x81); + gBattleScripting.atk6C_state++; + } + break; + case 9: + if (!sub_804F344()) + { + ClearWindowTilemap(14); + CopyWindowToVram(14, 1); + + ClearWindowTilemap(13); + CopyWindowToVram(13, 1); + + SetBgAttribute(2, BG_CTRL_ATTR_MOSAIC, 2); + ShowBg(2); + + gBattleScripting.atk6C_state = 10; + } + break; + case 10: + if (!IsDma3ManagerBusyWithBgCopy()) + { + SetBgAttribute(0, BG_CTRL_ATTR_MOSAIC, 0); + SetBgAttribute(1, BG_CTRL_ATTR_MOSAIC, 1); + ShowBg(0); + ShowBg(1); + gBattlescriptCurrInstr++; + } + break; + } +} + +void sub_804F100(void) +{ + struct StatsArray currentStats; + + sub_81D388C(&gPlayerParty[gBattleStruct->expGetterId], ¤tStats); + sub_81D3640(0xD, gBattleResources->statsBeforeLvlUp, ¤tStats, 0xE, 0xD, 0xF); +} + +void sub_804F144(void) +{ + struct StatsArray currentStats; + + sub_81D388C(&gPlayerParty[gBattleStruct->expGetterId], ¤tStats); + sub_81D3784(0xD, ¤tStats, 0xE, 0xD, 0xF); +} + +extern const u16 gUnknown_0831C2C8[]; +extern const u8 gUnknown_0831C2E8[]; + +void sub_804F17C(void) +{ + gBattle_BG2_Y = 0; + gBattle_BG2_X = 0x1A0; + + LoadPalette(gUnknown_0831C2C8, 0x60, 0x20); + CopyToWindowPixelBuffer(14, gUnknown_0831C2E8, 0, 0); + PutWindowTilemap(14); + CopyWindowToVram(14, 3); + + PutMonIconOnLvlUpBox(); +} + +bool8 sub_804F1CC(void) +{ + if (IsDma3ManagerBusyWithBgCopy()) + return TRUE; + + if (gBattle_BG2_X == 0x200) + return FALSE; + + if (gBattle_BG2_X == 0x1A0) + PutLevelAndGenderOnLvlUpBox(); + + gBattle_BG2_X += 8; + if (gBattle_BG2_X >= 0x200) + gBattle_BG2_X = 0x200; + + return (gBattle_BG2_X != 0x200); +} + +void PutLevelAndGenderOnLvlUpBox(void) +{ + u16 monLevel; + u8 monGender; + struct TextSubPrinter subPrinter; + u8 *txtPtr; + u32 var; + + monLevel = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL); + monGender = GetMonGender(&gPlayerParty[gBattleStruct->expGetterId]); + GetMonNickname(&gPlayerParty[gBattleStruct->expGetterId], gStringVar4); + + subPrinter.current_text_offset = gStringVar4; + subPrinter.windowId = 14; + subPrinter.fontId = 0; + subPrinter.x = 32; + subPrinter.y = 0; + subPrinter.currentX = 32; + subPrinter.currentY = 0; + subPrinter.letterSpacing = 0; + subPrinter.lineSpacing = 0; + subPrinter.fontColor_l = TEXT_COLOR_TRANSPARENT; + subPrinter.fontColor_h = TEXT_COLOR_WHITE; + subPrinter.bgColor = TEXT_COLOR_TRANSPARENT; + subPrinter.shadowColor = TEXT_COLOR_DARK_GREY; + + AddTextPrinter(&subPrinter, 0xFF, NULL); + + txtPtr = gStringVar4; + gStringVar4[0] = CHAR_SPECIAL_F9; + txtPtr++; + txtPtr[0] = 5; + txtPtr++; + + var = (u32)(txtPtr); + txtPtr = ConvertIntToDecimalStringN(txtPtr, monLevel, STR_CONV_MODE_LEFT_ALIGN, 3); + var = (u32)(txtPtr) - var; + txtPtr = StringFill(txtPtr, 0x77, 4 - var); + + if (monGender != MON_GENDERLESS) + { + if (monGender == MON_MALE) + { + txtPtr = WriteColorChangeControlCode(txtPtr, 0, 0xC); + txtPtr = WriteColorChangeControlCode(txtPtr, 1, 0xD); + *(txtPtr++) = CHAR_MALE; + } + else + { + txtPtr = WriteColorChangeControlCode(txtPtr, 0, 0xE); + txtPtr = WriteColorChangeControlCode(txtPtr, 1, 0xF); + *(txtPtr++) = CHAR_FEMALE; + } + *(txtPtr++) = EOS; + } + + subPrinter.y = 10; + subPrinter.currentY = 10; + AddTextPrinter(&subPrinter, 0xFF, NULL); + + CopyWindowToVram(14, 2); +} + +bool8 sub_804F344(void) +{ + if (gBattle_BG2_X == 0x1A0) + return FALSE; + + if (gBattle_BG2_X - 16 < 0x1A0) + gBattle_BG2_X = 0x1A0; + else + gBattle_BG2_X -= 16; + + return (gBattle_BG2_X != 0x1A0); +} + +#define MON_ICON_LVLUP_BOX_TAG 0xD75A + +#define sDestroy data0 +#define sSavedLvlUpBoxXPosition data1 + +void PutMonIconOnLvlUpBox(void) +{ + u8 spriteId; + const u16* iconPal; + struct SpriteSheet iconSheet; + struct SpritePalette iconPalSheet; + + u16 species = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPECIES); + u32 personality = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_PERSONALITY); + + const u8* iconPtr = GetMonIconPtr(species, personality, 1); + iconSheet.data = iconPtr; + iconSheet.size = 0x200; + iconSheet.tag = MON_ICON_LVLUP_BOX_TAG; + + iconPal = GetValidMonIconPalettePtr(species); + iconPalSheet.data = iconPal; + iconPalSheet.tag = MON_ICON_LVLUP_BOX_TAG; + + LoadSpriteSheet(&iconSheet); + LoadSpritePalette(&iconPalSheet); + + spriteId = CreateSprite(&SpriteTemplate_MonIconOnLvlUpBox, 256, 10, 0); + gSprites[spriteId].sDestroy = FALSE; + gSprites[spriteId].sSavedLvlUpBoxXPosition = gBattle_BG2_X; +} + +void SpriteCB_MonIconOnLvlUpBox(struct Sprite* sprite) +{ + sprite->pos2.x = sprite->sSavedLvlUpBoxXPosition - gBattle_BG2_X; + + if (sprite->pos2.x != 0) + { + sprite->sDestroy = TRUE; + } + else if (sprite->sDestroy) + { + DestroySprite(sprite); + FreeSpriteTilesByTag(MON_ICON_LVLUP_BOX_TAG); + FreeSpritePaletteByTag(MON_ICON_LVLUP_BOX_TAG); + } +} + +#undef sDestroy +#undef sSavedLvlUpBoxXPosition + +bool32 IsMonGettingExpSentOut(void) +{ + if (gBattlePartyID[0] == gBattleStruct->expGetterId) + return TRUE; + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && gBattlePartyID[2] == gBattleStruct->expGetterId) + return TRUE; + + return FALSE; +} + +void atk6D_reset_sentpokes_value(void) +{ + ResetSentPokesToOpponentValue(); + gBattlescriptCurrInstr++; +} + +void atk6E_set_atk_to_player0(void) +{ + gBankAttacker = GetBankByIdentity(0); + gBattlescriptCurrInstr++; +} + +void atk6F_set_visible(void) +{ + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + EmitSpriteInvisibility(0, FALSE); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 2; +} + +void atk70_record_last_used_ability(void) +{ + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + RecordAbilityBattle(gActiveBank, gLastUsedAbility); + gBattlescriptCurrInstr += 1; // UB: Should be + 2, one byte for command and one byte for bank argument. +} + +void BufferMoveToLearnIntoBattleTextBuff2(void) +{ + PREPARE_MOVE_BUFFER(gBattleTextBuff2, gMoveToLearn); +} + +void atk71_buffer_move_to_learn(void) +{ + BufferMoveToLearnIntoBattleTextBuff2(); + gBattlescriptCurrInstr++; +} + +void atk72_jump_if_can_run_frombattle(void) +{ + if (CanRunFromBattle(gBank1)) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + else + gBattlescriptCurrInstr += 5; +} + +void atk73_hp_thresholds(void) +{ + u8 opposingBank; + s32 result; + + if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + { + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + opposingBank = gActiveBank ^ BIT_SIDE; + + result = gBattleMons[opposingBank].hp * 100 / gBattleMons[opposingBank].maxHP; + if (result == 0) + result = 1; + + if (result > 69 || !gBattleMons[opposingBank].hp) + gBattleStruct->hpScale = 0; + else if (result > 39) + gBattleStruct->hpScale = 1; + else if (result > 9) + gBattleStruct->hpScale = 2; + else + gBattleStruct->hpScale = 3; + } + + gBattlescriptCurrInstr += 2; +} + +void atk74_hp_thresholds2(void) +{ + u8 opposingBank; + s32 result; + u8 hpSwitchout; + + if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + { + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + opposingBank = gActiveBank ^ BIT_SIDE; + hpSwitchout = *(gBattleStruct->hpOnSwitchout + GetBankSide(opposingBank)); + result = (hpSwitchout - gBattleMons[opposingBank].hp) * 100 / hpSwitchout; + + if (gBattleMons[opposingBank].hp >= hpSwitchout) + gBattleStruct->hpScale = 0; + else if (result <= 29) + gBattleStruct->hpScale = 1; + else if (result <= 69) + gBattleStruct->hpScale = 2; + else + gBattleStruct->hpScale = 3; + } + + gBattlescriptCurrInstr += 2; +} + +void atk75_item_effect_on_opponent(void) +{ + gBankInMenu = gBankAttacker; + ExecuteTableBasedItemEffect(&gEnemyParty[gBattlePartyID[gBankAttacker]], gLastUsedItem, gBattlePartyID[gBankAttacker], 0, 1); + + gBattlescriptCurrInstr += 1; +} + +extern const u8 gUnknown_0831C4F8[]; +extern const u8* const gRefereeStringsTable[]; + +void atk76_various(void) +{ + u8 side; + s32 i; + + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + + switch (gBattlescriptCurrInstr[2]) + { + case VARIOUS_CANCEL_MULTI_TURN_MOVES: + CancelMultiTurnMoves(gActiveBank); + break; + case VARIOUS_SET_MAGIC_COAT_TARGET: + gBankAttacker = gBankTarget; + side = GetBankSide(gBankAttacker) ^ 1; + if (gSideTimers[side].followmeTimer != 0 && gBattleMons[gSideTimers[side].followmeTarget].hp != 0) + gBankTarget = gSideTimers[side].followmeTarget; + else + gBankTarget = gActiveBank; + break; + case 2: + gBattleCommunication[0] = IsRunningFromBattleImpossible(); + break; + case VARIOUS_GET_MOVE_TARGET: + gBankTarget = GetMoveTarget(gCurrentMove, 0); + break; + case 4: + if (gHitMarker & HITMARKER_FAINTED(gActiveBank)) + gBattleCommunication[0] = 1; + else + gBattleCommunication[0] = 0; + break; + case VARIOUS_RESET_INTIMIDATE_TRACE_BITS: + gSpecialStatuses[gActiveBank].intimidatedPoke = 0; + gSpecialStatuses[gActiveBank].traced = 0; + break; + case VARIOUS_UPDATE_CHOICE_MOVE_ON_LVL_UP: + if (gBattlePartyID[0] == gBattleStruct->expGetterId || gBattlePartyID[2] == gBattleStruct->expGetterId) + { + u16 *choicedMove; + + if (gBattlePartyID[0] == gBattleStruct->expGetterId) + gActiveBank = 0; + else + gActiveBank = 2; + + choicedMove = &gBattleStruct->choicedMove[gActiveBank]; + + for (i = 0; i < 4; i++) + { + if (gBattleMons[gActiveBank].moves[i] == *choicedMove) + break; + } + if (i == 4) + *choicedMove = 0; + } + break; + case 7: + if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_DOUBLE)) + && gBattleTypeFlags & BATTLE_TYPE_TRAINER + && gBattleMons[0].hp != 0 + && gBattleMons[1].hp != 0) + { + gHitMarker &= ~(HITMARKER_x400000); + } + break; + case 8: + gBattleCommunication[0] = 0; + gBattleScripting.bank = gActiveBank = gBattleCommunication[1]; + if (!(gBattleStruct->field_92 & gBitTable[gActiveBank]) + && gBattleMons[gActiveBank].maxHP / 2 >= gBattleMons[gActiveBank].hp + && gBattleMons[gActiveBank].hp != 0 + && !(gBattleMons[gActiveBank].status1 & STATUS_SLEEP)) + { + gBattleStruct->field_92 |= gBitTable[gActiveBank]; + gBattleCommunication[0] = 1; + gBattleCommunication[MULTISTRING_CHOOSER] = gUnknown_0831C4F8[GetNatureFromPersonality(gBattleMons[gActiveBank].personality)]; + } + break; + case 9: + i = sub_81A5258(gBattleCommunication); + if (i == 0) + return; + + gBattleCommunication[1] = i; + break; + case 10: + gBattleMons[1].hp = 0; + gHitMarker |= HITMARKER_FAINTED(1); + gBattleStruct->field_2A1 |= gBitTable[gBattlePartyID[1]]; + gDisableStructs[1].truantUnknownBit = 1; + break; + case 11: + gBattleMons[0].hp = 0; + gHitMarker |= HITMARKER_FAINTED(0); + gHitMarker |= HITMARKER_x400000; + gBattleStruct->field_2A0 |= gBitTable[gBattlePartyID[0]]; + gDisableStructs[0].truantUnknownBit = 1; + break; + case 12: + gBattleMons[0].hp = 0; + gBattleMons[1].hp = 0; + gHitMarker |= HITMARKER_FAINTED(0); + gHitMarker |= HITMARKER_FAINTED(1); + gHitMarker |= HITMARKER_x400000; + gBattleStruct->field_2A0 |= gBitTable[gBattlePartyID[0]]; + gBattleStruct->field_2A1 |= gBitTable[gBattlePartyID[1]]; + gDisableStructs[0].truantUnknownBit = 1; + gDisableStructs[1].truantUnknownBit = 1; + break; + case 13: + EmitCmd13(0); + MarkBufferBankForExecution(gActiveBank); + break; + case 14: + sub_81A5BF8(); + break; + case 15: + sub_81A5D44(); + break; + case 16: + BattleStringExpandPlaceholdersToDisplayedString(gRefereeStringsTable[gBattlescriptCurrInstr[1]]); + sub_814F9EC(gDisplayedStringBattle, 0x16); + break; + case 17: + if (IsTextPrinterActive(0x16)) + return; + break; + case VARIOUS_WAIT_CRY: + if (!IsCryFinished()) + return; + break; + case VARIOUS_RETURN_OPPONENT_MON1: + gActiveBank = 1; + if (gBattleMons[gActiveBank].hp != 0) + { + EmitReturnPokeToBall(0, 0); + MarkBufferBankForExecution(gActiveBank); + } + break; + case VARIOUS_RETURN_OPPONENT_MON2: + if (gNoOfAllBanks > 3) + { + gActiveBank = 3; + if (gBattleMons[gActiveBank].hp != 0) + { + EmitReturnPokeToBall(0, 0); + MarkBufferBankForExecution(gActiveBank); + } + } + break; + case 21: + m4aMPlayVolumeControl(&gMPlay_BGM, 0xFFFF, 0x55); + break; + case 22: + m4aMPlayVolumeControl(&gMPlay_BGM, 0xFFFF, 0x100); + break; + case 23: + gBattleStruct->field_2A2 |= gBitTable[gActiveBank]; + break; + case 24: + if (sub_805725C(gActiveBank)) + return; + break; + case VARIOUS_SET_TELEPORT_OUTCOME: + if (GetBankSide(gActiveBank) == SIDE_PLAYER) + gBattleOutcome = BATTLE_PLAYER_TELEPORTED; + else + gBattleOutcome = BATTLE_OPPONENT_TELEPORTED; + break; + case VARIOUS_PLAY_TRAINER_DEFEATED_MUSIC: + EmitPlaySound(0, 0x19C, 1); + MarkBufferBankForExecution(gActiveBank); + break; + } + + gBattlescriptCurrInstr += 3; +} + +void atk77_set_protect_like(void) // protect and endure +{ + bool8 notLastTurn = TRUE; + u16 lastMove = gUnknown_02024260[gBankAttacker]; + + if (lastMove != MOVE_PROTECT && lastMove != MOVE_DETECT && lastMove != MOVE_ENDURE) + gDisableStructs[gBankAttacker].protectUses = 0; + + if (gCurrentMoveTurn == (gNoOfAllBanks - 1)) + notLastTurn = FALSE; + + if (sProtectSuccessRates[gDisableStructs[gBankAttacker].protectUses] >= Random() && notLastTurn) + { + if (gBattleMoves[gCurrentMove].effect == EFFECT_PROTECT) + { + gProtectStructs[gBankAttacker].protected = 1; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + if (gBattleMoves[gCurrentMove].effect == EFFECT_ENDURE) + { + gProtectStructs[gBankAttacker].endured = 1; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + gDisableStructs[gBankAttacker].protectUses++; + } + else + { + gDisableStructs[gBankAttacker].protectUses = 0; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + gBattleMoveFlags |= MOVESTATUS_MISSED; + } + + gBattlescriptCurrInstr++; +} + +void atk78_faintifabilitynotdamp(void) +{ + if (gBattleExecBuffer) + return; + + for (gBankTarget = 0; gBankTarget < gNoOfAllBanks; gBankTarget++) + { + if (gBattleMons[gBankTarget].ability == ABILITY_DAMP) + break; + } + + if (gBankTarget == gNoOfAllBanks) + { + gActiveBank = gBankAttacker; + gBattleMoveDamage = gBattleMons[gActiveBank].hp; + EmitHealthBarUpdate(0, 0x7FFF); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr++; + + for (gBankTarget = 0; gBankTarget < gNoOfAllBanks; gBankTarget++) + { + if (gBankTarget == gBankAttacker) + continue; + if (!(gAbsentBankFlags & gBitTable[gBankTarget])) + break; + } + } + else + { + gLastUsedAbility = ABILITY_DAMP; + RecordAbilityBattle(gBankTarget, gBattleMons[gBankTarget].ability); + gBattlescriptCurrInstr = BattleScript_DampStopsExplosion; + } +} + +void atk79_setatkhptozero(void) +{ + if (gBattleExecBuffer) + return; + + gActiveBank = gBankAttacker; + gBattleMons[gActiveBank].hp = 0; + EmitSetMonData(0, REQUEST_HP_BATTLE, 0, 2, &gBattleMons[gActiveBank].hp); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr++; +} + +void atk7A_jumpwhiletargetvalid(void) // Used by intimidate to loop through all targets. +{ + const u8* jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + for (gBankTarget++; ; gBankTarget++) + { + if (gBankTarget == gBankAttacker) + continue; + if (!(gAbsentBankFlags & gBitTable[gBankTarget])) + break; + } + + if (gBankTarget >= gNoOfAllBanks) + gBattlescriptCurrInstr += 5; + else + gBattlescriptCurrInstr = jumpPtr; + } + else + gBattlescriptCurrInstr += 5; +} + +void atk7B_healhalfHP_if_possible(void) +{ + const u8* failPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + + if (BSScriptRead8(gBattlescriptCurrInstr + 5) == BS_GET_ATTACKER) + gBankTarget = gBankAttacker; + + gBattleMoveDamage = gBattleMons[gBankTarget].maxHP / 2; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + gBattleMoveDamage *= -1; + + if (gBattleMons[gBankTarget].hp == gBattleMons[gBankTarget].maxHP) + gBattlescriptCurrInstr = failPtr; + else + gBattlescriptCurrInstr += 6; +} + +void atk7C_trymirrormove(void) +{ + s32 validMovesCount; + s32 i; + u16 move; + u16 movesArray[4]; + + for (i = 0; i < 3; i++) + movesArray[i] = 0; + + for (validMovesCount = 0, i = 0; i < gNoOfAllBanks; i++) + { + if (i != gBankAttacker) + { + move = *(i * 2 + gBankAttacker * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) + | (*(i * 2 + gBankAttacker * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) << 8); + + if (move != 0 && move != 0xFFFF) + { + movesArray[validMovesCount] = move; + validMovesCount++; + } + } + } + + move = *(gBattleStruct->mirrorMoves + gBankAttacker * 2 + 0) + | (*(gBattleStruct->mirrorMoves + gBankAttacker * 2 + 1) << 8); + + if (move != 0 && move != 0xFFFF) + { + gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); + gCurrentMove = move; + gBankTarget = GetMoveTarget(gCurrentMove, 0); + gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]; + } + else if (validMovesCount) + { + gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); + i = Random() % validMovesCount; + gCurrentMove = movesArray[i]; + gBankTarget = GetMoveTarget(gCurrentMove, 0); + gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]; + } + else + { + gSpecialStatuses[gBankAttacker].flag20 = 1; + gBattlescriptCurrInstr++; + } +} + +void atk7D_set_rain(void) +{ + if (gBattleWeather & WEATHER_RAIN_ANY) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + } + else + { + gBattleWeather = WEATHER_RAIN_TEMPORARY; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + gWishFutureKnock.weatherDuration = 5; + } + gBattlescriptCurrInstr++; +} + +void atk7E_setreflect(void) +{ + if (gSideAffecting[GET_BANK_SIDE(gBankAttacker)] & SIDE_STATUS_REFLECT) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + else + { + gSideAffecting[GET_BANK_SIDE(gBankAttacker)] |= SIDE_STATUS_REFLECT; + gSideTimers[GET_BANK_SIDE(gBankAttacker)].reflectTimer = 5; + gSideTimers[GET_BANK_SIDE(gBankAttacker)].reflectBank = gBankAttacker; + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && CountAliveMonsInBattle(BATTLE_ALIVE_ATK_SIDE) == 2) + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + gBattlescriptCurrInstr++; +} + +void atk7F_setseeded(void) +{ + if (gBattleMoveFlags & MOVESTATUS_NOEFFECT || gStatuses3[gBankTarget] & STATUS3_LEECHSEED) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + else if (gBattleMons[gBankTarget].type1 == TYPE_GRASS || gBattleMons[gBankTarget].type2 == TYPE_GRASS) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + } + else + { + gStatuses3[gBankTarget] |= gBankAttacker; + gStatuses3[gBankTarget] |= STATUS3_LEECHSEED; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + + gBattlescriptCurrInstr++; +} + +void atk80_manipulatedamage(void) +{ + switch (BSScriptRead8(gBattlescriptCurrInstr + 1)) + { + case ATK80_DMG_CHANGE_SIGN: + gBattleMoveDamage *= -1; + break; + case ATK80_DMG_HALF_BY_TWO_NOT_MORE_THAN_HALF_MAX_HP: + gBattleMoveDamage /= 2; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + if ((gBattleMons[gBankTarget].maxHP / 2) < gBattleMoveDamage) + gBattleMoveDamage = gBattleMons[gBankTarget].maxHP / 2; + break; + case ATK80_DMG_DOUBLED: + gBattleMoveDamage *= 2; + break; + } + + gBattlescriptCurrInstr += 2; +} + +void atk81_setrest(void) +{ + const u8* failJump = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + gActiveBank = gBankTarget = gBankAttacker; + gBattleMoveDamage = gBattleMons[gBankTarget].maxHP * (-1); + + if (gBattleMons[gBankTarget].hp == gBattleMons[gBankTarget].maxHP) + { + gBattlescriptCurrInstr = failJump; + } + else + { + if (gBattleMons[gBankTarget].status1 & ((u8)(~STATUS_SLEEP))) + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + + gBattleMons[gBankTarget].status1 = 3; + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 5; + } +} + +void atk82_jumpifnotfirstturn(void) +{ + const u8* failJump = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + + if (gDisableStructs[gBankAttacker].isFirstTurn) + gBattlescriptCurrInstr += 5; + else + gBattlescriptCurrInstr = failJump; +} + +void atk83_nop(void) +{ + gBattlescriptCurrInstr++; +} + +bool8 UproarWakeUpCheck(u8 bank) +{ + s32 i; + + for (i = 0; i < gNoOfAllBanks; i++) + { + if (!(gBattleMons[i].status2 & STATUS2_UPROAR) || gBattleMons[bank].ability == ABILITY_SOUNDPROOF) + continue; + + gBattleScripting.bank = i; + + if (gBankTarget == 0xFF) + gBankTarget = i; + else if (gBankTarget == i) + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + + break; + } + + if (i == gNoOfAllBanks) + return FALSE; + else + return TRUE; +} + +void atk84_jump_if_cant_sleep(void) +{ + const u8* jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + + if (UproarWakeUpCheck(gBankTarget)) + { + gBattlescriptCurrInstr = jumpPtr; + } + else if (gBattleMons[gBankTarget].ability == ABILITY_INSOMNIA + || gBattleMons[gBankTarget].ability == ABILITY_VITAL_SPIRIT) + { + gLastUsedAbility = gBattleMons[gBankTarget].ability; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + gBattlescriptCurrInstr = jumpPtr; + RecordAbilityBattle(gBankTarget, gLastUsedAbility); + } + else + { + gBattlescriptCurrInstr += 5; + } +} + +void atk85_stockpile(void) +{ + if (gDisableStructs[gBankAttacker].stockpileCounter == 3) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + else + { + gDisableStructs[gBankAttacker].stockpileCounter++; + + PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff1, 1, gDisableStructs[gBankAttacker].stockpileCounter) + + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + gBattlescriptCurrInstr++; +} + +void atk86_stockpiletobasedamage(void) +{ + const u8* jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + if (gDisableStructs[gBankAttacker].stockpileCounter == 0) + { + gBattlescriptCurrInstr = jumpPtr; + } + else + { + if (gBattleCommunication[6] != 1) + { + gBattleMoveDamage = CalculateBaseDamage(&gBattleMons[gBankAttacker], &gBattleMons[gBankTarget], gCurrentMove, + gSideAffecting[GET_BANK_SIDE(gBankTarget)], 0, + 0, gBankAttacker, gBankTarget) + * gDisableStructs[gBankAttacker].stockpileCounter; + gBattleScripting.animTurn = gDisableStructs[gBankAttacker].stockpileCounter; + + if (gProtectStructs[gBankAttacker].helpingHand) + gBattleMoveDamage = gBattleMoveDamage * 15 / 10; + } + + gDisableStructs[gBankAttacker].stockpileCounter = 0; + gBattlescriptCurrInstr += 5; + } +} + +void atk87_stockpiletohpheal(void) +{ + const u8* jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + + if (gDisableStructs[gBankAttacker].stockpileCounter == 0) + { + gBattlescriptCurrInstr = jumpPtr; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + else if (gBattleMons[gBankAttacker].maxHP == gBattleMons[gBankAttacker].hp) + { + gDisableStructs[gBankAttacker].stockpileCounter = 0; + gBattlescriptCurrInstr = jumpPtr; + gBankTarget = gBankAttacker; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + else + { + gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / (1 << (3 - gDisableStructs[gBankAttacker].stockpileCounter)); + + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + gBattleMoveDamage *= -1; + + gBattleScripting.animTurn = gDisableStructs[gBankAttacker].stockpileCounter; + gDisableStructs[gBankAttacker].stockpileCounter = 0; + gBattlescriptCurrInstr += 5; + gBankTarget = gBankAttacker; + } +} + +void atk88_negativedamage(void) +{ + gBattleMoveDamage = -(gHpDealt / 2); + if (gBattleMoveDamage == 0) + gBattleMoveDamage = -1; + + gBattlescriptCurrInstr++; +} + +u8 ChangeStatBuffs(s8 statValue, u8 statId, u8 flags, const u8* BS_ptr) +{ + bool8 certain = 0; + bool8 notProtectAffected = FALSE; + u32 index; + + if (flags & MOVE_EFFECT_AFFECTS_USER) + gActiveBank = gBankAttacker; + else + gActiveBank = gBankTarget; + + flags &= ~(MOVE_EFFECT_AFFECTS_USER); + + if (flags & MOVE_EFFECT_CERTAIN) + certain++; + flags &= ~(MOVE_EFFECT_CERTAIN); + + if (flags & STAT_CHANGE_NOT_PROTECT_AFFECTED) + notProtectAffected++; + flags &= ~(STAT_CHANGE_NOT_PROTECT_AFFECTED); + + PREPARE_STAT_BUFFER(gBattleTextBuff1, statId) + + if ((statValue << 0x18) < 0) // stat decrease + { + if (gSideTimers[GET_BANK_SIDE(gActiveBank)].mistTimer + && !certain && gCurrentMove != MOVE_CURSE) + { + if (flags == STAT_CHANGE_BS_PTR) + { + if (gSpecialStatuses[gActiveBank].statLowered) + { + gBattlescriptCurrInstr = BS_ptr; + } + else + { + BattleScriptPush(BS_ptr); + gBattleScripting.bank = gActiveBank; + gBattlescriptCurrInstr = BattleScript_MistProtected; + gSpecialStatuses[gActiveBank].statLowered = 1; + } + } + return STAT_CHANGE_DIDNT_WORK; + } + else if (gCurrentMove != MOVE_CURSE + && notProtectAffected != TRUE && JumpIfMoveAffectedByProtect(0)) + { + gBattlescriptCurrInstr = BattleScript_ButItFailed; + return STAT_CHANGE_DIDNT_WORK; + } + else if ((gBattleMons[gActiveBank].ability == ABILITY_CLEAR_BODY + || gBattleMons[gActiveBank].ability == ABILITY_WHITE_SMOKE) + && !certain && gCurrentMove != MOVE_CURSE) + { + if (flags == STAT_CHANGE_BS_PTR) + { + if (gSpecialStatuses[gActiveBank].statLowered) + { + gBattlescriptCurrInstr = BS_ptr; + } + else + { + BattleScriptPush(BS_ptr); + gBattleScripting.bank = gActiveBank; + gBattlescriptCurrInstr = BattleScript_AbilityNoStatLoss; + gLastUsedAbility = gBattleMons[gActiveBank].ability; + RecordAbilityBattle(gActiveBank, gLastUsedAbility); + gSpecialStatuses[gActiveBank].statLowered = 1; + } + } + return STAT_CHANGE_DIDNT_WORK; + } + else if (gBattleMons[gActiveBank].ability == ABILITY_KEEN_EYE + && !certain && statId == STAT_STAGE_ACC) + { + if (flags == STAT_CHANGE_BS_PTR) + { + BattleScriptPush(BS_ptr); + gBattleScripting.bank = gActiveBank; + gBattlescriptCurrInstr = BattleScript_AbilityNoSpecificStatLoss; + gLastUsedAbility = gBattleMons[gActiveBank].ability; + RecordAbilityBattle(gActiveBank, gLastUsedAbility); + } + return STAT_CHANGE_DIDNT_WORK; + } + else if (gBattleMons[gActiveBank].ability == ABILITY_HYPER_CUTTER + && !certain && statId == STAT_STAGE_ATK) + { + if (flags == STAT_CHANGE_BS_PTR) + { + BattleScriptPush(BS_ptr); + gBattleScripting.bank = gActiveBank; + gBattlescriptCurrInstr = BattleScript_AbilityNoSpecificStatLoss; + gLastUsedAbility = gBattleMons[gActiveBank].ability; + RecordAbilityBattle(gActiveBank, gLastUsedAbility); + } + return STAT_CHANGE_DIDNT_WORK; + } + else if (gBattleMons[gActiveBank].ability == ABILITY_SHIELD_DUST && flags == 0) + { + return STAT_CHANGE_DIDNT_WORK; + } + else // try to decrease + { + statValue = -GET_STAT_BUFF_VALUE(statValue); + gBattleTextBuff2[0] = B_BUFF_PLACEHOLDER_BEGIN; + index = 1; + if (statValue == -2) + { + gBattleTextBuff2[1] = B_BUFF_STRING; + gBattleTextBuff2[2] = 0xD3; // harshly + gBattleTextBuff2[3] = 0xD3 >> 8; + index = 4; + } + gBattleTextBuff2[index] = B_BUFF_STRING; + index++; + gBattleTextBuff2[index] = 0xD4; // fell + index++; + gBattleTextBuff2[index] = 0xD4 >> 8; + index++; + gBattleTextBuff2[index] = B_BUFF_EOS; + + if (gBattleMons[gActiveBank].statStages[statId] == 0) + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + else + gBattleCommunication[MULTISTRING_CHOOSER] = (gBankTarget == gActiveBank); + + } + } + else // stat increase + { + statValue = GET_STAT_BUFF_VALUE(statValue); + gBattleTextBuff2[0] = B_BUFF_PLACEHOLDER_BEGIN; + index = 1; + if (statValue == 2) + { + gBattleTextBuff2[1] = B_BUFF_STRING; + gBattleTextBuff2[2] = 0xD1; // sharply + gBattleTextBuff2[3] = 0xD1 >> 8; + index = 4; + } + gBattleTextBuff2[index] = B_BUFF_STRING; + index++; + gBattleTextBuff2[index] = 0xD2; // rose + index++; + gBattleTextBuff2[index] = 0xD2 >> 8; + index++; + gBattleTextBuff2[index] = B_BUFF_EOS; + + if (gBattleMons[gActiveBank].statStages[statId] == 0xC) + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + else + gBattleCommunication[MULTISTRING_CHOOSER] = (gBankTarget == gActiveBank); + } + + gBattleMons[gActiveBank].statStages[statId] += statValue; + if (gBattleMons[gActiveBank].statStages[statId] < 0) + gBattleMons[gActiveBank].statStages[statId] = 0; + if (gBattleMons[gActiveBank].statStages[statId] > 0xC) + gBattleMons[gActiveBank].statStages[statId] = 0xC; + + if (gBattleCommunication[MULTISTRING_CHOOSER] == 2 && flags & STAT_CHANGE_BS_PTR) + gBattleMoveFlags |= MOVESTATUS_MISSED; + + if (gBattleCommunication[MULTISTRING_CHOOSER] == 2 && !(flags & STAT_CHANGE_BS_PTR)) + return STAT_CHANGE_DIDNT_WORK; + + return STAT_CHANGE_WORKED; +} + +void atk89_statbuffchange(void) +{ + const u8* jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + if (ChangeStatBuffs(gBattleScripting.statChanger & 0xF0, GET_STAT_BUFF_ID(gBattleScripting.statChanger), BSScriptRead8(gBattlescriptCurrInstr + 1), jumpPtr) == STAT_CHANGE_WORKED) + gBattlescriptCurrInstr += 6; +} + +void atk8A_normalisebuffs(void) // haze +{ + s32 i, j; + + for (i = 0; i < gNoOfAllBanks; i++) + { + for (j = 0; j < BATTLE_STATS_NO; j++) + gBattleMons[i].statStages[j] = 6; + } + + gBattlescriptCurrInstr++; +} + +void atk8B_setbide(void) +{ + gBattleMons[gBankAttacker].status2 |= STATUS2_MULTIPLETURNS; + gLockedMoves[gBankAttacker] = gCurrentMove; + gTakenDmg[gBankAttacker] = 0; + gBattleMons[gBankAttacker].status2 |= (STATUS2_BIDE - 0x100); // 2 turns + + gBattlescriptCurrInstr++; +} + +void atk8C_confuseifrepeatingattackends(void) +{ + if (!(gBattleMons[gBankAttacker].status2 & STATUS2_LOCK_CONFUSE)) + gBattleCommunication[MOVE_EFFECT_BYTE] = (MOVE_EFFECT_THRASH | MOVE_EFFECT_AFFECTS_USER); + + gBattlescriptCurrInstr++; +} + +void atk8D_setmultihit_counter(void) +{ + if (BSScriptRead8(gBattlescriptCurrInstr + 1)) + { + gMultiHitCounter = BSScriptRead8(gBattlescriptCurrInstr + 1); + } + else + { + gMultiHitCounter = Random() & 3; + if (gMultiHitCounter > 1) + gMultiHitCounter = (Random() & 3) + 2; + else + gMultiHitCounter += 2; + } + + gBattlescriptCurrInstr += 2; +} + +void atk8E_init_multihit_string(void) +{ + PREPARE_BYTE_NUMBER_BUFFER(gBattleScripting.multihitString, 1, 0) + + gBattlescriptCurrInstr++; +} + +bool8 sub_8051064(void) +{ + if (gBattleMons[gBankAttacker].level >= gBattleMons[gBankTarget].level) + { + *(gBattleStruct->field_58 + gBankTarget) = gBattlePartyID[gBankTarget]; + } + else + { + u16 random = Random() & 0xFF; + if ((u32)((random * (gBattleMons[gBankAttacker].level + gBattleMons[gBankTarget].level) >> 8) + 1) <= (gBattleMons[gBankTarget].level / 4)) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + return FALSE; + } + *(gBattleStruct->field_58 + gBankTarget) = gBattlePartyID[gBankTarget]; + } + + gBattlescriptCurrInstr = gUnknown_082DADD8; + return TRUE; +} + +void atk8F_forcerandomswitch(void) +{ + s32 i; + s32 bank1PartyId = 0; + s32 bank2PartyId = 0; + + #ifdef NONMATCHING + s32 lastMonId = 0; // + 1 + #else + register s32 lastMonId asm("r8") = 0; // + 1 + #endif // NONMATCHING + + s32 firstMonId = 0; + s32 monsCount = 0; + struct Pokemon* party = NULL; + s32 validMons = 0; + s32 minNeeded = 0; + + if ((gBattleTypeFlags & BATTLE_TYPE_TRAINER)) + { + if (GetBankSide(gBankTarget) == SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + if ((gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER && gBattleTypeFlags & BATTLE_TYPE_LINK) + || (gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER && gBattleTypeFlags & BATTLE_TYPE_x2000000) + || (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)) + { + if ((gBankTarget & BIT_MON) != 0) + { + firstMonId = 3; + lastMonId = 6; + } + else + { + firstMonId = 0; + lastMonId = 3; + } + monsCount = 3; + minNeeded = 1; + bank2PartyId = gBattlePartyID[gBankTarget]; + bank1PartyId = gBattlePartyID[gBankTarget ^ BIT_MON]; + } + else if ((gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_LINK) + || (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_x2000000)) + { + if (sub_806D82C(sub_806D864(gBankTarget)) == 1) + { + firstMonId = 3; + lastMonId = 6; + } + else + { + firstMonId = 0; + lastMonId = 3; + } + monsCount = 3; + minNeeded = 1; + bank2PartyId = gBattlePartyID[gBankTarget]; + bank1PartyId = gBattlePartyID[gBankTarget ^ BIT_MON]; + } + else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + { + if (GetBankSide(gBankTarget) == SIDE_PLAYER) + { + firstMonId = 0; + lastMonId = 6; + monsCount = 6; + minNeeded = 2; // since there are two opponents, it has to be a double battle + } + else + { + if ((gBankTarget & BIT_MON) != 0) + { + firstMonId = 3; + lastMonId = 6; + } + else + { + firstMonId = 0; + lastMonId = 3; + } + monsCount = 3; + minNeeded = 1; + } + bank2PartyId = gBattlePartyID[gBankTarget]; + bank1PartyId = gBattlePartyID[gBankTarget ^ BIT_MON]; + } + else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + firstMonId = 0; + lastMonId = 6; + monsCount = 6; + minNeeded = 2; + bank2PartyId = gBattlePartyID[gBankTarget]; + bank1PartyId = gBattlePartyID[gBankTarget ^ BIT_MON]; + } + else + { + firstMonId = 0; + lastMonId = 6; + monsCount = 6; + minNeeded = 1; + bank2PartyId = gBattlePartyID[gBankTarget]; // there is only one pokemon out in single battles + bank1PartyId = gBattlePartyID[gBankTarget]; + } + + for (i = firstMonId; i < lastMonId; i++) + { + if (GetMonData(&party[i], MON_DATA_SPECIES) != SPECIES_NONE + && !GetMonData(&party[i], MON_DATA_IS_EGG) + && GetMonData(&party[i], MON_DATA_HP) != 0) + { + validMons++; + } + } + + if (validMons <= minNeeded) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + if (sub_8051064()) + { + do + { + i = Random() % monsCount; + i += firstMonId; + } + while (i == bank2PartyId + || i == bank1PartyId + || GetMonData(&party[i], MON_DATA_SPECIES) == SPECIES_NONE + || GetMonData(&party[i], MON_DATA_IS_EGG) == TRUE + || GetMonData(&party[i], MON_DATA_HP) == 0); + } + *(gBattleStruct->field_5C + gBankTarget) = i; + + if (!sub_81B1250()) + sub_803BDA0(gBankTarget); + + if ((gBattleTypeFlags & BATTLE_TYPE_LINK && gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER) + || (gBattleTypeFlags & BATTLE_TYPE_LINK && gBattleTypeFlags & BATTLE_TYPE_MULTI) + || (gBattleTypeFlags & BATTLE_TYPE_x2000000 && gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER) + || (gBattleTypeFlags & BATTLE_TYPE_x2000000 && gBattleTypeFlags & BATTLE_TYPE_MULTI)) + { + sub_81B8E80(gBankTarget, i, 0); + sub_81B8E80(gBankTarget ^ BIT_MON, i, 1); + } + + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + sub_80571DC(gBankTarget, i); + } + } + else + { + sub_8051064(); + } +} + +void atk90_conversion_type_change(void) // randomly changes user's type to one of its moves' type +{ + u8 validMoves = 0; + u8 moveChecked; + u8 moveType; + + while (validMoves < 4) + { + if (gBattleMons[gBankAttacker].moves[validMoves] == 0) + break; + + validMoves++; + } + + for (moveChecked = 0; moveChecked < validMoves; moveChecked++) + { + moveType = gBattleMoves[gBattleMons[gBankAttacker].moves[moveChecked]].type; + + if (moveType == TYPE_MYSTERY) + { + if (gBattleMons[gBankAttacker].type1 == TYPE_GHOST || gBattleMons[gBankAttacker].type2 == TYPE_GHOST) + moveType = TYPE_GHOST; + else + moveType = TYPE_NORMAL; + } + if (moveType != gBattleMons[gBankAttacker].type1 + && moveType != gBattleMons[gBankAttacker].type2) + { + break; + } + } + + if (moveChecked == validMoves) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + do + { + + while ((moveChecked = Random() & 3) >= validMoves); + + moveType = gBattleMoves[gBattleMons[gBankAttacker].moves[moveChecked]].type; + + if (moveType == TYPE_MYSTERY) + { + if (gBattleMons[gBankAttacker].type1 == TYPE_GHOST || gBattleMons[gBankAttacker].type2 == TYPE_GHOST) + moveType = TYPE_GHOST; + else + moveType = TYPE_NORMAL; + } + } + while (moveType == gBattleMons[gBankAttacker].type1 || moveType == gBattleMons[gBankAttacker].type2); + + gBattleMons[gBankAttacker].type1 = moveType; + gBattleMons[gBankAttacker].type2 = moveType; + + PREPARE_TYPE_BUFFER(gBattleTextBuff1, moveType) + + gBattlescriptCurrInstr += 5; + } +} + +void atk91_givepaydaymoney(void) +{ + if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000)) && gPaydayMoney != 0) + { + u32 bonusMoney = gPaydayMoney * gBattleStruct->moneyMultiplier; + AddMoney(&gSaveBlock1Ptr->money, bonusMoney); + + PREPARE_HWORD_NUMBER_BUFFER(gBattleTextBuff1, 5, bonusMoney) + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_PrintPayDayMoneyString; + } + else + { + gBattlescriptCurrInstr++; + } +} + +void atk92_setlightscreen(void) +{ + if (gSideAffecting[GET_BANK_SIDE(gBankAttacker)] & SIDE_STATUS_LIGHTSCREEN) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + else + { + gSideAffecting[GET_BANK_SIDE(gBankAttacker)] |= SIDE_STATUS_LIGHTSCREEN; + gSideTimers[GET_BANK_SIDE(gBankAttacker)].lightscreenTimer = 5; + gSideTimers[GET_BANK_SIDE(gBankAttacker)].lightscreenBank = gBankAttacker; + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && CountAliveMonsInBattle(BATTLE_ALIVE_ATK_SIDE) == 2) + gBattleCommunication[MULTISTRING_CHOOSER] = 4; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 3; + } + + gBattlescriptCurrInstr++; +} + +void atk93_ko_move(void) +{ + u8 holdEffect, param; + + if (gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY) + { + holdEffect = gEnigmaBerries[gBankTarget].holdEffect; + param = gEnigmaBerries[gBankTarget].holdEffectParam; + } + else + { + holdEffect = ItemId_GetHoldEffect(gBattleMons[gBankTarget].item); + param = ItemId_GetHoldEffectParam(gBattleMons[gBankTarget].item); + } + + gStringBank = gBankTarget; + + if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < param) + { + RecordItemEffectBattle(gBankTarget, HOLD_EFFECT_FOCUS_BAND); + gSpecialStatuses[gBankTarget].focusBanded = 1; + } + + if (gBattleMons[gBankTarget].ability == ABILITY_STURDY) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gLastUsedAbility = ABILITY_STURDY; + gBattlescriptCurrInstr = BattleScript_SturdyPreventsOHKO; + RecordAbilityBattle(gBankTarget, ABILITY_STURDY); + } + else + { + u16 chance; + if (!(gStatuses3[gBankTarget] & STATUS3_ALWAYS_HITS)) + { + chance = gBattleMoves[gCurrentMove].accuracy + (gBattleMons[gBankAttacker].level - gBattleMons[gBankTarget].level); + if (Random() % 100 + 1 < chance && gBattleMons[gBankAttacker].level >= gBattleMons[gBankTarget].level) + chance = TRUE; + else + chance = FALSE; + } + else if (gDisableStructs[gBankTarget].bankWithSureHit == gBankAttacker + && gBattleMons[gBankAttacker].level >= gBattleMons[gBankTarget].level) + { + chance = TRUE; + } + else + { + chance = gBattleMoves[gCurrentMove].accuracy + (gBattleMons[gBankAttacker].level - gBattleMons[gBankTarget].level); + if (Random() % 100 + 1 < chance && gBattleMons[gBankAttacker].level >= gBattleMons[gBankTarget].level) + chance = TRUE; + else + chance = FALSE; + } + if (chance) + { + if (gProtectStructs[gBankTarget].endured) + { + gBattleMoveDamage = gBattleMons[gBankTarget].hp - 1; + gBattleMoveFlags |= MOVESTATUS_ENDURED; + } + else if (gSpecialStatuses[gBankTarget].focusBanded) + { + gBattleMoveDamage = gBattleMons[gBankTarget].hp - 1; + gBattleMoveFlags |= MOVESTATUS_HUNGON; + gLastUsedItem = gBattleMons[gBankTarget].item; + } + else + { + gBattleMoveDamage = gBattleMons[gBankTarget].hp; + gBattleMoveFlags |= MOVESTATUS_ONEHITKO; + } + gBattlescriptCurrInstr += 5; + } + else + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + if (gBattleMons[gBankAttacker].level >= gBattleMons[gBankTarget].level) + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + } +} + +void atk94_damagetohalftargethp(void) // super fang +{ + gBattleMoveDamage = gBattleMons[gBankTarget].hp / 2; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + + gBattlescriptCurrInstr++; +} + +void atk95_setsandstorm(void) +{ + if (gBattleWeather & WEATHER_SANDSTORM_ANY) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + } + else + { + gBattleWeather = WEATHER_SANDSTORM_TEMPORARY; + gBattleCommunication[MULTISTRING_CHOOSER] = 3; + gWishFutureKnock.weatherDuration = 5; + } + gBattlescriptCurrInstr++; +} + +void atk96_weatherdamage(void) +{ + if (WEATHER_HAS_EFFECT) + { + if (gBattleWeather & WEATHER_SANDSTORM_ANY) + { + if (gBattleMons[gBankAttacker].type1 != TYPE_ROCK + && gBattleMons[gBankAttacker].type1 != TYPE_STEEL + && gBattleMons[gBankAttacker].type1 != TYPE_GROUND + && gBattleMons[gBankAttacker].type2 != TYPE_ROCK + && gBattleMons[gBankAttacker].type2 != TYPE_STEEL + && gBattleMons[gBankAttacker].type2 != TYPE_GROUND + && gBattleMons[gBankAttacker].ability != ABILITY_SAND_VEIL + && !(gStatuses3[gBankAttacker] & STATUS3_UNDERGROUND) + && !(gStatuses3[gBankAttacker] & STATUS3_UNDERWATER)) + { + gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 16; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + } + else + { + gBattleMoveDamage = 0; + } + } + if (gBattleWeather & WEATHER_HAIL) + { + if (gBattleMons[gBankAttacker].type1 != TYPE_ICE + && gBattleMons[gBankAttacker].type2 != TYPE_ICE + && !(gStatuses3[gBankAttacker] & STATUS3_UNDERGROUND) + && !(gStatuses3[gBankAttacker] & STATUS3_UNDERWATER)) + { + gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 16; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + } + else + { + gBattleMoveDamage = 0; + } + } + } + else + { + gBattleMoveDamage = 0; + } + + if (gAbsentBankFlags & gBitTable[gBankAttacker]) + gBattleMoveDamage = 0; + + gBattlescriptCurrInstr++; +} + +void atk97_try_infatuation(void) +{ + struct Pokemon *monAttacker, *monTarget; + u16 speciesAttacker, speciesTarget; + u32 personalityAttacker, personalityTarget; + + if (GetBankSide(gBankAttacker) == SIDE_PLAYER) + monAttacker = &gPlayerParty[gBattlePartyID[gBankAttacker]]; + else + monAttacker = &gEnemyParty[gBattlePartyID[gBankAttacker]]; + + if (GetBankSide(gBankTarget) == SIDE_PLAYER) + monTarget = &gPlayerParty[gBattlePartyID[gBankTarget]]; + else + monTarget = &gEnemyParty[gBattlePartyID[gBankTarget]]; + + speciesAttacker = GetMonData(monAttacker, MON_DATA_SPECIES); + personalityAttacker = GetMonData(monAttacker, MON_DATA_PERSONALITY); + + speciesTarget = GetMonData(monTarget, MON_DATA_SPECIES); + personalityTarget = GetMonData(monTarget, MON_DATA_PERSONALITY); + + if (gBattleMons[gBankTarget].ability == ABILITY_OBLIVIOUS) + { + gBattlescriptCurrInstr = BattleScript_ObliviousPreventsAttraction; + gLastUsedAbility = ABILITY_OBLIVIOUS; + RecordAbilityBattle(gBankTarget, ABILITY_OBLIVIOUS); + } + else + { + if (GetGenderFromSpeciesAndPersonality(speciesAttacker, personalityAttacker) == GetGenderFromSpeciesAndPersonality(speciesTarget, personalityTarget) + || gBattleMons[gBankTarget].status2 & STATUS2_INFATUATION + || GetGenderFromSpeciesAndPersonality(speciesAttacker, personalityAttacker) == MON_GENDERLESS + || GetGenderFromSpeciesAndPersonality(speciesTarget, personalityTarget) == MON_GENDERLESS) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gBattleMons[gBankTarget].status2 |= STATUS2_INFATUATED_WITH(gBankAttacker); + gBattlescriptCurrInstr += 5; + } + } +} + +void atk98_status_icon_update(void) +{ + if (gBattleExecBuffer) + return; + + if (BSScriptRead8(gBattlescriptCurrInstr + 1) != BS_ATTACKER_WITH_PARTNER) + { + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + EmitStatusIconUpdate(0, gBattleMons[gActiveBank].status1, gBattleMons[gActiveBank].status2); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 2; + } + else + { + gActiveBank = gBankAttacker; + if (!(gAbsentBankFlags & gBitTable[gActiveBank])) + { + EmitStatusIconUpdate(0, gBattleMons[gActiveBank].status1, gBattleMons[gActiveBank].status2); + MarkBufferBankForExecution(gActiveBank); + } + if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + { + gActiveBank = GetBankByIdentity(GetBankIdentity(gBankAttacker) ^ BIT_MON); + if (!(gAbsentBankFlags & gBitTable[gActiveBank])) + { + EmitStatusIconUpdate(0, gBattleMons[gActiveBank].status1, gBattleMons[gActiveBank].status2); + MarkBufferBankForExecution(gActiveBank); + } + } + gBattlescriptCurrInstr += 2; + } +} + +void atk99_setmist(void) +{ + if (gSideTimers[GET_BANK_SIDE(gBankAttacker)].mistTimer) + { + gBattleMoveFlags |= MOVESTATUS_FAILED; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + else + { + gSideTimers[GET_BANK_SIDE(gBankAttacker)].mistTimer = 5; + gSideTimers[GET_BANK_SIDE(gBankAttacker)].mistBank = gBankAttacker; + gSideAffecting[GET_BANK_SIDE(gBankAttacker)] |= SIDE_STATUS_MIST; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + gBattlescriptCurrInstr++; +} + +void atk9A_set_focusenergy(void) +{ + if (gBattleMons[gBankAttacker].status2 & STATUS2_FOCUS_ENERGY) + { + gBattleMoveFlags |= MOVESTATUS_FAILED; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + else + { + gBattleMons[gBankAttacker].status2 |= STATUS2_FOCUS_ENERGY; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + gBattlescriptCurrInstr++; +} + +void atk9B_transformdataexecution(void) +{ + gLastUsedMove = 0xFFFF; + gBattlescriptCurrInstr++; + if (gBattleMons[gBankTarget].status2 & STATUS2_TRANSFORMED + || gStatuses3[gBankTarget] & STATUS3_SEMI_INVULNERABLE) + { + gBattleMoveFlags |= MOVESTATUS_FAILED; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + else + { + s32 i; + u8 *battleMonAttacker, *battleMonTarget; + + gBattleMons[gBankAttacker].status2 |= STATUS2_TRANSFORMED; + gDisableStructs[gBankAttacker].disabledMove = 0; + gDisableStructs[gBankAttacker].disableTimer1 = 0; + gDisableStructs[gBankAttacker].unk0 = gBattleMons[gBankTarget].personality; + gDisableStructs[gBankAttacker].unk18_b = 0; + + PREPARE_SPECIES_BUFFER(gBattleTextBuff1, gBattleMons[gBankTarget].species) + + battleMonAttacker = (u8*)(&gBattleMons[gBankAttacker]); + battleMonTarget = (u8*)(&gBattleMons[gBankTarget]); + + for (i = 0; i < offsetof(struct BattlePokemon, pp); i++) + battleMonAttacker[i] = battleMonTarget[i]; + + for (i = 0; i < 4; i++) + { + if (gBattleMoves[gBattleMons[gBankAttacker].moves[i]].pp < 5) + gBattleMons[gBankAttacker].pp[i] = gBattleMoves[gBattleMons[gBankAttacker].moves[i]].pp; + else + gBattleMons[gBankAttacker].pp[i] = 5; + } + + gActiveBank = gBankAttacker; + EmitResetActionMoveSelection(0, RESET_MOVE_SELECTION); + MarkBufferBankForExecution(gActiveBank); + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } +} + +void atk9C_set_substitute(void) +{ + u32 hp = gBattleMons[gBankAttacker].maxHP / 4; + if (gBattleMons[gBankAttacker].maxHP / 4 == 0) + hp = 1; + + if (gBattleMons[gBankAttacker].hp <= hp) + { + gBattleMoveDamage = 0; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + else + { + gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 4; // one bit value will only work for pokemon which max hp can go to 1020(which is more than possible in games) + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + + gBattleMons[gBankAttacker].status2 |= STATUS2_SUBSTITUTE; + gBattleMons[gBankAttacker].status2 &= ~(STATUS2_WRAPPED); + gDisableStructs[gBankAttacker].substituteHP = gBattleMoveDamage; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + gHitMarker |= HITMARKER_IGNORE_SUBSTITUTE; + } + + gBattlescriptCurrInstr++; +} + +extern const u16 gMovesForbiddenToCopy[]; +#define MIMIC_FORBIDDEN_END 0xFFFE +#define METRONOME_SLEEPTALK_FORBIDDEN_END 0xFFFF + +static bool8 IsMoveUncopyableByMimic(u16 move) +{ + s32 i; + for (i = 0; gMovesForbiddenToCopy[i] != MIMIC_FORBIDDEN_END + && gMovesForbiddenToCopy[i] != move; i++); + + return (gMovesForbiddenToCopy[i] != MIMIC_FORBIDDEN_END); +} + +void atk9D_mimicattackcopy(void) +{ + gLastUsedMove = 0xFFFF; + + if (IsMoveUncopyableByMimic(gLastUsedMovesByBanks[gBankTarget]) + || gBattleMons[gBankAttacker].status2 & STATUS2_TRANSFORMED + || gLastUsedMovesByBanks[gBankTarget] == 0 + || gLastUsedMovesByBanks[gBankTarget] == 0xFFFF) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + s32 i; + + for (i = 0; i < 4; i++) + { + if (gBattleMons[gBankAttacker].moves[i] == gLastUsedMovesByBanks[gBankTarget]) + break; + } + + if (i == 4) + { + gBattleMons[gBankAttacker].moves[gCurrMovePos] = gLastUsedMovesByBanks[gBankTarget]; + if (gBattleMoves[gLastUsedMovesByBanks[gBankTarget]].pp < 5) + gBattleMons[gBankAttacker].pp[gCurrMovePos] = gBattleMoves[gLastUsedMovesByBanks[gBankTarget]].pp; + else + gBattleMons[gBankAttacker].pp[gCurrMovePos] = 5; + + + PREPARE_MOVE_BUFFER(gBattleTextBuff1, gLastUsedMovesByBanks[gBankTarget]) + + gDisableStructs[gBankAttacker].unk18_b |= gBitTable[gCurrMovePos]; + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + } +} + +#ifdef NONMATCHING +void atk9E_metronome(void) +{ + while (1) + { + const u16 *move; + s32 i, j; + + gCurrentMove = (Random() & 0x1FF) + 1; + if (gCurrentMove > LAST_MOVE_INDEX) + continue; + + for (i = 0; i < 4; i++); // ? + + for (move = gMovesForbiddenToCopy; ; move++) + { + if (*move == gCurrentMove) + break; + if (*move == METRONOME_SLEEPTALK_FORBIDDEN_END) + break; + } + + if (*move == METRONOME_SLEEPTALK_FORBIDDEN_END) + break; + } + + gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); + gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]; + gBankTarget = GetMoveTarget(gCurrentMove, 0); +} + +#else +__attribute__((naked)) +void atk9E_metronome(void) +{ + asm( + "\n\ + .syntax unified\n\ + push {r4-r7,lr}\n\ + mov r7, r8\n\ + push {r7}\n\ + ldr r7, =gCurrentMove\n\ + movs r6, 0xB1\n\ + lsls r6, 1\n\ + ldr r5, =gMovesForbiddenToCopy\n\ + ldr r0, =gBattlescriptCurrInstr\n\ + mov r8, r0\n\ +_080524EE:\n\ + bl Random\n\ + ldr r2, =0x000001ff\n\ + adds r1, r2, 0\n\ + ands r0, r1\n\ + adds r0, 0x1\n\ + strh r0, [r7]\n\ + cmp r0, r6\n\ + bhi _080524EE\n\ + movs r0, 0x3\n\ +_08052502:\n\ + subs r0, 0x1\n\ + cmp r0, 0\n\ + bge _08052502\n\ + ldr r4, =gCurrentMove\n\ + ldrh r2, [r4]\n\ + ldr r3, =0x0000ffff\n\ + subs r0, r5, 0x2\n\ +_08052510:\n\ + adds r0, 0x2\n\ + ldrh r1, [r0]\n\ + cmp r1, r2\n\ + beq _0805251C\n\ + cmp r1, r3\n\ + bne _08052510\n\ +_0805251C:\n\ + ldr r0, =0x0000ffff\n\ + cmp r1, r0\n\ + bne _080524EE\n\ + ldr r2, =gHitMarker\n\ + ldr r0, [r2]\n\ + ldr r1, =0xfffffbff\n\ + ands r0, r1\n\ + str r0, [r2]\n\ + ldr r3, =gBattleScriptsForMoveEffects\n\ + ldr r2, =gBattleMoves\n\ + ldrh r1, [r4]\n\ + lsls r0, r1, 1\n\ + adds r0, r1\n\ + lsls r0, 2\n\ + adds r0, r2\n\ + ldrb r0, [r0]\n\ + lsls r0, 2\n\ + adds r0, r3\n\ + ldr r0, [r0]\n\ + mov r1, r8\n\ + str r0, [r1]\n\ + ldrh r0, [r4]\n\ + movs r1, 0\n\ + bl GetMoveTarget\n\ + ldr r1, =gBankTarget\n\ + strb r0, [r1]\n\ + pop {r3}\n\ + mov r8, r3\n\ + pop {r4-r7}\n\ + pop {r0}\n\ + bx r0\n\ + .pool\n\ + .syntax divided"); +} + +#endif // NONMATCHING + +void atk9F_dmgtolevel(void) +{ + gBattleMoveDamage = gBattleMons[gBankAttacker].level; + gBattlescriptCurrInstr++; +} + +void atkA0_psywavedamageeffect(void) +{ + s32 randDamage; + + while ((randDamage = (Random() & 0xF)) > 10); + + randDamage *= 10; + gBattleMoveDamage = gBattleMons[gBankAttacker].level * (randDamage + 50) / 100; + gBattlescriptCurrInstr++; +} + +void atkA1_counterdamagecalculator(void) +{ + u8 sideAttacker = GetBankSide(gBankAttacker); + u8 sideTarget = GetBankSide(gProtectStructs[gBankAttacker].physicalBank); + + if (gProtectStructs[gBankAttacker].physicalDmg + && sideAttacker != sideTarget + && gBattleMons[gProtectStructs[gBankAttacker].physicalBank].hp) + { + gBattleMoveDamage = gProtectStructs[gBankAttacker].physicalDmg * 2; + + if (gSideTimers[sideTarget].followmeTimer && gBattleMons[gSideTimers[sideTarget].followmeTarget].hp) + gBankTarget = gSideTimers[sideTarget].followmeTarget; + else + gBankTarget = gProtectStructs[gBankAttacker].physicalBank; + + gBattlescriptCurrInstr += 5; + } + else + { + gSpecialStatuses[gBankAttacker].flag20 = 1; + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +void atkA2_mirrorcoatdamagecalculator(void) // a copy of atkA1 with the physical -> special field changes +{ + u8 sideAttacker = GetBankSide(gBankAttacker); + u8 sideTarget = GetBankSide(gProtectStructs[gBankAttacker].specialBank); + + if (gProtectStructs[gBankAttacker].specialDmg && sideAttacker != sideTarget && gBattleMons[gProtectStructs[gBankAttacker].specialBank].hp) + { + gBattleMoveDamage = gProtectStructs[gBankAttacker].specialDmg * 2; + + if (gSideTimers[sideTarget].followmeTimer && gBattleMons[gSideTimers[sideTarget].followmeTarget].hp) + gBankTarget = gSideTimers[sideTarget].followmeTarget; + else + gBankTarget = gProtectStructs[gBankAttacker].specialBank; + + gBattlescriptCurrInstr += 5; + } + else + { + gSpecialStatuses[gBankAttacker].flag20 = 1; + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +void atkA3_disablelastusedattack(void) +{ + s32 i; + + for (i = 0; i < 4; i++) + { + if (gBattleMons[gBankTarget].moves[i] == gLastUsedMovesByBanks[gBankTarget]) + break; + } + if (gDisableStructs[gBankTarget].disabledMove == 0 + && i != 4 && gBattleMons[gBankTarget].pp[i] != 0) + { + PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleMons[gBankTarget].moves[i]) + + gDisableStructs[gBankTarget].disabledMove = gBattleMons[gBankTarget].moves[i]; + gDisableStructs[gBankTarget].disableTimer1 = (Random() & 3) + 2; + gDisableStructs[gBankTarget].disableTimer2 = gDisableStructs[gBankTarget].disableTimer1; // used to save the random amount of turns? + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +void atkA4_setencore(void) +{ + s32 i; + + for (i = 0; i < 4; i++) + { + if (gBattleMons[gBankTarget].moves[i] == gLastUsedMovesByBanks[gBankTarget]) + break; + } + + if (gLastUsedMovesByBanks[gBankTarget] == MOVE_STRUGGLE + || gLastUsedMovesByBanks[gBankTarget] == MOVE_ENCORE + || gLastUsedMovesByBanks[gBankTarget] == MOVE_MIRROR_MOVE) + { + i = 4; + } + + if (gDisableStructs[gBankTarget].encoredMove == 0 + && i != 4 && gBattleMons[gBankTarget].pp[i] != 0) + { + gDisableStructs[gBankTarget].encoredMove = gBattleMons[gBankTarget].moves[i]; + gDisableStructs[gBankTarget].encoredMovePos = i; + gDisableStructs[gBankTarget].encoreTimer1 = (Random() & 3) + 3; + gDisableStructs[gBankTarget].encoreTimer2 = gDisableStructs[gBankTarget].encoreTimer1; + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +void atkA5_painsplitdmgcalc(void) +{ + if (!(gBattleMons[gBankTarget].status2 & STATUS2_SUBSTITUTE)) + { + s32 hpDiff = (gBattleMons[gBankAttacker].hp + gBattleMons[gBankTarget].hp) / 2; + s32 painSplitHp = gBattleMoveDamage = gBattleMons[gBankTarget].hp - hpDiff; + u8* storeLoc = (void*)(&gBattleScripting.painSplitHp); + + storeLoc[0] = (painSplitHp); + storeLoc[1] = (painSplitHp & 0x0000FF00) >> 8; + storeLoc[2] = (painSplitHp & 0x00FF0000) >> 16; + storeLoc[3] = (painSplitHp & 0xFF000000) >> 24; + + gBattleMoveDamage = gBattleMons[gBankAttacker].hp - hpDiff; + gSpecialStatuses[gBankTarget].moveturnLostHP = 0xFFFF; + + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +#ifdef NONMATCHING +void atkA6_settypetorandomresistance(void) // conversion 2 +{ + if (gUnknown_02024250[gBankAttacker] == 0 + || gUnknown_02024250[gBankAttacker] == 0xFFFF) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else if (IsTwoTurnsMove(gUnknown_02024250[gBankAttacker]) + && gBattleMons[gUnknown_02024270[gBankAttacker]].status2 & STATUS2_MULTIPLETURNS) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + s32 type = 0, rands = 0; + do + { + while (((type = (Random() & 0x7F)) > 0x70)); + + type *= 3; + + if (gTypeEffectiveness[type] == gUnknown_02024258[gBankAttacker] + && gTypeEffectiveness[type + 2] <= 5 + && gBattleMons[gBankAttacker].type1 != gTypeEffectiveness[type + 1] + && gBattleMons[gBankAttacker].type2 != gTypeEffectiveness[type + 1]) + { + gBattleMons[gBankAttacker].type1 = type; + gBattleMons[gBankAttacker].type2 = type; + + PREPARE_TYPE_BUFFER(gBattleTextBuff1, type) + + gBattlescriptCurrInstr += 5; + return; + } + + rands++; + } while (rands <= 999); + + type = 0, rands = 0; + do + { + s8 var = (s8)(gTypeEffectiveness[type]); + if (var > -1 || var < -2) + { + if (gTypeEffectiveness[type] == gUnknown_02024258[gBankAttacker] + && gTypeEffectiveness[type + 2] <= 5 + && gBattleMons[gBankAttacker].type1 != gTypeEffectiveness[type + 1] + && gBattleMons[gBankAttacker].type2 != gTypeEffectiveness[type + 1]) + { + gBattleMons[gBankAttacker].type1 = gTypeEffectiveness[rands + 1]; + gBattleMons[gBankAttacker].type2 = gTypeEffectiveness[rands + 1]; + + PREPARE_TYPE_BUFFER(gBattleTextBuff1, gTypeEffectiveness[rands + 1]) + + gBattlescriptCurrInstr += 5; + return; + } + } + type += 3, rands += 3; + } while (rands < 336); + + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +#else +__attribute__((naked)) +void atkA6_settypetorandomresistance(void) // conversion 2 +{ + asm(".syntax unified\n\ + push {r4-r7,lr}\n\ + mov r7, r10\n\ + mov r6, r9\n\ + mov r5, r8\n\ + push {r5-r7}\n\ + ldr r1, =gUnknown_02024250\n\ + ldr r4, =gBankAttacker\n\ + ldrb r0, [r4]\n\ + lsls r0, 1\n\ + adds r2, r0, r1\n\ + ldrh r1, [r2]\n\ + cmp r1, 0\n\ + beq _08052B7E\n\ + ldr r0, =0x0000ffff\n\ + cmp r1, r0\n\ + beq _08052B7E\n\ + ldrh r0, [r2]\n\ + bl IsTwoTurnsMove\n\ + lsls r0, 24\n\ + cmp r0, 0\n\ + beq _08052C1C\n\ + ldr r1, =gBattleMons\n\ + ldr r2, =gUnknown_02024270\n\ + ldrb r0, [r4]\n\ + adds r0, r2\n\ + ldrb r2, [r0]\n\ + movs r0, 0x58\n\ + muls r0, r2\n\ + adds r1, 0x50\n\ + adds r0, r1\n\ + ldr r0, [r0]\n\ + movs r1, 0x80\n\ + lsls r1, 5\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _08052C1C\n\ +_08052B7E:\n\ + ldr r3, =gBattlescriptCurrInstr\n\ + ldr r2, [r3]\n\ + ldrb r1, [r2, 0x1]\n\ + ldrb r0, [r2, 0x2]\n\ + lsls r0, 8\n\ + orrs r1, r0\n\ + ldrb r0, [r2, 0x3]\n\ + lsls r0, 16\n\ + orrs r1, r0\n\ + ldrb r0, [r2, 0x4]\n\ + lsls r0, 24\n\ + orrs r1, r0\n\ + str r1, [r3]\n\ + b _08052D08\n\ + .pool\n\ +_08052BB4:\n\ + mov r0, r12\n\ + strb r5, [r0]\n\ + mov r1, r10\n\ + ldrb r0, [r1]\n\ + muls r0, r2\n\ + adds r0, r7\n\ + adds r0, 0x22\n\ + strb r5, [r0]\n\ + ldr r1, =gBattleTextBuff1\n\ + movs r0, 0xFD\n\ + strb r0, [r1]\n\ + movs r0, 0x3\n\ + strb r0, [r1, 0x1]\n\ + strb r5, [r1, 0x2]\n\ + movs r0, 0xFF\n\ + strb r0, [r1, 0x3]\n\ + ldr r1, =gBattlescriptCurrInstr\n\ + b _08052C0A\n\ + .pool\n\ +_08052BE0:\n\ + mov r0, r8\n\ + adds r0, 0x1\n\ + adds r0, r3\n\ + ldrb r2, [r0]\n\ + strb r2, [r4]\n\ + mov r4, r10\n\ + ldrb r0, [r4]\n\ + muls r0, r6\n\ + ldr r7, =gBattleMons\n\ + adds r0, r7\n\ + adds r0, 0x22\n\ + strb r2, [r0]\n\ + ldr r1, =gBattleTextBuff1\n\ + movs r0, 0xFD\n\ + strb r0, [r1]\n\ + movs r0, 0x3\n\ + strb r0, [r1, 0x1]\n\ + strb r2, [r1, 0x2]\n\ + movs r0, 0xFF\n\ + strb r0, [r1, 0x3]\n\ + mov r1, r12\n\ +_08052C0A:\n\ + ldr r0, [r1]\n\ + adds r0, 0x5\n\ + str r0, [r1]\n\ + b _08052D08\n\ + .pool\n\ +_08052C1C:\n\ + movs r4, 0\n\ + mov r8, r4\n\ + movs r7, 0x7F\n\ + mov r9, r7\n\ +_08052C24:\n\ + bl Random\n\ + mov r4, r9\n\ + ands r4, r0\n\ + cmp r4, 0x70\n\ + bhi _08052C24\n\ + lsls r0, r4, 1\n\ + adds r4, r0, r4\n\ + ldr r6, =gTypeEffectiveness\n\ + adds r3, r4, r6\n\ + ldr r1, =gUnknown_02024258\n\ + ldr r2, =gBankAttacker\n\ + ldrb r5, [r2]\n\ + lsls r0, r5, 1\n\ + adds r0, r1\n\ + ldrb r1, [r3]\n\ + mov r10, r2\n\ + ldrh r0, [r0]\n\ + cmp r1, r0\n\ + bne _08052C80\n\ + adds r0, r4, 0x2\n\ + adds r0, r6\n\ + ldrb r0, [r0]\n\ + cmp r0, 0x5\n\ + bhi _08052C80\n\ + ldr r7, =gBattleMons\n\ + movs r2, 0x58\n\ + adds r0, r5, 0\n\ + muls r0, r2\n\ + adds r3, r0, r7\n\ + movs r0, 0x21\n\ + adds r0, r3\n\ + mov r12, r0\n\ + adds r0, r4, 0x1\n\ + adds r0, r6\n\ + ldrb r5, [r0]\n\ + mov r1, r12\n\ + ldrb r0, [r1]\n\ + adds r1, r5, 0\n\ + cmp r0, r1\n\ + beq _08052C80\n\ + adds r0, r3, 0\n\ + adds r0, 0x22\n\ + ldrb r0, [r0]\n\ + cmp r0, r1\n\ + bne _08052BB4\n\ +_08052C80:\n\ + movs r7, 0x1\n\ + add r8, r7\n\ + ldr r0, =0x000003e7\n\ + cmp r8, r0\n\ + ble _08052C24\n\ + movs r0, 0\n\ + mov r8, r0\n\ + ldr r1, =gBattlescriptCurrInstr\n\ + mov r12, r1\n\ + ldr r3, =gTypeEffectiveness\n\ + adds r0, r4, 0x1\n\ + adds r0, r3\n\ + mov r9, r0\n\ + adds r5, r3, 0\n\ +_08052C9C:\n\ + ldrb r1, [r5]\n\ + cmp r1, 0xFF\n\ + bgt _08052CA6\n\ + cmp r1, 0xFE\n\ + bge _08052CE0\n\ +_08052CA6:\n\ + mov r4, r10\n\ + ldrb r2, [r4]\n\ + lsls r0, r2, 1\n\ + ldr r7, =gUnknown_02024258\n\ + adds r0, r7\n\ + ldrh r0, [r0]\n\ + cmp r1, r0\n\ + bne _08052CE0\n\ + ldrb r0, [r5, 0x2]\n\ + cmp r0, 0x5\n\ + bhi _08052CE0\n\ + movs r6, 0x58\n\ + adds r0, r2, 0\n\ + muls r0, r6\n\ + ldr r1, =gBattleMons\n\ + adds r2, r0, r1\n\ + adds r4, r2, 0\n\ + adds r4, 0x21\n\ + ldrb r0, [r4]\n\ + mov r7, r9\n\ + ldrb r1, [r7]\n\ + cmp r0, r1\n\ + beq _08052CE0\n\ + adds r0, r2, 0\n\ + adds r0, 0x22\n\ + ldrb r0, [r0]\n\ + cmp r0, r1\n\ + beq _08052CE0\n\ + b _08052BE0\n\ +_08052CE0:\n\ + adds r5, 0x3\n\ + movs r0, 0x3\n\ + add r8, r0\n\ + ldr r0, =0x0000014f\n\ + cmp r8, r0\n\ + bls _08052C9C\n\ + mov r1, r12\n\ + ldr r2, [r1]\n\ + ldrb r1, [r2, 0x1]\n\ + ldrb r0, [r2, 0x2]\n\ + lsls r0, 8\n\ + orrs r1, r0\n\ + ldrb r0, [r2, 0x3]\n\ + lsls r0, 16\n\ + orrs r1, r0\n\ + ldrb r0, [r2, 0x4]\n\ + lsls r0, 24\n\ + orrs r1, r0\n\ + mov r4, r12\n\ + str r1, [r4]\n\ +_08052D08:\n\ + pop {r3-r5}\n\ + mov r8, r3\n\ + mov r9, r4\n\ + mov r10, r5\n\ + pop {r4-r7}\n\ + pop {r0}\n\ + bx r0\n\ + .pool\n\ + .syntax divided"); +} +#endif // NONMATCHING + +void atkA7_setalwayshitflag(void) +{ + gStatuses3[gBankTarget] &= ~(STATUS3_ALWAYS_HITS); + gStatuses3[gBankTarget] |= 0x10; + gDisableStructs[gBankTarget].bankWithSureHit = gBankAttacker; + gBattlescriptCurrInstr++; +} + +void atkA8_copymovepermanently(void) // sketch +{ + gLastUsedMove = 0xFFFF; + + if (!(gBattleMons[gBankAttacker].status2 & STATUS2_TRANSFORMED) + && gUnknownMovesUsedByBanks[gBankTarget] != MOVE_STRUGGLE + && gUnknownMovesUsedByBanks[gBankTarget] != 0 + && gUnknownMovesUsedByBanks[gBankTarget] != 0xFFFF + && gUnknownMovesUsedByBanks[gBankTarget] != MOVE_SKETCH) + { + s32 i; + + for (i = 0; i < 4; i++) + { + if (gBattleMons[gBankAttacker].moves[i] == MOVE_SKETCH) + continue; + if (gBattleMons[gBankAttacker].moves[i] == gUnknownMovesUsedByBanks[gBankTarget]) + break; + } + + if (i != 4) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else // sketch worked + { + struct MovePpInfo movePpData; + + gBattleMons[gBankAttacker].moves[gCurrMovePos] = gUnknownMovesUsedByBanks[gBankTarget]; + gBattleMons[gBankAttacker].pp[gCurrMovePos] = gBattleMoves[gUnknownMovesUsedByBanks[gBankTarget]].pp; + gActiveBank = gBankAttacker; + + for (i = 0; i < 4; i++) + { + movePpData.move[i] = gBattleMons[gBankAttacker].moves[i]; + movePpData.pp[i] = gBattleMons[gBankAttacker].pp[i]; + } + movePpData.ppBonuses = gBattleMons[gBankAttacker].ppBonuses; + + EmitSetMonData(0, REQUEST_MOVES_PP_BATTLE, 0, sizeof(struct MovePpInfo), &movePpData); + MarkBufferBankForExecution(gActiveBank); + + PREPARE_MOVE_BUFFER(gBattleTextBuff1, gUnknownMovesUsedByBanks[gBankTarget]) + + gBattlescriptCurrInstr += 5; + } + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + diff --git a/src/battle_ai.c b/src/battle_ai.c index 75b5eb2ed..8590b0f03 100644 --- a/src/battle_ai.c +++ b/src/battle_ai.c @@ -1802,7 +1802,7 @@ static void BattleAICmd_count_alive_pokemon(void) u32 status; bankOnField1 = gBattlePartyID[index]; status = GetBankIdentity(index) ^ 2; - bankOnField2 = gBattlePartyID[GetBankByPlayerAI(status)]; + bankOnField2 = gBattlePartyID[GetBankByIdentity(status)]; } else // in singles there's only one bank by side { diff --git a/src/calculate_base_damage.c b/src/calculate_base_damage.c index 105b334f2..8996059f9 100644 --- a/src/calculate_base_damage.c +++ b/src/calculate_base_damage.c @@ -19,7 +19,6 @@ extern struct BattleEnigmaBerry gEnigmaBerries[]; extern u16 gBattleMovePower; extern u16 gTrainerBattleOpponent_A; -u8 CountAliveMonsInBattle(u8); bool8 ShouldGetStatBadgeBoost(u16 flagId, u8 bank); extern const struct BattleMove gBattleMoves[]; diff --git a/src/pokemon_2.c b/src/pokemon_2.c index cf073570d..b6359f76a 100644 --- a/src/pokemon_2.c +++ b/src/pokemon_2.c @@ -35,7 +35,7 @@ extern const u8 gText_BadEgg[]; extern const u8 gText_EggNickname[]; extern u8 GetBankSide(u8 bank); -extern u8 GetBankByPlayerAI(u8 bank); +extern u8 GetBankByIdentity(u8 bank); extern u8 GetBankIdentity(u8 bank); u8 CountAliveMonsInBattle(u8 caseId) @@ -90,7 +90,7 @@ u8 sub_8069F34(u8 bank) status ^= 1; if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) - return GetBankByPlayerAI(status); + return GetBankByIdentity(status); if (CountAliveMonsInBattle(BATTLE_ALIVE_EXCEPT_ACTIVE) > 1) { u8 val; @@ -99,14 +99,14 @@ u8 sub_8069F34(u8 bank) val = status ^ 2; else val = status; - return GetBankByPlayerAI(val); + return GetBankByIdentity(val); } else { if ((gAbsentBankFlags & gBitTable[status])) - return GetBankByPlayerAI(status ^ 2); + return GetBankByIdentity(status ^ 2); else - return GetBankByPlayerAI(status); + return GetBankByIdentity(status); } } diff --git a/src/pokemon_3.c b/src/pokemon_3.c index aaa02c5d4..d381c7544 100644 --- a/src/pokemon_3.c +++ b/src/pokemon_3.c @@ -216,7 +216,7 @@ void sub_806CF24(s32 stat) gBankTarget = gBankInMenu; StringCopy(gBattleTextBuff1, gStatNamesTable[gUnknown_08329EC8[stat]]); StringCopy(gBattleTextBuff2, gText_StatRose); - StrCpyDecodeToDisplayedStringBattle(gText_PkmnsStatChanged2); + BattleStringExpandPlaceholdersToDisplayedString(gText_PkmnsStatChanged2); } u8 *sub_806CF78(u16 itemId) @@ -251,7 +251,7 @@ u8 *sub_806CF78(u16 itemId) else { gBankAttacker = gBankInMenu; - StrCpyDecodeToDisplayedStringBattle(gText_PkmnGettingPumped); + BattleStringExpandPlaceholdersToDisplayedString(gText_PkmnGettingPumped); } } } @@ -259,7 +259,7 @@ u8 *sub_806CF78(u16 itemId) if (itemEffect[3] & 0x80) { gBankAttacker = gBankInMenu; - StrCpyDecodeToDisplayedStringBattle(gText_PkmnShroudedInMist); + BattleStringExpandPlaceholdersToDisplayedString(gText_PkmnShroudedInMist); } return gDisplayedStringBattle; diff --git a/src/window.c b/src/window.c index 164031bee..704060b9d 100644 --- a/src/window.c +++ b/src/window.c @@ -451,7 +451,7 @@ void FillWindowPixelRect(u8 windowId, u8 fillValue, u16 x, u16 y, u16 width, u16 FillBitmapRect4Bit(&pixelRect, x, y, width, height, fillValue); } -void CopyToWindowPixelBuffer(u8 windowId, u8 *src, u16 size, u16 tileOffset) +void CopyToWindowPixelBuffer(u8 windowId, const u8 *src, u16 size, u16 tileOffset) { if (size != 0) CpuCopy16(src, gWindows[windowId].tileData + (0x20 * tileOffset), size); -- cgit v1.2.3 From 69928d3904a610791d5e34e32364d9ee5f9392ee Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Wed, 27 Sep 2017 23:43:45 +0200 Subject: battle 4 up to 0xE5 --- src/battle_3.c | 21 +- src/battle_4.c | 1756 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/pokemon_3.c | 20 +- 3 files changed, 1726 insertions(+), 71 deletions(-) (limited to 'src') diff --git a/src/battle_3.c b/src/battle_3.c index 1fd84a61b..9ac439390 100644 --- a/src/battle_3.c +++ b/src/battle_3.c @@ -261,7 +261,7 @@ u8 sub_803FB4C(void) // msg, can't select a move } } - if (IsImprisoned(gActiveBank, move)) + if (GetImprisonedMovesCount(gActiveBank, move)) { gCurrentMove = move; if (gBattleTypeFlags & BATTLE_TYPE_PALACE) @@ -314,13 +314,6 @@ u8 sub_803FB4C(void) // msg, can't select a move return limitations; } -#define MOVE_LIMITATION_ZEROMOVE (1 << 0) -#define MOVE_LIMITATION_PP (1 << 1) -#define MOVE_LIMITATION_DISABLED (1 << 2) -#define MOVE_LIMITATION_TORMENTED (1 << 3) -#define MOVE_LIMITATION_TAUNT (1 << 4) -#define MOVE_LIMITATION_IMPRISION (1 << 5) - u8 CheckMoveLimitations(u8 bank, u8 unusableMoves, u8 check) { u8 holdEffect; @@ -346,7 +339,7 @@ u8 CheckMoveLimitations(u8 bank, u8 unusableMoves, u8 check) unusableMoves |= gBitTable[i]; if (gDisableStructs[bank].tauntTimer1 && check & MOVE_LIMITATION_TAUNT && gBattleMoves[gBattleMons[bank].moves[i]].power == 0) unusableMoves |= gBitTable[i]; - if (IsImprisoned(bank, gBattleMons[bank].moves[i]) && check & MOVE_LIMITATION_IMPRISION) + 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]; @@ -374,7 +367,7 @@ bool8 AreAllMovesUnusable(void) return (unusable == 0xF); } -u8 IsImprisoned(u8 bank, u16 move) +u8 GetImprisonedMovesCount(u8 bank, u16 move) { s32 i; u8 imprisionedMoves = 0; @@ -382,7 +375,7 @@ u8 IsImprisoned(u8 bank, u16 move) for (i = 0; i < gNoOfAllBanks; i++) { - if (bankSide != GetBankSide(i) && gStatuses3[i] & STATUS3_IMPRISIONED) + if (bankSide != GetBankSide(i) && gStatuses3[i] & STATUS3_IMPRISONED_OTHERS) { s32 j; for (j = 0; j < 4; j++) @@ -1327,7 +1320,7 @@ u8 AtkCanceller_UnableToUseMove(void) gBattleStruct->atkCancellerTracker++; break; case 8: // imprisoned - if (IsImprisoned(gBankAttacker, gCurrentMove)) + if (GetImprisonedMovesCount(gBankAttacker, gCurrentMove)) { gProtectStructs[gBankAttacker].usedImprisionedMove = 1; CancelMultiTurnMoves(gBankAttacker); @@ -2379,7 +2372,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) } } break; - case ABILITYEFFECT_COUNT_OTHER_SIZE: // 16 + case ABILITYEFFECT_COUNT_OTHER_SIDE: // 16 side = GetBankSide(bank); for (i = 0; i < gNoOfAllBanks; i++) { @@ -6238,7 +6231,7 @@ u8 GetMoveTarget(u16 move, u8 useMoveTarget) targetBank = Random() % gNoOfAllBanks; } while (targetBank == gBankAttacker || side == GetBankSide(targetBank) || gAbsentBankFlags & gBitTable[targetBank]); if (gBattleMoves[move].type == TYPE_ELECTRIC - && AbilityBattleEffects(ABILITYEFFECT_COUNT_OTHER_SIZE, gBankAttacker, ABILITY_LIGHTNING_ROD, 0, 0) + && AbilityBattleEffects(ABILITYEFFECT_COUNT_OTHER_SIDE, gBankAttacker, ABILITY_LIGHTNING_ROD, 0, 0) && gBattleMons[targetBank].ability != ABILITY_LIGHTNING_ROD) { targetBank ^= 2; diff --git a/src/battle_4.c b/src/battle_4.c index 0f52ee0dd..9ef443b70 100644 --- a/src/battle_4.c +++ b/src/battle_4.c @@ -29,6 +29,7 @@ #include "pokemon_icon.h" #include "pokemon_item_effects.h" #include "m4a.h" +#include "mail.h" // variables @@ -96,6 +97,7 @@ extern u16 gUnknownMovesUsedByBanks[BATTLE_BANKS_COUNT]; extern u16 gLastUsedMovesByBanks[BATTLE_BANKS_COUNT]; extern u16 gTrainerBattleOpponent_A; extern u16 gTrainerBattleOpponent_B; +extern u8 gUnknown_020241E9; extern struct MusicPlayerInfo gMPlay_BGM; struct TrainerMoney @@ -127,6 +129,7 @@ extern void sub_81A5BF8(void); // battle frontier 2 extern void sub_81A5D44(void); // battle frontier 2 extern void sub_81B8E80(u8 bank, u8, u8); // party menu extern bool8 sub_81B1250(void); // ? +extern u8 GetScaledHPFraction(s16 hp, s16 maxhp, u8 scale); // battle interface // BattleScripts extern const u8 BattleScript_MoveEnd[]; @@ -150,7 +153,7 @@ extern const u8 BattleScript_ItemSteal[]; extern const u8 BattleScript_RapidSpinAway[]; extern const u8 BattleScript_TargetPRLZHeal[]; extern const u8 BattleScript_KnockedOff[]; -extern const u8 BattleScript_StickyHoldOnKnockOff[]; +extern const u8 BattleScript_StickyHoldActivates[]; extern const u8 BattleScript_AllStatsUp[]; extern const u8 BattleScript_AtkDefDown[]; extern const u8 BattleScript_SAtkDown2[]; @@ -197,6 +200,7 @@ extern const u8 gUnknown_082DADD8[]; extern const u8 BattleScript_PrintPayDayMoneyString[]; extern const u8 BattleScript_SturdyPreventsOHKO[]; extern const u8 BattleScript_ObliviousPreventsAttraction[]; +extern const u8 BattleScript_PauseEffectivenessSoundResultMsgEndMove[]; // strings extern const u8 gText_BattleYesNoChoice[]; @@ -252,7 +256,7 @@ void atk11_printstring_playeronly(void); void atk12_waitmessage(void); void atk13_printfromtable(void); void atk14_printfromtable_playeronly(void); -void atk15_seteffectwithchancetarget(void); +void atk15_seteffectwithchance(void); void atk16_seteffectprimary(void); void atk17_seteffectsecondary(void); void atk18_status_effect_clear(void); @@ -421,15 +425,15 @@ void atkBA_jumpifnopursuitswitchdmg(void); void atkBB_setsunny(void); void atkBC_maxattackhalvehp(void); void atkBD_copyfoestats(void); -void atkBE_breakfree(void); +void atkBE_rapidspinfree(void); void atkBF_set_defense_curl(void); void atkC0_recoverbasedonsunlight(void); void atkC1_hidden_power(void); void atkC2_selectnexttarget(void); void atkC3_setfutureattack(void); void atkC4_beat_up(void); -void atkC5_hidepreattack(void); -void atkC6_unhidepostattack(void); +void atkC5_setsemiinvulnerablebit(void); +void atkC6_clearsemiinvulnerablebit(void); void atkC7_setminimize(void); void atkC8_sethail(void); void atkC9_jumpifattackandspecialattackcannotfall(void); @@ -458,7 +462,7 @@ void atkDF_setmagiccoat(void); void atkE0_setstealstatchange(void); void atkE1_intimidate_string_loader(void); void atkE2_switchout_abilities(void); -void atkE3_jumpiffainted(void); +void atkE3_jumpifhasnohp(void); void atkE4_getsecretpowereffect(void); void atkE5_pickup(void); void atkE6_castform_change_animation(void); @@ -504,7 +508,7 @@ void (* const gBattleScriptingCommandsTable[])(void) = atk12_waitmessage, atk13_printfromtable, atk14_printfromtable_playeronly, - atk15_seteffectwithchancetarget, + atk15_seteffectwithchance, atk16_seteffectprimary, atk17_seteffectsecondary, atk18_status_effect_clear, @@ -673,15 +677,15 @@ void (* const gBattleScriptingCommandsTable[])(void) = atkBB_setsunny, atkBC_maxattackhalvehp, atkBD_copyfoestats, - atkBE_breakfree, + atkBE_rapidspinfree, atkBF_set_defense_curl, atkC0_recoverbasedonsunlight, atkC1_hidden_power, atkC2_selectnexttarget, atkC3_setfutureattack, atkC4_beat_up, - atkC5_hidepreattack, - atkC6_unhidepostattack, + atkC5_setsemiinvulnerablebit, + atkC6_clearsemiinvulnerablebit, atkC7_setminimize, atkC8_sethail, atkC9_jumpifattackandspecialattackcannotfall, @@ -710,7 +714,7 @@ void (* const gBattleScriptingCommandsTable[])(void) = atkE0_setstealstatchange, atkE1_intimidate_string_loader, atkE2_switchout_abilities, - atkE3_jumpiffainted, + atkE3_jumpifhasnohp, atkE4_getsecretpowereffect, atkE5_pickup, atkE6_castform_change_animation, @@ -871,6 +875,8 @@ static const struct WindowTemplate sUnusedWinTemplate = {0, 1, 3, 7, 0xF, 0x1F, extern const struct SpriteTemplate SpriteTemplate_MonIconOnLvlUpBox; extern const u16 sProtectSuccessRates[]; +extern const u16 sNaturePowerMoves[]; +extern const u16 sWeightToDamageTable[]; void atk00_attackcanceler(void) { @@ -1163,7 +1169,7 @@ void atk02_attackstring(void) void atk03_ppreduce(void) { - s32 to_deduct = 1; + s32 ppToDeduct = 1; if (gBattleExecBuffer) return; @@ -1173,15 +1179,15 @@ void atk03_ppreduce(void) switch (gBattleMoves[gCurrentMove].target) { case MOVE_TARGET_FOES_AND_ALLY: - to_deduct += AbilityBattleEffects(ABILITYEFFECT_COUNT_ON_FIELD, gBankAttacker, ABILITY_PRESSURE, 0, 0); + ppToDeduct += AbilityBattleEffects(ABILITYEFFECT_COUNT_ON_FIELD, gBankAttacker, ABILITY_PRESSURE, 0, 0); break; case MOVE_TARGET_BOTH: case MOVE_TARGET_OPPONENTS_FIELD: - to_deduct += AbilityBattleEffects(ABILITYEFFECT_COUNT_OTHER_SIZE, gBankAttacker, ABILITY_PRESSURE, 0, 0); + ppToDeduct += AbilityBattleEffects(ABILITYEFFECT_COUNT_OTHER_SIDE, gBankAttacker, ABILITY_PRESSURE, 0, 0); break; default: if (gBankAttacker != gBankTarget && gBattleMons[gBankTarget].ability == ABILITY_PRESSURE) - to_deduct++; + ppToDeduct++; break; } } @@ -1190,8 +1196,8 @@ void atk03_ppreduce(void) { gProtectStructs[gBankAttacker].notFirstStrike = 1; - if (gBattleMons[gBankAttacker].pp[gCurrMovePos] > to_deduct) - gBattleMons[gBankAttacker].pp[gCurrMovePos] -= to_deduct; + if (gBattleMons[gBankAttacker].pp[gCurrMovePos] > ppToDeduct) + gBattleMons[gBankAttacker].pp[gCurrMovePos] -= ppToDeduct; else gBattleMons[gBankAttacker].pp[gCurrMovePos] = 0; @@ -2126,10 +2132,10 @@ void atk13_printfromtable(void) { if (gBattleExecBuffer == 0) { - u16 *ptr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + const u16 *ptr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); ptr += gBattleCommunication[MULTISTRING_CHOOSER]; - PrepareStringBattle(*(u16*)ptr, gBankAttacker); + PrepareStringBattle(*ptr, gBankAttacker); gBattlescriptCurrInstr += 5; gBattleCommunication[MSG_DISPLAY] = 1; @@ -2140,11 +2146,11 @@ void atk14_printfromtable_playeronly(void) { if (gBattleExecBuffer == 0) { - u16 *ptr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + const u16 *ptr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); ptr += gBattleCommunication[MULTISTRING_CHOOSER]; gActiveBank = gBankAttacker; - EmitPrintStringPlayerOnly(0, *(u16*)ptr); + EmitPrintStringPlayerOnly(0, *ptr); MarkBufferBankForExecution(gActiveBank); gBattlescriptCurrInstr += 5; @@ -2729,23 +2735,17 @@ void SetMoveEffect(bool8 primary, u8 certain) gLastUsedAbility = gBattleMons[gBankTarget].ability; RecordAbilityBattle(gBankTarget, gLastUsedAbility); } - else if (gBattleMons[gBankAttacker].item + else if (gBattleMons[gBankAttacker].item != 0 || gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY - || (gBattleMons[gBankTarget].item > 0x78 && gBattleMons[gBankTarget].item < 0x85) + || IS_ITEM_MAIL(gBattleMons[gBankTarget].item) || gBattleMons[gBankTarget].item == 0) { gBattlescriptCurrInstr++; } else { - // This is a leftover from R/S direct use of ewram addresses - u16* changedItem; - GET_CHANGED_ITEM_PTR_VIA_MEME_ACCESS(gBankAttacker, changedItem); + u16* changedItem = &gBattleStruct->changedItems[gBankAttacker]; gLastUsedItem = *changedItem = gBattleMons[gBankTarget].item; - - // A sane representation of this would simply be: - // gLastUsedItem = gBattleStruct->changedItems[gBankAttacker] = gBattleMons[gBankTarget].item; - gBattleMons[gBankTarget].item = 0; gActiveBank = gBankAttacker; @@ -2833,7 +2833,7 @@ void SetMoveEffect(bool8 primary, u8 certain) else { gLastUsedAbility = ABILITY_STICKY_HOLD; - gBattlescriptCurrInstr = BattleScript_StickyHoldOnKnockOff; + gBattlescriptCurrInstr = BattleScript_StickyHoldActivates; RecordAbilityBattle(gEffectBank, ABILITY_STICKY_HOLD); } break; @@ -2868,7 +2868,7 @@ void SetMoveEffect(bool8 primary, u8 certain) gBattleCommunication[MOVE_EFFECT_BYTE] = 0; } -void atk15_seteffectwithchancetarget(void) +void atk15_seteffectwithchance(void) { u32 percentChance; @@ -3351,8 +3351,8 @@ void atk23_getexp(void) } else { - i = 0x149; - } + i = 0x149; + } // get exp getter bank if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) @@ -4816,8 +4816,7 @@ void atk49_moveend(void) case 7: // changed held items for (i = 0; i < gNoOfAllBanks; i++) { - u16* changedItem; - GET_CHANGED_ITEM_PTR_VIA_MEME_ACCESS(i, changedItem); + u16* changedItem = &gBattleStruct->changedItems[i]; if (*changedItem != 0) { gBattleMons[i].item = *changedItem; @@ -5775,8 +5774,7 @@ void atk52_switch_in_effects(void) for (i = 0; i < gNoOfAllBanks; i++) { - u16* hpOnSwitchout; - GET_HP_SWITCHOUT_PTR_VIA_MEME_ACCESS(GetBankSide(i), hpOnSwitchout) + u16* hpOnSwitchout = &gBattleStruct->hpOnSwitchout[GetBankSide(i)]; *hpOnSwitchout = gBattleMons[i].hp; } @@ -6413,7 +6411,7 @@ void atk6A_removeitem(void) gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); - GET_USED_ITEM_PTR_VIA_MEME_ACCESS(gActiveBank, usedHeldItem) + usedHeldItem = &gBattleStruct->usedHeldItems[gActiveBank]; *usedHeldItem = gBattleMons[gActiveBank].item; gBattleMons[gActiveBank].item = 0; @@ -6653,7 +6651,7 @@ bool8 sub_804F344(void) return (gBattle_BG2_X != 0x1A0); } -#define MON_ICON_LVLUP_BOX_TAG 0xD75A +#define MON_ICON_LVLUP_BOX_TAG 0xD75A #define sDestroy data0 #define sSavedLvlUpBoxXPosition data1 @@ -8148,9 +8146,9 @@ void atk97_try_infatuation(void) || gBattleMons[gBankTarget].status2 & STATUS2_INFATUATION || GetGenderFromSpeciesAndPersonality(speciesAttacker, personalityAttacker) == MON_GENDERLESS || GetGenderFromSpeciesAndPersonality(speciesTarget, personalityTarget) == MON_GENDERLESS) - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } else { gBattleMons[gBankTarget].status2 |= STATUS2_INFATUATED_WITH(gBankAttacker); @@ -8296,8 +8294,9 @@ void atk9C_set_substitute(void) } extern const u16 gMovesForbiddenToCopy[]; -#define MIMIC_FORBIDDEN_END 0xFFFE -#define METRONOME_SLEEPTALK_FORBIDDEN_END 0xFFFF +#define MIMIC_FORBIDDEN_END 0xFFFE +#define METRONOME_FORBIDDEN_END 0xFFFF +#define ASSIST_FORBIDDEN_END 0xFFFF static bool8 IsMoveUncopyableByMimic(u16 move) { @@ -8368,11 +8367,11 @@ void atk9E_metronome(void) { if (*move == gCurrentMove) break; - if (*move == METRONOME_SLEEPTALK_FORBIDDEN_END) + if (*move == METRONOME_FORBIDDEN_END) break; } - if (*move == METRONOME_SLEEPTALK_FORBIDDEN_END) + if (*move == METRONOME_FORBIDDEN_END) break; } @@ -8974,3 +8973,1666 @@ void atkA8_copymovepermanently(void) // sketch } } +bool8 IsTwoTurnsMove(u16 move) +{ + if (gBattleMoves[move].effect == EFFECT_SKULL_BASH + || gBattleMoves[move].effect == EFFECT_RAZOR_WIND + || gBattleMoves[move].effect == EFFECT_SKY_ATTACK + || gBattleMoves[move].effect == EFFECT_SOLARBEAM + || gBattleMoves[move].effect == EFFECT_FLY + || gBattleMoves[move].effect == EFFECT_BIDE) + return TRUE; + else + return FALSE; +} + +static bool8 IsInvalidForSleepTalkOrAssist(u16 move) +{ + if (move == 0 || move == MOVE_SLEEP_TALK || move == MOVE_ASSIST + || move == MOVE_MIRROR_MOVE || move == MOVE_METRONOME) + return TRUE; + else + return FALSE; +} + +u8 AttacksThisTurn(u8 bank, u16 move) // Note: returns 1 if it's a charging turn, otherwise 2 +{ + // first argument is unused + if (gBattleMoves[move].effect == EFFECT_SOLARBEAM + && (gBattleWeather & WEATHER_SUN_ANY)) + return 2; + + if (gBattleMoves[move].effect == EFFECT_SKULL_BASH + || gBattleMoves[move].effect == EFFECT_RAZOR_WIND + || gBattleMoves[move].effect == EFFECT_SKY_ATTACK + || gBattleMoves[move].effect == EFFECT_SOLARBEAM + || gBattleMoves[move].effect == EFFECT_FLY + || gBattleMoves[move].effect == EFFECT_BIDE) + { + if ((gHitMarker & HITMARKER_x8000000)) + return 1; + } + return 2; +} + +void atkA9_sleeptalk_choose_move(void) +{ + s32 i; + u8 unusableMovesBits = 0; + + for (i = 0; i < 4; i++) + { + if (IsInvalidForSleepTalkOrAssist(gBattleMons[gBankAttacker].moves[i]) + || gBattleMons[gBankAttacker].moves[i] == MOVE_FOCUS_PUNCH + || gBattleMons[gBankAttacker].moves[i] == MOVE_UPROAR + || IsTwoTurnsMove(gBattleMons[gBankAttacker].moves[i])) + { + unusableMovesBits |= gBitTable[i]; + } + + } + + unusableMovesBits = CheckMoveLimitations(gBankAttacker, unusableMovesBits, ~(MOVE_LIMITATION_PP)); + if (unusableMovesBits == 0xF) // all 4 moves cannot be chosen + { + gBattlescriptCurrInstr += 5; + } + else // at least one move can be chosen + { + u32 movePosition; + + do + { + movePosition = Random() & 3; + } while ((gBitTable[movePosition] & unusableMovesBits)); + + gRandomMove = gBattleMons[gBankAttacker].moves[movePosition]; + gCurrMovePos = movePosition; + gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); + gBankTarget = GetMoveTarget(gRandomMove, 0); + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +void atkAA_set_destinybond(void) +{ + gBattleMons[gBankAttacker].status2 |= STATUS2_DESTINY_BOND; + gBattlescriptCurrInstr++; +} + +void DestinyBondFlagUpdate(void) +{ + u8 sideAttacker = GetBankSide(gBankAttacker); + u8 sideTarget = GetBankSide(gBankTarget); + if (gBattleMons[gBankTarget].status2 & STATUS2_DESTINY_BOND + && sideAttacker != sideTarget + && !(gHitMarker & HITMARKER_GRUDGE)) + { + gHitMarker |= HITMARKER_DESTINYBOND; + } +} + +void atkAB_DestinyBondFlagUpdate(void) +{ + DestinyBondFlagUpdate(); + gBattlescriptCurrInstr++; +} + +extern const u8 sFlailHpScaleToPowerTable[12]; + +void atkAC_remaininghptopower(void) +{ + s32 i; + s32 hpFraction = GetScaledHPFraction(gBattleMons[gBankAttacker].hp, gBattleMons[gBankAttacker].maxHP, 48); + + for (i = 0; i < (s32) sizeof(sFlailHpScaleToPowerTable); i += 2) + { + if (hpFraction <= sFlailHpScaleToPowerTable[i]) + break; + } + + gDynamicBasePower = sFlailHpScaleToPowerTable[i + 1]; + gBattlescriptCurrInstr++; +} + +void atkAD_spite_ppreduce(void) +{ + if (gLastUsedMovesByBanks[gBankTarget] != 0 + && gLastUsedMovesByBanks[gBankTarget] != 0xFFFF) + { + s32 i; + + for (i = 0; i < 4; i++) + { + if (gLastUsedMovesByBanks[gBankTarget] == gBattleMons[gBankTarget].moves[i]) + break; + } + + if (i != 4 && gBattleMons[gBankTarget].pp[i] > 1) + { + s32 ppToDeduct = (Random() & 3) + 2; + if (gBattleMons[gBankTarget].pp[i] < ppToDeduct) + ppToDeduct = gBattleMons[gBankTarget].pp[i]; + + PREPARE_MOVE_BUFFER(gBattleTextBuff1, gLastUsedMovesByBanks[gBankTarget]) + + ConvertIntToDecimalStringN(gBattleTextBuff2, ppToDeduct, 0, 1); + + PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff2, 1, ppToDeduct) + + gBattleMons[gBankTarget].pp[i] -= ppToDeduct; + gActiveBank = gBankTarget; + + if (!(gDisableStructs[gActiveBank].unk18_b & gBitTable[i]) + && !(gBattleMons[gActiveBank].status2 & STATUS2_TRANSFORMED)) + { + EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + i, 0, 1, &gBattleMons[gActiveBank].pp[i]); + MarkBufferBankForExecution(gActiveBank); + } + + gBattlescriptCurrInstr += 5; + + if (gBattleMons[gBankTarget].pp[i] == 0) + CancelMultiTurnMoves(gBankTarget); + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +void atkAE_heal_party_status(void) +{ + u32 zero = 0; + u8 toHeal = 0; + + if (gCurrentMove == MOVE_HEAL_BELL) + { + struct Pokemon* party; + s32 i; + + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + + if (GetBankSide(gBankAttacker) == SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + if (gBattleMons[gBankAttacker].ability != ABILITY_SOUNDPROOF) + { + gBattleMons[gBankAttacker].status1 = 0; + gBattleMons[gBankAttacker].status2 &= ~(STATUS2_NIGHTMARE); + } + else + { + RecordAbilityBattle(gBankAttacker, gBattleMons[gBankAttacker].ability); + gBattleCommunication[MULTISTRING_CHOOSER] |= 1; + } + + gActiveBank = gBattleScripting.bank = GetBankByIdentity(GetBankIdentity(gBankAttacker) ^ BIT_MON); + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && !(gAbsentBankFlags & gBitTable[gActiveBank])) + { + if (gBattleMons[gActiveBank].ability != ABILITY_SOUNDPROOF) + { + gBattleMons[gActiveBank].status1 = 0; + gBattleMons[gActiveBank].status2 &= ~(STATUS2_NIGHTMARE); + } + else + { + RecordAbilityBattle(gActiveBank, gBattleMons[gActiveBank].ability); + gBattleCommunication[MULTISTRING_CHOOSER] |= 2; + } + } + + for (i = 0; i < 6; i++) + { + u16 species = GetMonData(&party[i], MON_DATA_SPECIES2); + u8 abilityBit = GetMonData(&party[i], MON_DATA_ALT_ABILITY); + + if (species != 0 && species != SPECIES_EGG) + { + u8 ability; + + if (gBattlePartyID[gBankAttacker] == i) + ability = gBattleMons[gBankAttacker].ability; + else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && gBattlePartyID[gActiveBank] == i + && !(gAbsentBankFlags & gBitTable[gActiveBank])) + ability = gBattleMons[gActiveBank].ability; + else + ability = GetAbilityBySpecies(species, abilityBit); + + if (ability != ABILITY_SOUNDPROOF) + toHeal |= (1 << i); + } + } + } + else // Aromatherapy + { + gBattleCommunication[MULTISTRING_CHOOSER] = 4; + toHeal = 0x3F; + + gBattleMons[gBankAttacker].status1 = 0; + gBattleMons[gBankAttacker].status2 &= ~(STATUS2_NIGHTMARE); + + gActiveBank = GetBankByIdentity(GetBankIdentity(gBankAttacker) ^ 2); + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && !(gAbsentBankFlags & gBitTable[gActiveBank])) + { + gBattleMons[gActiveBank].status1 = 0; + gBattleMons[gActiveBank].status2 &= ~(STATUS2_NIGHTMARE); + } + + } + + if (toHeal) + { + gActiveBank = gBankAttacker; + EmitSetMonData(0, REQUEST_STATUS_BATTLE, toHeal, 4, &zero); + MarkBufferBankForExecution(gActiveBank); + } + + gBattlescriptCurrInstr++; +} + +void atkAF_cursetarget(void) +{ + if (gBattleMons[gBankTarget].status2 & STATUS2_CURSED) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gBattleMons[gBankTarget].status2 |= STATUS2_CURSED; + gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 2; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + + gBattlescriptCurrInstr += 5; + } +} + +void atkB0_set_spikes(void) +{ + u8 targetSide = GetBankSide(gBankAttacker) ^ BIT_SIDE; + + if (gSideTimers[targetSide].spikesAmount == 3) + { + gSpecialStatuses[gBankAttacker].flag20 = 1; + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gSideAffecting[targetSide] |= SIDE_STATUS_SPIKES; + gSideTimers[targetSide].spikesAmount++; + gBattlescriptCurrInstr += 5; + } +} + +void atkB1_set_foresight(void) +{ + gBattleMons[gBankTarget].status2 |= STATUS2_FORESIGHT; + gBattlescriptCurrInstr++; +} + +void atkB2_setperishsong(void) +{ + s32 i; + s32 notAffectedCount = 0; + + for (i = 0; i < gNoOfAllBanks; i++) + { + if (gStatuses3[i] & STATUS3_PERISH_SONG + || gBattleMons[i].ability == ABILITY_SOUNDPROOF) + { + notAffectedCount++; + } + else + { + gStatuses3[i] |= STATUS3_PERISH_SONG; + gDisableStructs[i].perishSong1 = 3; + gDisableStructs[i].perishSong2 = 3; + } + } + + PressurePPLoseOnUsingPerishSong(gBankAttacker); + + if (notAffectedCount == gNoOfAllBanks) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + else + gBattlescriptCurrInstr += 5; +} + +void atkB3_rolloutdamagecalculation(void) +{ + if (gBattleMoveFlags & MOVESTATUS_NOEFFECT) + { + CancelMultiTurnMoves(gBankAttacker); + gBattlescriptCurrInstr = BattleScript_PauseEffectivenessSoundResultMsgEndMove; + } + else + { + s32 i; + + if (!(gBattleMons[gBankAttacker].status2 & STATUS2_MULTIPLETURNS)) // first hit + { + gDisableStructs[gBankAttacker].rolloutTimer1 = 5; + gDisableStructs[gBankAttacker].rolloutTimer2 = 5; + gBattleMons[gBankAttacker].status2 |= STATUS2_MULTIPLETURNS; + gLockedMoves[gBankAttacker] = gCurrentMove; + } + if (--gDisableStructs[gBankAttacker].rolloutTimer1 == 0) // last hit + { + gBattleMons[gBankAttacker].status2 &= ~(STATUS2_MULTIPLETURNS); + } + + gDynamicBasePower = gBattleMoves[gCurrentMove].power; + + for (i = 1; i < (5 - gDisableStructs[gBankAttacker].rolloutTimer1); i++) + gDynamicBasePower *= 2; + + if (gBattleMons[gBankAttacker].status2 & STATUS2_DEFENSE_CURL) + gDynamicBasePower *= 2; + + gBattlescriptCurrInstr++; + } +} + +void atkB4_jumpifconfusedandstatmaxed(void) +{ + if (gBattleMons[gBankTarget].status2 & STATUS2_CONFUSION + && gBattleMons[gBankTarget].statStages[gBattlescriptCurrInstr[1]] == 0xC) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + else + gBattlescriptCurrInstr += 6; +} + +void atkB5_furycuttercalc(void) +{ + if (gBattleMoveFlags & MOVESTATUS_NOEFFECT) + { + gDisableStructs[gBankAttacker].furyCutterCounter = 0; + gBattlescriptCurrInstr = BattleScript_PauseEffectivenessSoundResultMsgEndMove; + } + else + { + s32 i; + + if (gDisableStructs[gBankAttacker].furyCutterCounter != 5) + gDisableStructs[gBankAttacker].furyCutterCounter++; + + gDynamicBasePower = gBattleMoves[gCurrentMove].power; + + for (i = 1; i < gDisableStructs[gBankAttacker].furyCutterCounter; i++) + gDynamicBasePower *= 2; + + gBattlescriptCurrInstr++; + } +} + +void atkB6_happinesstodamagecalculation(void) +{ + if (gBattleMoves[gCurrentMove].effect == EFFECT_RETURN) + gDynamicBasePower = 10 * (gBattleMons[gBankAttacker].friendship) / 25; + else // EFFECT_FRUSTRATION + gDynamicBasePower = 10 * (255 - gBattleMons[gBankAttacker].friendship) / 25; + + gBattlescriptCurrInstr++; +} + +extern const u8 BattleScript_PresentDamageTarget[]; +extern const u8 BattleScript_AlreadyAtFullHp[]; +extern const u8 BattleScript_PresentHealTarget[]; + +void atkB7_presentdamagecalculation(void) +{ + s32 rand = Random() & 0xFF; + + if (rand < 102) + gDynamicBasePower = 40; + else if (rand < 178) + gDynamicBasePower = 80; + else if (rand < 204) + gDynamicBasePower = 120; + else + { + gBattleMoveDamage = gBattleMons[gBankTarget].maxHP / 4; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + gBattleMoveDamage *= -1; + } + if (rand < 204) + gBattlescriptCurrInstr = BattleScript_PresentDamageTarget; + else if (gBattleMons[gBankTarget].maxHP == gBattleMons[gBankTarget].hp) + gBattlescriptCurrInstr = BattleScript_AlreadyAtFullHp; + else + { + gBattleMoveFlags &= ~(MOVESTATUS_NOTAFFECTED); + gBattlescriptCurrInstr = BattleScript_PresentHealTarget; + } +} + +void atkB8_set_safeguard(void) +{ + if (gSideAffecting[GET_BANK_SIDE(gBankAttacker)] & SIDE_STATUS_SAFEGUARD) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + else + { + gSideAffecting[GET_BANK_SIDE(gBankAttacker)] |= SIDE_STATUS_SAFEGUARD; + gSideTimers[GET_BANK_SIDE(gBankAttacker)].safeguardTimer = 5; + gSideTimers[GET_BANK_SIDE(gBankAttacker)].safeguardBank = gBankAttacker; + gBattleCommunication[MULTISTRING_CHOOSER] = 5; + } + + gBattlescriptCurrInstr++; +} + +void atkB9_magnitudedamagecalculation(void) +{ + s32 magnitude = Random() % 100; + + if (magnitude < 5) + { + gDynamicBasePower = 10; + magnitude = 4; + } + else if (magnitude < 15) + { + gDynamicBasePower = 30; + magnitude = 5; + } + else if (magnitude < 35) + { + gDynamicBasePower = 50; + magnitude = 6; + } + else if (magnitude < 65) + { + gDynamicBasePower = 70; + magnitude = 7; + } + else if (magnitude < 85) + { + gDynamicBasePower = 90; + magnitude = 8; + } + else if (magnitude < 95) + { + gDynamicBasePower = 110; + magnitude = 9; + } + else + { + gDynamicBasePower = 150; + magnitude = 10; + } + + + PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff1, 2, magnitude) + + for (gBankTarget = 0; gBankTarget < gNoOfAllBanks; gBankTarget++) + { + if (gBankTarget == gBankAttacker) + continue; + if (!(gAbsentBankFlags & gBitTable[gBankTarget])) // a valid target was found + break; + } + + gBattlescriptCurrInstr++; +} + +void atkBA_jumpifnopursuitswitchdmg(void) +{ + if (gMultiHitCounter == 1) + { + if (GetBankSide(gBankAttacker) == SIDE_PLAYER) + gBankTarget = GetBankByIdentity(IDENTITY_OPPONENT_MON1); + else + gBankTarget = GetBankByIdentity(IDENTITY_PLAYER_MON1); + } + else + { + if (GetBankSide(gBankAttacker) == SIDE_PLAYER) + gBankTarget = GetBankByIdentity(IDENTITY_OPPONENT_MON2); + else + gBankTarget = GetBankByIdentity(IDENTITY_PLAYER_MON2); + } + + if (gActionForBanks[gBankTarget] == 0 + && gBankAttacker == *(gBattleStruct->moveTarget + gBankTarget) + && !(gBattleMons[gBankTarget].status1 & (STATUS_SLEEP | STATUS_FREEZE)) + && gBattleMons[gBankAttacker].hp + && !gDisableStructs[gBankTarget].truantCounter + && gChosenMovesByBanks[gBankTarget] == MOVE_PURSUIT) + { + s32 i; + + for (i = 0; i < gNoOfAllBanks; i++) + { + if (gTurnOrder[i] == gBankTarget) + gUnknown_0202407A[i] = 11; + } + + gCurrentMove = MOVE_PURSUIT; + gCurrMovePos = gUnknown_020241E9 = *(gBattleStruct->chosenMovesIds + gBankTarget); + gBattlescriptCurrInstr += 5; + gBattleScripting.animTurn = 1; + gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +void atkBB_setsunny(void) +{ + if (gBattleWeather & WEATHER_SUN_ANY) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + } + else + { + gBattleWeather = WEATHER_SUN_TEMPORARY; + gBattleCommunication[MULTISTRING_CHOOSER] = 4; + gWishFutureKnock.weatherDuration = 5; + } + + gBattlescriptCurrInstr++; +} + +void atkBC_maxattackhalvehp(void) // belly drum +{ + u32 halfHp = gBattleMons[gBankAttacker].maxHP / 2; + + if (!(gBattleMons[gBankAttacker].maxHP / 2)) + halfHp = 1; + + if (gBattleMons[gBankAttacker].statStages[STAT_STAGE_ATK] < 12 + && gBattleMons[gBankAttacker].hp > halfHp) + { + gBattleMons[gBankAttacker].statStages[STAT_STAGE_ATK] = 12; + gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 2; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +void atkBD_copyfoestats(void) // psych up +{ + s32 i; + + for (i = 0; i < BATTLE_STATS_NO; i++) + { + gBattleMons[gBankAttacker].statStages[i] = gBattleMons[gBankTarget].statStages[i]; + } + + gBattlescriptCurrInstr += 5; // Has an unused jump ptr(possibly for a failed attempt) parameter. +} + +extern const u8 BattleScript_WrapFree[]; +extern const u8 BattleScript_LeechSeedFree[]; +extern const u8 BattleScript_SpikesFree[]; + +void atkBE_rapidspinfree(void) +{ + if (gBattleMons[gBankAttacker].status2 & STATUS2_WRAPPED) + { + gBattleScripting.bank = gBankTarget; + gBattleMons[gBankAttacker].status2 &= ~(STATUS2_WRAPPED); + gBankTarget = *(gBattleStruct->wrappedBy + gBankAttacker); + + gBattleTextBuff1[0] = B_BUFF_PLACEHOLDER_BEGIN; + gBattleTextBuff1[1] = B_BUFF_MOVE; + gBattleTextBuff1[2] = *(gBattleStruct->wrappedMove + gBankAttacker * 2 + 0); + gBattleTextBuff1[3] = *(gBattleStruct->wrappedMove + gBankAttacker * 2 + 1); + gBattleTextBuff1[4] = B_BUFF_EOS; + + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_WrapFree; + } + else if (gStatuses3[gBankAttacker] & STATUS3_LEECHSEED) + { + gStatuses3[gBankAttacker] &= ~(STATUS3_LEECHSEED); + gStatuses3[gBankAttacker] &= ~(STATUS3_LEECHSEED_BANK); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_LeechSeedFree; + } + else if (gSideAffecting[GetBankSide(gBankAttacker)] & SIDE_STATUS_SPIKES) + { + gSideAffecting[GetBankSide(gBankAttacker)] &= ~(SIDE_STATUS_SPIKES); + gSideTimers[GetBankSide(gBankAttacker)].spikesAmount = 0; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_SpikesFree; + } + else + { + gBattlescriptCurrInstr++; + } +} + +void atkBF_set_defense_curl(void) +{ + gBattleMons[gBankAttacker].status2 |= STATUS2_DEFENSE_CURL; + gBattlescriptCurrInstr++; +} + +void atkC0_recoverbasedonsunlight(void) +{ + gBankTarget = gBankAttacker; + + if (gBattleMons[gBankAttacker].hp != gBattleMons[gBankAttacker].maxHP) + { + if (gBattleWeather == 0 || !WEATHER_HAS_EFFECT) + gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 2; + else if (gBattleWeather & WEATHER_SUN_ANY) + gBattleMoveDamage = 20 * gBattleMons[gBankAttacker].maxHP / 30; + else // not sunny weather + gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 4; + + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + gBattleMoveDamage *= -1; + + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +#ifdef NONMATCHING +void atkC1_hidden_power(void) +{ + s32 powerBits; + s32 typeBits; + + powerBits = ((gBattleMons[gBankAttacker].hpIV & 2) >> 1) + | ((gBattleMons[gBankAttacker].attackIV & 2) << 0) + | ((gBattleMons[gBankAttacker].defenseIV & 2) << 1) + | ((gBattleMons[gBankAttacker].speedIV & 2) << 2) + | ((gBattleMons[gBankAttacker].spAttackIV & 2) << 3) + | ((gBattleMons[gBankAttacker].spDefenseIV & 2) << 4); + + typeBits = ((gBattleMons[gBankAttacker].hpIV & 1) << 0) + | ((gBattleMons[gBankAttacker].attackIV & 1) << 1) + | ((gBattleMons[gBankAttacker].defenseIV & 1) << 2) + | ((gBattleMons[gBankAttacker].speedIV & 1) << 3) + | ((gBattleMons[gBankAttacker].spAttackIV & 1) << 4) + | ((gBattleMons[gBankAttacker].spDefenseIV & 1) << 5); + + gDynamicBasePower = (40 * powerBits) / 63 + 30; + + gBattleStruct->dynamicMoveType = (15 * typeBits) / 63 + 1; + if (gBattleStruct->dynamicMoveType > 8) + gBattleStruct->dynamicMoveType++; + gBattleStruct->dynamicMoveType |= 0xC0; + + gBattlescriptCurrInstr++; +} + +#else +__attribute__((naked)) +void atkC1_hidden_power(void) +{ + asm(".syntax unified\n\ + push {r4-r7,lr}\n\ + mov r7, r10\n\ + mov r6, r9\n\ + mov r5, r8\n\ + push {r5-r7}\n\ + ldr r2, =gBattleMons\n\ + ldr r0, =gBankAttacker\n\ + ldrb r1, [r0]\n\ + movs r0, 0x58\n\ + adds r4, r1, 0\n\ + muls r4, r0\n\ + adds r4, r2\n\ + ldrb r0, [r4, 0x14]\n\ + mov r10, r0\n\ + mov r7, r10\n\ + lsls r7, 27\n\ + adds r0, r7, 0\n\ + lsrs r0, 27\n\ + mov r10, r0\n\ + movs r1, 0x2\n\ + mov r2, r10\n\ + ands r2, r1\n\ + asrs r2, 1\n\ + ldrh r7, [r4, 0x14]\n\ + mov r9, r7\n\ + mov r0, r9\n\ + lsls r0, 22\n\ + mov r9, r0\n\ + lsrs r3, r0, 27\n\ + adds r0, r1, 0\n\ + ands r0, r3\n\ + orrs r2, r0\n\ + ldrb r7, [r4, 0x15]\n\ + mov r8, r7\n\ + mov r0, r8\n\ + lsls r0, 25\n\ + mov r8, r0\n\ + lsrs r3, r0, 27\n\ + adds r0, r1, 0\n\ + ands r0, r3\n\ + lsls r0, 1\n\ + orrs r2, r0\n\ + ldr r6, [r4, 0x14]\n\ + lsls r6, 12\n\ + lsrs r3, r6, 27\n\ + adds r0, r1, 0\n\ + ands r0, r3\n\ + lsls r0, 2\n\ + orrs r2, r0\n\ + ldrh r5, [r4, 0x16]\n\ + lsls r5, 23\n\ + lsrs r3, r5, 27\n\ + adds r0, r1, 0\n\ + ands r0, r3\n\ + lsls r0, 3\n\ + orrs r2, r0\n\ + ldrb r3, [r4, 0x17]\n\ + lsls r3, 26\n\ + lsrs r0, r3, 27\n\ + ands r1, r0\n\ + lsls r1, 4\n\ + orrs r2, r1\n\ + movs r1, 0x1\n\ + adds r4, r1, 0\n\ + mov r7, r10\n\ + ands r4, r7\n\ + mov r0, r9\n\ + lsrs r0, 27\n\ + mov r9, r0\n\ + adds r0, r1, 0\n\ + mov r7, r9\n\ + ands r0, r7\n\ + lsls r0, 1\n\ + orrs r4, r0\n\ + mov r0, r8\n\ + lsrs r0, 27\n\ + mov r8, r0\n\ + adds r0, r1, 0\n\ + mov r7, r8\n\ + ands r0, r7\n\ + lsls r0, 2\n\ + orrs r4, r0\n\ + lsrs r6, 27\n\ + adds r0, r1, 0\n\ + ands r0, r6\n\ + lsls r0, 3\n\ + orrs r4, r0\n\ + lsrs r5, 27\n\ + adds r0, r1, 0\n\ + ands r0, r5\n\ + lsls r0, 4\n\ + orrs r4, r0\n\ + lsrs r3, 27\n\ + ands r1, r3\n\ + lsls r1, 5\n\ + orrs r4, r1\n\ + ldr r5, =gDynamicBasePower\n\ + lsls r0, r2, 2\n\ + adds r0, r2\n\ + lsls r0, 3\n\ + movs r1, 0x3F\n\ + bl __divsi3\n\ + adds r0, 0x1E\n\ + strh r0, [r5]\n\ + ldr r6, =gBattleStruct\n\ + ldr r5, [r6]\n\ + lsls r0, r4, 4\n\ + subs r0, r4\n\ + movs r1, 0x3F\n\ + bl __divsi3\n\ + adds r0, 0x1\n\ + strb r0, [r5, 0x13]\n\ + ldr r1, [r6]\n\ + ldrb r0, [r1, 0x13]\n\ + cmp r0, 0x8\n\ + bls _080544F0\n\ + adds r0, 0x1\n\ + strb r0, [r1, 0x13]\n\ +_080544F0:\n\ + ldr r2, [r6]\n\ + ldrb r0, [r2, 0x13]\n\ + movs r1, 0xC0\n\ + orrs r0, r1\n\ + strb r0, [r2, 0x13]\n\ + ldr r1, =gBattlescriptCurrInstr\n\ + ldr r0, [r1]\n\ + adds r0, 0x1\n\ + str r0, [r1]\n\ + pop {r3-r5}\n\ + mov r8, r3\n\ + mov r9, r4\n\ + mov r10, r5\n\ + pop {r4-r7}\n\ + pop {r0}\n\ + bx r0\n\ + .pool\n\ + .syntax divided"); +} +#endif // NONMATCHING + +void atkC2_selectnexttarget(void) +{ + for (gBankTarget = 0; gBankTarget < gNoOfAllBanks; gBankTarget++) + { + if (gBankTarget == gBankAttacker) + continue; + if (!(gAbsentBankFlags & gBitTable[gBankTarget])) + break; + } + gBattlescriptCurrInstr++; +} + +void atkC3_setfutureattack(void) +{ + if (gWishFutureKnock.futureSightCounter[gBankTarget] != 0) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gSideAffecting[GET_BANK_SIDE(gBankTarget)] |= SIDE_STATUS_FUTUREATTACK; + gWishFutureKnock.futureSightMove[gBankTarget] = gCurrentMove; + gWishFutureKnock.futureSightAttacker[gBankTarget] = gBankAttacker; + gWishFutureKnock.futureSightCounter[gBankTarget] = 3; + gWishFutureKnock.futureSightDmg[gBankTarget] = CalculateBaseDamage(&gBattleMons[gBankAttacker], &gBattleMons[gBankTarget], gCurrentMove, + gSideAffecting[GET_BANK_SIDE(gBankTarget)], 0, + 0, gBankAttacker, gBankTarget); + + if (gProtectStructs[gBankAttacker].helpingHand) + gWishFutureKnock.futureSightDmg[gBankTarget] = gWishFutureKnock.futureSightDmg[gBankTarget] * 15 / 10; + + if (gCurrentMove == MOVE_DOOM_DESIRE) + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + + gBattlescriptCurrInstr += 5; + } +} + +void atkC4_beat_up(void) +{ + struct Pokemon* party; + + if (GetBankSide(gBankAttacker) == SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + if (gBattleMons[gBankTarget].hp == 0) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + u8 beforeLoop = gBattleCommunication[0]; + for (;gBattleCommunication[0] < 6; gBattleCommunication[0]++) + { + if (GetMonData(&party[gBattleCommunication[0]], MON_DATA_HP) + && GetMonData(&party[gBattleCommunication[0]], MON_DATA_SPECIES2) + && GetMonData(&party[gBattleCommunication[0]], MON_DATA_SPECIES2) != SPECIES_EGG + && !GetMonData(&party[gBattleCommunication[0]], MON_DATA_STATUS)) + break; + } + if (gBattleCommunication[0] < 6) + { + PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBankAttacker, gBattleCommunication[0]) + + gBattlescriptCurrInstr += 9; + + gBattleMoveDamage = gBaseStats[GetMonData(&party[gBattleCommunication[0]], MON_DATA_SPECIES)].baseAttack; + gBattleMoveDamage *= gBattleMoves[gCurrentMove].power; + gBattleMoveDamage *= (GetMonData(&party[gBattleCommunication[0]], MON_DATA_LEVEL) * 2 / 5 + 2); + gBattleMoveDamage /= gBaseStats[gBattleMons[gBankTarget].species].baseDefense; + gBattleMoveDamage = (gBattleMoveDamage / 50) + 2; + if (gProtectStructs[gBankAttacker].helpingHand) + gBattleMoveDamage = gBattleMoveDamage * 15 / 10; + + gBattleCommunication[0]++; + } + else if (beforeLoop != 0) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + else + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 5); + } +} + +void atkC5_setsemiinvulnerablebit(void) +{ + switch (gCurrentMove) + { + case MOVE_FLY: + case MOVE_BOUNCE: + gStatuses3[gBankAttacker] |= STATUS3_ON_AIR; + break; + case MOVE_DIG: + gStatuses3[gBankAttacker] |= STATUS3_UNDERGROUND; + break; + case MOVE_DIVE: + gStatuses3[gBankAttacker] |= STATUS3_UNDERWATER; + break; + } + + gBattlescriptCurrInstr++; +} + +void atkC6_clearsemiinvulnerablebit(void) +{ + switch (gCurrentMove) + { + case MOVE_FLY: + case MOVE_BOUNCE: + gStatuses3[gBankAttacker] &= ~STATUS3_ON_AIR; + break; + case MOVE_DIG: + gStatuses3[gBankAttacker] &= ~STATUS3_UNDERGROUND; + break; + case MOVE_DIVE: + gStatuses3[gBankAttacker] &= ~STATUS3_UNDERWATER; + break; + } + + gBattlescriptCurrInstr++; +} + +void atkC7_setminimize(void) +{ + if (gHitMarker & HITMARKER_OBEYS) + gStatuses3[gBankAttacker] |= STATUS3_MINIMIZED; + + gBattlescriptCurrInstr++; +} + +void atkC8_sethail(void) +{ + if (gBattleWeather & WEATHER_HAIL_ANY) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + } + else + { + gBattleWeather = WEATHER_HAIL; + gBattleCommunication[MULTISTRING_CHOOSER] = 5; + gWishFutureKnock.weatherDuration = 5; + } + + gBattlescriptCurrInstr++; +} + +void atkC9_jumpifattackandspecialattackcannotfall(void) // memento +{ + if (gBattleMons[gBankTarget].statStages[STAT_STAGE_ATK] == 0 + && gBattleMons[gBankTarget].statStages[STAT_STAGE_SPATK] == 0 + && gBattleCommunication[6] != 1) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gActiveBank = gBankAttacker; + gBattleMoveDamage = gBattleMons[gActiveBank].hp; + EmitHealthBarUpdate(0, 0x7FFF); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 5; + } +} + +void atkCA_setforcedtarget(void) // follow me +{ + gSideTimers[GetBankSide(gBankAttacker)].followmeTimer = 1; + gSideTimers[GetBankSide(gBankAttacker)].followmeTarget = gBankAttacker; + gBattlescriptCurrInstr++; +} + +void atkCB_setcharge(void) +{ + gStatuses3[gBankAttacker] |= STATUS3_CHARGED_UP; + gDisableStructs[gBankAttacker].chargeTimer1 = 2; + gDisableStructs[gBankAttacker].chargeTimer2 = 2; + gBattlescriptCurrInstr++; +} + +void atkCC_callterrainattack(void) // nature power +{ + gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); + gCurrentMove = sNaturePowerMoves[gBattleTerrain]; + gBankTarget = GetMoveTarget(gCurrentMove, 0); + BattleScriptPush(gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]); + gBattlescriptCurrInstr++; +} + +void atkCD_cureifburnedparalysedorpoisoned(void) // refresh +{ + if (gBattleMons[gBankAttacker].status1 & (STATUS_POISON | STATUS_BURN | STATUS_PARALYSIS | STATUS_TOXIC_POISON)) + { + gBattleMons[gBankAttacker].status1 = 0; + gBattlescriptCurrInstr += 5; + gActiveBank = gBankAttacker; + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); + MarkBufferBankForExecution(gActiveBank); + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +void atkCE_settorment(void) +{ + if (gBattleMons[gBankTarget].status2 & STATUS2_TORMENT) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gBattleMons[gBankTarget].status2 |= STATUS2_TORMENT; + gBattlescriptCurrInstr += 5; + } +} + +void atkCF_jumpifnodamage(void) +{ + if (gProtectStructs[gBankAttacker].physicalDmg || gProtectStructs[gBankAttacker].specialDmg) + gBattlescriptCurrInstr += 5; + else + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); +} + +void atkD0_settaunt(void) +{ + if (gDisableStructs[gBankTarget].tauntTimer1 == 0) + { + gDisableStructs[gBankTarget].tauntTimer1 = 2; + gDisableStructs[gBankTarget].tauntTimer2 = 2; + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +void atkD1_set_helpinghand(void) +{ + gBankTarget = GetBankByIdentity(GetBankIdentity(gBankAttacker) ^ BIT_MON); + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && !(gAbsentBankFlags & gBitTable[gBankTarget]) + && !gProtectStructs[gBankAttacker].helpingHand + && !gProtectStructs[gBankTarget].helpingHand) + { + gProtectStructs[gBankTarget].helpingHand = 1; + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +void atkD2_swap_items(void) // trick +{ + // opponent can't swap items with player in regular battles + if (gBattleTypeFlags & BATTLE_TYPE_x4000000 + || (GetBankSide(gBankAttacker) == SIDE_OPPONENT + && !(gBattleTypeFlags & (BATTLE_TYPE_LINK + | BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_FRONTIER + | BATTLE_TYPE_SECRET_BASE + | BATTLE_TYPE_x2000000)))) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + u8 sideAttacker = GetBankSide(gBankAttacker); + u8 sideTarget = GetBankSide(gBankTarget); + + // you can't swap items if they were knocked off in regular battles + if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK + | BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_FRONTIER + | BATTLE_TYPE_SECRET_BASE + | BATTLE_TYPE_x2000000)) + && (gWishFutureKnock.knockedOffPokes[sideAttacker] & gBitTable[gBattlePartyID[gBankAttacker]] + || gWishFutureKnock.knockedOffPokes[sideTarget] & gBitTable[gBattlePartyID[gBankTarget]])) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + // can't swap if two pokemon don't have an item + // or if either of them is an enigma berry or a mail + else if ((gBattleMons[gBankAttacker].item == 0 && gBattleMons[gBankTarget].item == 0) + || gBattleMons[gBankAttacker].item == ITEM_ENIGMA_BERRY + || gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY + || IS_ITEM_MAIL(gBattleMons[gBankAttacker].item) + || IS_ITEM_MAIL(gBattleMons[gBankTarget].item)) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + // check if ability prevents swapping + else if (gBattleMons[gBankTarget].ability == ABILITY_STICKY_HOLD) + { + gBattlescriptCurrInstr = BattleScript_StickyHoldActivates; + gLastUsedAbility = gBattleMons[gBankTarget].ability; + RecordAbilityBattle(gBankTarget, gLastUsedAbility); + } + // took a while, but all checks passed and items can be safely swapped + else + { + u16 oldItemAtk, *newItemAtk; + + newItemAtk = &gBattleStruct->changedItems[gBankAttacker]; + oldItemAtk = gBattleMons[gBankAttacker].item; + *newItemAtk = gBattleMons[gBankTarget].item; + + gBattleMons[gBankAttacker].item = 0; + gBattleMons[gBankTarget].item = oldItemAtk; + + gActiveBank = gBankAttacker; + EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, newItemAtk); + MarkBufferBankForExecution(gBankAttacker); + + gActiveBank = gBankTarget; + EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gBankTarget].item); + MarkBufferBankForExecution(gBankTarget); + + *(u8*)((u8*)(&gBattleStruct->choicedMove[gBankTarget]) + 0) = 0; + *(u8*)((u8*)(&gBattleStruct->choicedMove[gBankTarget]) + 1) = 0; + + *(u8*)((u8*)(&gBattleStruct->choicedMove[gBankAttacker]) + 0) = 0; + *(u8*)((u8*)(&gBattleStruct->choicedMove[gBankAttacker]) + 1) = 0; + + gBattlescriptCurrInstr += 5; + + PREPARE_ITEM_BUFFER(gBattleTextBuff1, *newItemAtk) + PREPARE_ITEM_BUFFER(gBattleTextBuff2, oldItemAtk) + + if (oldItemAtk != 0 && *newItemAtk != 0) + gBattleCommunication[MULTISTRING_CHOOSER] = 2; // attacker's item -> <- target's item + else if (oldItemAtk == 0 && *newItemAtk != 0) + gBattleCommunication[MULTISTRING_CHOOSER] = 0; // nothing -> <- target's item + else + gBattleCommunication[MULTISTRING_CHOOSER] = 1; // attacker's item -> <- nothing + } + } +} + +void atkD3_copy_ability(void) // role play +{ + if (gBattleMons[gBankTarget].ability != 0 + && gBattleMons[gBankTarget].ability != ABILITY_WONDER_GUARD) + { + gBattleMons[gBankAttacker].ability = gBattleMons[gBankTarget].ability; + gLastUsedAbility = gBattleMons[gBankTarget].ability; + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +void atkD4_wish_effect(void) +{ + switch (BSScriptRead8(gBattlescriptCurrInstr + 1)) + { + case 0: // use wish + if (gWishFutureKnock.wishCounter[gBankAttacker] == 0) + { + gWishFutureKnock.wishCounter[gBankAttacker] = 2; + gWishFutureKnock.wishUserID[gBankAttacker] = gBattlePartyID[gBankAttacker]; + gBattlescriptCurrInstr += 6; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + } + break; + case 1: // heal effect + PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBankTarget, gWishFutureKnock.wishUserID[gBankTarget]) + + gBattleMoveDamage = gBattleMons[gBankTarget].maxHP / 2; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + gBattleMoveDamage *= -1; + + if (gBattleMons[gBankTarget].hp == gBattleMons[gBankTarget].maxHP) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + else + gBattlescriptCurrInstr += 6; + + break; + } +} + +void atkD5_setroots(void) // ingrain +{ + if (gStatuses3[gBankAttacker] & STATUS3_ROOTED) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gStatuses3[gBankAttacker] |= STATUS3_ROOTED; + gBattlescriptCurrInstr += 5; + } +} + +void atkD6_doubledamagedealtifdamaged(void) +{ + if ((gProtectStructs[gBankAttacker].physicalDmg + && gProtectStructs[gBankAttacker].physicalBank == gBankTarget) + || (gProtectStructs[gBankAttacker].specialDmg + && gProtectStructs[gBankAttacker].specialBank == gBankTarget)) + { + gBattleScripting.dmgMultiplier = 2; + } + + gBattlescriptCurrInstr++; +} + +void atkD7_setyawn(void) +{ + if (gStatuses3[gBankTarget] & STATUS3_YAWN + || gBattleMons[gBankTarget].status1 & STATUS_ANY) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gStatuses3[gBankTarget] |= 0x1000; + gBattlescriptCurrInstr += 5; + } +} + +void atkD8_setdamagetohealthdifference(void) +{ + if (gBattleMons[gBankTarget].hp <= gBattleMons[gBankAttacker].hp) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gBattleMoveDamage = gBattleMons[gBankTarget].hp - gBattleMons[gBankAttacker].hp; + gBattlescriptCurrInstr += 5; + } +} + +void atkD9_scaledamagebyhealthratio(void) +{ + if (gDynamicBasePower == 0) + { + u8 power = gBattleMoves[gCurrentMove].power; + gDynamicBasePower = gBattleMons[gBankAttacker].hp * power / gBattleMons[gBankAttacker].maxHP; + if (gDynamicBasePower == 0) + gDynamicBasePower = 1; + } + gBattlescriptCurrInstr++; +} + +void atkDA_abilityswap(void) // skill swap +{ + if ((gBattleMons[gBankAttacker].ability == 0 + && gBattleMons[gBankTarget].ability == 0) + || gBattleMons[gBankAttacker].ability == ABILITY_WONDER_GUARD + || gBattleMons[gBankTarget].ability == ABILITY_WONDER_GUARD + || gBattleMoveFlags & MOVESTATUS_NOEFFECT) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + u8 abilityAtk = gBattleMons[gBankAttacker].ability; + gBattleMons[gBankAttacker].ability = gBattleMons[gBankTarget].ability; + gBattleMons[gBankTarget].ability = abilityAtk; + + gBattlescriptCurrInstr += 5; + } +} + +void atkDB_imprisoneffect(void) +{ + if ((gStatuses3[gBankAttacker] & STATUS3_IMPRISONED_OTHERS)) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + u8 bank, sideAttacker; + + sideAttacker = GetBankSide(gBankAttacker); + PressurePPLoseOnUsingImprision(gBankAttacker); + for (bank = 0; bank < gNoOfAllBanks; bank++) + { + if (sideAttacker != GetBankSide(bank)) + { + s32 attackerMoveId; + for (attackerMoveId = 0; attackerMoveId < 4; attackerMoveId++) + { + s32 i; + for (i = 0; i < 4; i++) + { + if (gBattleMons[gBankAttacker].moves[attackerMoveId] == gBattleMons[bank].moves[i] + && gBattleMons[gBankAttacker].moves[attackerMoveId] != MOVE_NONE) + break; + } + if (i != 4) + break; + } + if (attackerMoveId != 4) + { + gStatuses3[gBankAttacker] |= STATUS3_IMPRISONED_OTHERS; + gBattlescriptCurrInstr += 5; + break; + } + } + } + if (bank == gNoOfAllBanks) // In Generation 3 games, Imprison fails if the user doesn't share any moves with any of the foes + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +void atkDC_setgrudge(void) +{ + if (gStatuses3[gBankAttacker] & STATUS3_GRUDGE) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gStatuses3[gBankAttacker] |= STATUS3_GRUDGE; + gBattlescriptCurrInstr += 5; + } +} + +void atkDD_weightdamagecalculation(void) +{ + s32 i; + for (i = 0; sWeightToDamageTable[i] != 0xFFFF; i += 2) + { + if (sWeightToDamageTable[i] > GetPokedexHeightWeight(SpeciesToNationalPokedexNum(gBattleMons[gBankTarget].species), 1)) + break; + } + + if (sWeightToDamageTable[i] != 0xFFFF) + gDynamicBasePower = sWeightToDamageTable[i + 1]; + else + gDynamicBasePower = 120; + + gBattlescriptCurrInstr++; +} + +void atkDE_asistattackselect(void) +{ + s32 chooseableMovesNo = 0; + struct Pokemon* party; + s32 monId, moveId; + u16* movesArray = gBattleStruct->assistPossibleMoves; + + if (GET_BANK_SIDE(gBankAttacker) != SIDE_PLAYER) + party = gEnemyParty; + else + party = gPlayerParty; + + for (monId = 0; monId < 6; monId++) + { + if (monId == gBattlePartyID[gBankAttacker]) + continue; + if (GetMonData(&party[monId], MON_DATA_SPECIES2) == SPECIES_NONE) + continue; + if (GetMonData(&party[monId], MON_DATA_SPECIES2) == SPECIES_EGG) + continue; + + for (moveId = 0; moveId < 4; moveId++) + { + s32 i = 0; + u16 move = GetMonData(&party[monId], MON_DATA_MOVE1 + moveId); + + if (IsInvalidForSleepTalkOrAssist(move)) + continue; + + for (; gMovesForbiddenToCopy[i] != ASSIST_FORBIDDEN_END && move != gMovesForbiddenToCopy[i]; i++); + + if (gMovesForbiddenToCopy[i] != ASSIST_FORBIDDEN_END) + continue; + if (move == MOVE_NONE) + continue; + + movesArray[chooseableMovesNo] = move; + chooseableMovesNo++; + } + } + if (chooseableMovesNo) + { + gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); + gRandomMove = movesArray[((Random() & 0xFF) * chooseableMovesNo) >> 8]; + gBankTarget = GetMoveTarget(gRandomMove, 0); + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +void atkDF_setmagiccoat(void) +{ + gBankTarget = gBankAttacker; + gSpecialStatuses[gBankAttacker].flag20 = 1; + if (gCurrentMoveTurn == gNoOfAllBanks - 1) // moves last turn + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gProtectStructs[gBankAttacker].bounceMove = 1; + gBattlescriptCurrInstr += 5; + } +} + +void atkE0_setstealstatchange(void) // snatch +{ + gSpecialStatuses[gBankAttacker].flag20 = 1; + if (gCurrentMoveTurn == gNoOfAllBanks - 1) // moves last turn + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gProtectStructs[gBankAttacker].stealMove = 1; + gBattlescriptCurrInstr += 5; + } +} + +void atkE1_intimidate_string_loader(void) +{ + u8 side; + + gBattleScripting.bank = gBattleStruct->intimidateBank; + side = GetBankSide(gBattleScripting.bank); + + PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gBattleMons[gBattleScripting.bank].ability) + + for (;gBankTarget < gNoOfAllBanks; gBankTarget++) + { + if (GetBankSide(gBankTarget) == side) + continue; + if (!(gAbsentBankFlags & gBitTable[gBankTarget])) + break; + } + + if (gBankTarget >= gNoOfAllBanks) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + else + gBattlescriptCurrInstr += 5; +} + +void atkE2_switchout_abilities(void) +{ + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + + switch (gBattleMons[gActiveBank].ability) + { + case ABILITY_NATURAL_CURE: + gBattleMons[gActiveBank].status1 = 0; + EmitSetMonData(0, REQUEST_STATUS_BATTLE, gBitTable[*(gBattleStruct->field_58 + gActiveBank)], 4, &gBattleMons[gActiveBank].status1); + MarkBufferBankForExecution(gActiveBank); + break; + } + + gBattlescriptCurrInstr += 2; +} + +void atkE3_jumpifhasnohp(void) +{ + gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + + if (gBattleMons[gActiveBank].hp == 0) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + else + gBattlescriptCurrInstr += 6; +} + +void atkE4_getsecretpowereffect(void) +{ + switch (gBattleTerrain) + { + case BATTLE_TERRAIN_GRASS: + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_POISON; + break; + case BATTLE_TERRAIN_LONG_GRASS: + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_SLEEP; + break; + case BATTLE_TERRAIN_SAND: + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_ACC_MINUS_1; + break; + case BATTLE_TERRAIN_UNDERWATER: + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_DEF_MINUS_1; + break; + case BATTLE_TERRAIN_WATER: + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_ATK_MINUS_1; + break; + case BATTLE_TERRAIN_POND: + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_SPD_MINUS_1; + break; + case BATTLE_TERRAIN_ROCK: + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_CONFUSION; + break; + case BATTLE_TERRAIN_CAVE: + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_FLINCH; + break; + default: + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_PARALYSIS; + break; + } + gBattlescriptCurrInstr++; +} + +extern bool8 InBattlePike(void); +extern bool8 InBattlePyramid(void); +extern u16 GetBattlePyramidPickupItemId(void); + +extern const u16 gRarePickupItems[]; +extern const u16 gPickupItems[]; +extern const u8 gPickupProbabilities[]; + +void atkE5_pickup(void) +{ + if (!InBattlePike()) + { + s32 i; + u16 species, heldItem; + u8 ability; + + if (InBattlePyramid()) + { + for (i = 0; i < 6; i++) + { + species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2); + heldItem = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM); + + if (GetMonData(&gPlayerParty[i], MON_DATA_ALT_ABILITY)) + ability = gBaseStats[species].ability2; + else + ability = gBaseStats[species].ability1; + + if (ability == ABILITY_PICKUP + && species != 0 + && species != SPECIES_EGG + && heldItem == ITEM_NONE + && (Random() % 10) == 0) + { + heldItem = GetBattlePyramidPickupItemId(); + SetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM, &heldItem); + } + } + } + else + { + for (i = 0; i < 6; i++) + { + species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2); + heldItem = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM); + + if (GetMonData(&gPlayerParty[i], MON_DATA_ALT_ABILITY)) + ability = gBaseStats[species].ability2; + else + ability = gBaseStats[species].ability1; + + if (ability == ABILITY_PICKUP + && species != 0 + && species != SPECIES_EGG + && heldItem == ITEM_NONE + && (Random() % 10) == 0) + { + s32 j; + s32 rand = Random() % 100; + u8 lvlDivBy10 = (GetMonData(&gPlayerParty[i], MON_DATA_LEVEL) - 1) / 10; + if (lvlDivBy10 > 9) + lvlDivBy10 = 9; + + for (j = 0; j < 9; j++) + { + if (gPickupProbabilities[j] > rand) + { + SetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM, &gPickupItems[lvlDivBy10 + j]); + break; + } + else if (rand == 99 || rand == 98) + { + SetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM, &gRarePickupItems[lvlDivBy10 + (99 - rand)]); + break; + } + } + } + } + } + } + + gBattlescriptCurrInstr++; +} diff --git a/src/pokemon_3.c b/src/pokemon_3.c index d381c7544..d44c0cb2f 100644 --- a/src/pokemon_3.c +++ b/src/pokemon_3.c @@ -1361,20 +1361,20 @@ void BoxMonRestorePP(struct BoxPokemon *boxMon) void sub_806E994(void) { gLastUsedAbility = gBattleStruct->field_B0; - gBattleTextBuff1[0] = 0xFD; - gBattleTextBuff1[1] = 4; + + gBattleTextBuff1[0] = B_BUFF_PLACEHOLDER_BEGIN; + gBattleTextBuff1[1] = B_BUFF_MON_NICK_WITH_PREFIX; gBattleTextBuff1[2] = gBattleStruct->field_49; - gBattleTextBuff1[4] = EOS; + gBattleTextBuff1[4] = B_BUFF_EOS; + if (!GetBankSide(gBattleStruct->field_49)) gBattleTextBuff1[3] = pokemon_order_func(gBattlePartyID[gBattleStruct->field_49]); else gBattleTextBuff1[3] = gBattlePartyID[gBattleStruct->field_49]; - gBattleTextBuff2[0] = 0xFD; - gBattleTextBuff2[1] = 4; - gBattleTextBuff2[2] = gBankInMenu; - gBattleTextBuff2[3] = pokemon_order_func(gBattlePartyID[gBankInMenu]); - gBattleTextBuff2[4] = EOS; - BattleStringExpandPlaceholders(gText_PkmnsXPreventsSwitching, gStringVar4); + + PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff2, gBankInMenu, pokemon_order_func(gBattlePartyID[gBankInMenu])) + + BattleStringExpandPlaceholders(gText_PkmnsXPreventsSwitching, gStringVar4); } struct PokeItem @@ -1388,7 +1388,7 @@ extern const struct PokeItem gAlteringCaveWildMonHeldItems[9]; static s32 GetWildMonTableIdInAlteringCave(u16 species) { s32 i; - for (i = 0; i < 9; i++) + for (i = 0; i < (s32) ARRAY_COUNT(gAlteringCaveWildMonHeldItems); i++) if (gAlteringCaveWildMonHeldItems[i].species == species) return i; return 0; -- cgit v1.2.3 From bc3b4b4d9ae6ab59c9ce3892b7d287ebd0ee13fa Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Thu, 28 Sep 2017 15:34:21 +0200 Subject: battle 4 commands are decompiled --- src/battle_3.c | 172 +++--- src/battle_4.c | 1890 +++++++++++++++++++++++++++++++++++++------------------- 2 files changed, 1331 insertions(+), 731 deletions(-) (limited to 'src') diff --git a/src/battle_3.c b/src/battle_3.c index 9ac439390..e81d527d0 100644 --- a/src/battle_3.c +++ b/src/battle_3.c @@ -179,13 +179,9 @@ extern const u8 gStatusConditionString_ConfusionJpn[]; extern const u8 gStatusConditionString_LoveJpn[]; extern const u16 gSoundMovesTable[]; -extern void CancelMultiTurnMoves(u8 bank); extern u8 b_first_side(u8, u8, u8); extern void sub_803CEDC(u8, u8); -extern void b_call_bc_move_exec(const u8 *); extern void BattleTurnPassed(void); -extern void SetMoveEffect(bool8 primary, u8 certainArg); -extern bool8 UproarWakeUpCheck(u8 bank); extern void sub_803F9EC(); extern bool8 sub_80423F4(u8 bank, u8, u8); extern u8 weather_get_current(void); @@ -441,7 +437,7 @@ u8 UpdateTurnCounters(void) if (--gSideTimers[sideBank].reflectTimer == 0) { gSideAffecting[sideBank] &= ~SIDE_STATUS_REFLECT; - b_call_bc_move_exec(gUnknown_082DACFA); + BattleScriptExecute(gUnknown_082DACFA); gBattleTextBuff1[0] = 0xFD; gBattleTextBuff1[1] = 2; gBattleTextBuff1[2] = MOVE_REFLECT; @@ -470,7 +466,7 @@ u8 UpdateTurnCounters(void) if (--gSideTimers[sideBank].lightscreenTimer == 0) { gSideAffecting[sideBank] &= ~SIDE_STATUS_LIGHTSCREEN; - b_call_bc_move_exec(gUnknown_082DACFA); + BattleScriptExecute(gUnknown_082DACFA); gBattleCommunication[MULTISTRING_CHOOSER] = sideBank; gBattleTextBuff1[0] = 0xFD; gBattleTextBuff1[1] = 2; @@ -499,7 +495,7 @@ u8 UpdateTurnCounters(void) && --gSideTimers[sideBank].mistTimer == 0) { gSideAffecting[sideBank] &= ~SIDE_STATUS_MIST; - b_call_bc_move_exec(gUnknown_082DACFA); + BattleScriptExecute(gUnknown_082DACFA); gBattleCommunication[MULTISTRING_CHOOSER] = sideBank; gBattleTextBuff1[0] = 0xFD; gBattleTextBuff1[1] = 2; @@ -528,7 +524,7 @@ u8 UpdateTurnCounters(void) if (--gSideTimers[sideBank].safeguardTimer == 0) { gSideAffecting[sideBank] &= ~SIDE_STATUS_SAFEGUARD; - b_call_bc_move_exec(gUnknown_082DAD0B); + BattleScriptExecute(gUnknown_082DAD0B); effect++; } } @@ -551,7 +547,7 @@ u8 UpdateTurnCounters(void) && gBattleMons[gActiveBank].hp != 0) { gBankTarget = gActiveBank; - b_call_bc_move_exec(BattleScript_WishComesTrue); + BattleScriptExecute(BattleScript_WishComesTrue); effect++; } gBattleStruct->turnSideTracker++; @@ -583,7 +579,7 @@ u8 UpdateTurnCounters(void) gBattleCommunication[MULTISTRING_CHOOSER] = 1; else gBattleCommunication[MULTISTRING_CHOOSER] = 0; - b_call_bc_move_exec(gUnknown_082DAC2C); + BattleScriptExecute(gUnknown_082DAC2C); effect++; } gBattleStruct->turncountersTracker++; @@ -601,7 +597,7 @@ u8 UpdateTurnCounters(void) gBattleScripting.animArg1 = 0xC; gBattleCommunication[MULTISTRING_CHOOSER] = 0; - b_call_bc_move_exec(gBattlescriptCurrInstr); + BattleScriptExecute(gBattlescriptCurrInstr); effect++; } gBattleStruct->turncountersTracker++; @@ -617,7 +613,7 @@ u8 UpdateTurnCounters(void) else gBattlescriptCurrInstr = gUnknown_082DACD2; - b_call_bc_move_exec(gBattlescriptCurrInstr); + BattleScriptExecute(gBattlescriptCurrInstr); effect++; } gBattleStruct->turncountersTracker++; @@ -635,7 +631,7 @@ u8 UpdateTurnCounters(void) gBattleScripting.animArg1 = 0xD; gBattleCommunication[MULTISTRING_CHOOSER] = 1; - b_call_bc_move_exec(gBattlescriptCurrInstr); + BattleScriptExecute(gBattlescriptCurrInstr); effect++; } gBattleStruct->turncountersTracker++; @@ -675,7 +671,7 @@ u8 TurnBasedEffects(void) if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; gBattleMoveDamage *= -1; - b_call_bc_move_exec(BattleScript_IngrainTurnHeal); + BattleScriptExecute(BattleScript_IngrainTurnHeal); effect++; } gBattleStruct->turnEffectsTracker++; @@ -706,7 +702,7 @@ u8 TurnBasedEffects(void) gBattleMoveDamage = 1; gBattleScripting.animArg1 = gBankTarget; gBattleScripting.animArg2 = gBankAttacker; - b_call_bc_move_exec(BattleScript_LeechSeedTurnDrain); + BattleScriptExecute(BattleScript_LeechSeedTurnDrain); effect++; } gBattleStruct->turnEffectsTracker++; @@ -717,7 +713,7 @@ u8 TurnBasedEffects(void) gBattleMoveDamage = gBattleMons[gActiveBank].maxHP / 8; if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; - b_call_bc_move_exec(BattleScript_PoisonTurnDmg); + BattleScriptExecute(BattleScript_PoisonTurnDmg); effect++; } gBattleStruct->turnEffectsTracker++; @@ -731,7 +727,7 @@ u8 TurnBasedEffects(void) if ((gBattleMons[gActiveBank].status1 & 0xF00) != 0xF00) //not 16 turns gBattleMons[gActiveBank].status1 += 0x100; gBattleMoveDamage *= (gBattleMons[gActiveBank].status1 & 0xF00) >> 8; - b_call_bc_move_exec(BattleScript_PoisonTurnDmg); + BattleScriptExecute(BattleScript_PoisonTurnDmg); effect++; } gBattleStruct->turnEffectsTracker++; @@ -742,7 +738,7 @@ u8 TurnBasedEffects(void) gBattleMoveDamage = gBattleMons[gActiveBank].maxHP / 8; if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; - b_call_bc_move_exec(BattleScript_BurnTurnDmg); + BattleScriptExecute(BattleScript_BurnTurnDmg); effect++; } gBattleStruct->turnEffectsTracker++; @@ -757,7 +753,7 @@ u8 TurnBasedEffects(void) gBattleMoveDamage = gBattleMons[gActiveBank].maxHP / 4; if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; - b_call_bc_move_exec(BattleScript_NightmareTurnDmg); + BattleScriptExecute(BattleScript_NightmareTurnDmg); effect++; } else @@ -773,7 +769,7 @@ u8 TurnBasedEffects(void) gBattleMoveDamage = gBattleMons[gActiveBank].maxHP / 4; if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; - b_call_bc_move_exec(BattleScript_CurseTurnDmg); + BattleScriptExecute(BattleScript_CurseTurnDmg); effect++; } gBattleStruct->turnEffectsTracker++; @@ -806,7 +802,7 @@ u8 TurnBasedEffects(void) gBattleTextBuff1[4] = EOS; gBattlescriptCurrInstr = BattleScript_WrapEnds; } - b_call_bc_move_exec(gBattlescriptCurrInstr); + BattleScriptExecute(gBattlescriptCurrInstr); effect++; } gBattleStruct->turnEffectsTracker++; @@ -822,7 +818,7 @@ u8 TurnBasedEffects(void) gBattleMons[gBankAttacker].status1 &= ~(STATUS_SLEEP); gBattleMons[gBankAttacker].status2 &= ~(STATUS2_NIGHTMARE); gBattleCommunication[MULTISTRING_CHOOSER] = 1; - b_call_bc_move_exec(gUnknown_082DB234); + BattleScriptExecute(gUnknown_082DB234); gActiveBank = gBankAttacker; EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); MarkBufferBankForExecution(gActiveBank); @@ -853,7 +849,7 @@ u8 TurnBasedEffects(void) gBattleCommunication[MULTISTRING_CHOOSER] = 1; CancelMultiTurnMoves(gActiveBank); } - b_call_bc_move_exec(gUnknown_082DB2A6); + BattleScriptExecute(gUnknown_082DB2A6); effect = 1; } } @@ -875,7 +871,7 @@ u8 TurnBasedEffects(void) gBattleCommunication[MOVE_EFFECT_BYTE] = 0x47; SetMoveEffect(1, 0); if (gBattleMons[gActiveBank].status2 & STATUS2_CONFUSION) - b_call_bc_move_exec(BattleScript_ThrashConfuses); + BattleScriptExecute(BattleScript_ThrashConfuses); effect++; } } @@ -899,7 +895,7 @@ u8 TurnBasedEffects(void) else if (--gDisableStructs[gActiveBank].disableTimer1 == 0) // disable ends { gDisableStructs[gActiveBank].disabledMove = 0; - b_call_bc_move_exec(BattleScript_DisabledNoMore); + BattleScriptExecute(BattleScript_DisabledNoMore); effect++; } } @@ -918,7 +914,7 @@ u8 TurnBasedEffects(void) { gDisableStructs[gActiveBank].encoredMove = 0; gDisableStructs[gActiveBank].encoreTimer1 = 0; - b_call_bc_move_exec(BattleScript_EncoredNoMore); + BattleScriptExecute(BattleScript_EncoredNoMore); effect++; } } @@ -952,7 +948,7 @@ u8 TurnBasedEffects(void) EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); MarkBufferBankForExecution(gActiveBank); gEffectBank = gActiveBank; - b_call_bc_move_exec(BattleScript_YawnMakesAsleep); + BattleScriptExecute(BattleScript_YawnMakesAsleep); effect++; } } @@ -1006,7 +1002,7 @@ bool8 sub_8041364(void) gBankAttacker = gWishFutureKnock.futureSightAttacker[gActiveBank]; gBattleMoveDamage = gWishFutureKnock.futureSightDmg[gActiveBank]; gSpecialStatuses[gBankTarget].moveturnLostHP = 0xFFFF; - b_call_bc_move_exec(gUnknown_082DAFE4); + BattleScriptExecute(gUnknown_082DAFE4); if (gWishFutureKnock.futureSightCounter[gActiveBank] == 0 && gWishFutureKnock.futureSightCounter[gActiveBank ^ 2] == 0) @@ -1052,7 +1048,7 @@ bool8 sub_8041364(void) gDisableStructs[gActiveBank].perishSong1--; gBattlescriptCurrInstr = gUnknown_082DAF20; } - b_call_bc_move_exec(gBattlescriptCurrInstr); + BattleScriptExecute(gBattlescriptCurrInstr); return 1; } } @@ -1074,7 +1070,7 @@ bool8 sub_8041364(void) CancelMultiTurnMoves(i); gBattlescriptCurrInstr = gUnknown_082DB8F3; - b_call_bc_move_exec(gUnknown_082DB8F3); + BattleScriptExecute(gUnknown_082DB8F3); gBattleStruct->field_1A0++; return 1; } @@ -1114,7 +1110,7 @@ bool8 sub_8041728(void) && !(gBattleStruct->field_DF & gBitTable[gBattlePartyID[gBattleStruct->field_4E]]) && !(gAbsentBankFlags & gBitTable[gBattleStruct->field_4E])) { - b_call_bc_move_exec(gUnknown_082DA7C4); + BattleScriptExecute(gUnknown_082DA7C4); gBattleStruct->field_4D = 2; return TRUE; } @@ -1139,7 +1135,7 @@ bool8 sub_8041728(void) if (gBattleMons[gBattleStruct->field_4E].hp == 0 && !(gAbsentBankFlags & gBitTable[gBattleStruct->field_4E])) { - b_call_bc_move_exec(gUnknown_082DA7CD); + BattleScriptExecute(gUnknown_082DA7CD); gBattleStruct->field_4D = 5; return TRUE; } @@ -1709,7 +1705,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) if (effect) { gBattleCommunication[MULTISTRING_CHOOSER] = weather_get_current(); - b_push_move_exec(gUnknown_082DACE7); + BattleScriptPushCursorAndCallback(gUnknown_082DACE7); } break; case ABILITY_DRIZZLE: @@ -1717,7 +1713,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) if (!(gBattleWeather & WEATHER_RAIN_PERMANENT)) { gBattleWeather = (WEATHER_RAIN_PERMANENT | WEATHER_RAIN_TEMPORARY); - b_push_move_exec(BattleScript_DrizzleActivates); + BattleScriptPushCursorAndCallback(BattleScript_DrizzleActivates); gBattleScripting.bank = bank; effect++; } @@ -1727,7 +1723,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) if (!(gBattleWeather & WEATHER_SANDSTORM_PERMANENT)) { gBattleWeather = (WEATHER_SANDSTORM_PERMANENT | WEATHER_SANDSTORM_TEMPORARY); - b_push_move_exec(BattleScript_SandstreamActivates); + BattleScriptPushCursorAndCallback(BattleScript_SandstreamActivates); gBattleScripting.bank = bank; effect++; } @@ -1737,7 +1733,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) if (!(gBattleWeather & WEATHER_SUN_PERMANENT)) { gBattleWeather = (WEATHER_SUN_PERMANENT | WEATHER_SUN_TEMPORARY); - b_push_move_exec(BattleScript_DroughtActivates); + BattleScriptPushCursorAndCallback(BattleScript_DroughtActivates); gBattleScripting.bank = bank; effect++; } @@ -1755,7 +1751,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) effect = CastformDataTypeChange(bank); if (effect != 0) { - b_push_move_exec(BattleScript_CastformChange); + BattleScriptPushCursorAndCallback(BattleScript_CastformChange); gBattleScripting.bank = bank; gBattleStruct->formToChangeInto = effect - 1; } @@ -1779,7 +1775,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) effect = CastformDataTypeChange(i); if (effect != 0) { - b_push_move_exec(BattleScript_CastformChange); + BattleScriptPushCursorAndCallback(BattleScript_CastformChange); gBattleScripting.bank = i; gBattleStruct->formToChangeInto = effect - 1; break; @@ -1802,7 +1798,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) && gBattleMons[bank].maxHP > gBattleMons[bank].hp) { gLastUsedAbility = ABILITY_RAIN_DISH; //why - b_push_move_exec(BattleScript_RainDishActivates); + BattleScriptPushCursorAndCallback(BattleScript_RainDishActivates); gBattleMoveDamage = gBattleMons[bank].maxHP / 16; if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; @@ -1827,7 +1823,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) gBattleMons[bank].status1 = 0; gBattleMons[bank].status2 &= ~(STATUS2_NIGHTMARE); // fix nighmare glitch gBattleScripting.bank = gActiveBank = bank; - b_push_move_exec(BattleScript_ShedSkinActivates); + BattleScriptPushCursorAndCallback(BattleScript_ShedSkinActivates); EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[bank].status1); MarkBufferBankForExecution(gActiveBank); effect++; @@ -1840,7 +1836,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) gBattleMons[bank].statStages[STAT_STAGE_SPEED]++; gBattleScripting.animArg1 = 0x11; gBattleScripting.animArg2 = 0; - b_push_move_exec(BattleScript_SpeedBoostActivates); + BattleScriptPushCursorAndCallback(BattleScript_SpeedBoostActivates); gBattleScripting.bank = bank; effect++; } @@ -2167,7 +2163,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) effect = CastformDataTypeChange(i); if (effect) { - b_push_move_exec(BattleScript_CastformChange); + BattleScriptPushCursorAndCallback(BattleScript_CastformChange); gBattleScripting.bank = i; gBattleStruct->formToChangeInto = effect - 1; return effect; @@ -2215,7 +2211,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) { gLastUsedAbility = ABILITY_INTIMIDATE; gStatuses3[i] &= ~(STATUS3_INTIMIDATE_POKES); - b_push_move_exec(gUnknown_082DB4B8); + BattleScriptPushCursorAndCallback(gUnknown_082DB4B8); gBattleStruct->intimidateBank = i; effect++; break; @@ -2267,7 +2263,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 bank, u8 ability, u8 special, u16 moveArg) } if (effect) { - b_push_move_exec(BattleScript_TraceActivates); + BattleScriptPushCursorAndCallback(BattleScript_TraceActivates); gStatuses3[i] &= ~(STATUS3_TRACE); gBattleScripting.bank = i; @@ -2774,7 +2770,7 @@ _08042B56:\n\ ldr r1, =gBattleCommunication\n\ strb r0, [r1, 0x5]\n\ ldr r0, =gUnknown_082DACE7\n\ - bl b_push_move_exec\n\ + bl BattleScriptPushCursorAndCallback\n\ bl _0804441E\n\ .pool\n\ _08042B78:\n\ @@ -2789,7 +2785,7 @@ _08042B88:\n\ movs r0, 0x5\n\ strh r0, [r2]\n\ ldr r0, =BattleScript_DrizzleActivates\n\ - bl b_push_move_exec\n\ + bl BattleScriptPushCursorAndCallback\n\ ldr r0, =gBattleScripting\n\ mov r1, r10\n\ strb r1, [r0, 0x17]\n\ @@ -2807,7 +2803,7 @@ _08042BB8:\n\ movs r0, 0x18\n\ strh r0, [r2]\n\ ldr r0, =BattleScript_SandstreamActivates\n\ - bl b_push_move_exec\n\ + bl BattleScriptPushCursorAndCallback\n\ ldr r0, =gBattleScripting\n\ mov r2, r10\n\ strb r2, [r0, 0x17]\n\ @@ -2825,7 +2821,7 @@ _08042BE8:\n\ movs r0, 0x60\n\ strh r0, [r2]\n\ ldr r0, =BattleScript_DroughtActivates\n\ - bl b_push_move_exec\n\ + bl BattleScriptPushCursorAndCallback\n\ ldr r0, =gBattleScripting\n\ mov r3, r10\n\ strb r3, [r0, 0x17]\n\ @@ -2866,7 +2862,7 @@ _08042C3C:\n\ bl _0804443A\n\ _08042C50:\n\ ldr r0, =BattleScript_CastformChange\n\ - bl b_push_move_exec\n\ + bl BattleScriptPushCursorAndCallback\n\ ldr r0, =gBattleScripting\n\ mov r1, r10\n\ strb r1, [r0, 0x17]\n\ @@ -2999,7 +2995,7 @@ _08042D66:\n\ _08042D72:\n\ strb r5, [r7]\n\ ldr r0, =BattleScript_RainDishActivates\n\ - bl b_push_move_exec\n\ + bl BattleScriptPushCursorAndCallback\n\ ldr r1, =gBattleMoveDamage\n\ ldrh r0, [r4, 0x2C]\n\ lsrs r0, 4\n\ @@ -3093,7 +3089,7 @@ _08042E24:\n\ strb r3, [r4]\n\ strb r3, [r0, 0x17]\n\ ldr r0, =BattleScript_ShedSkinActivates\n\ - bl b_push_move_exec\n\ + bl BattleScriptPushCursorAndCallback\n\ str r5, [sp]\n\ movs r0, 0\n\ movs r1, 0x28\n\ @@ -3131,7 +3127,7 @@ _08042EA8:\n\ strb r0, [r4, 0x10]\n\ strb r1, [r4, 0x11]\n\ ldr r0, =BattleScript_SpeedBoostActivates\n\ - bl b_push_move_exec\n\ + bl BattleScriptPushCursorAndCallback\n\ strb r5, [r4, 0x17]\n\ bl _080443D0\n\ .pool\n\ @@ -5288,7 +5284,7 @@ _080442C0:\n\ .pool\n\ _080442D8:\n\ ldr r0, =BattleScript_CastformChange\n\ - bl b_push_move_exec\n\ + bl BattleScriptPushCursorAndCallback\n\ ldr r0, =gBattleScripting\n\ strb r6, [r0, 0x17]\n\ _080442E2:\n\ @@ -5302,7 +5298,7 @@ _080442E2:\n\ .pool\n\ _080442FC:\n\ ldr r0, =BattleScript_CastformChange\n\ - bl b_push_move_exec\n\ + bl BattleScriptPushCursorAndCallback\n\ ldr r0, =gBattleScripting\n\ mov r5, r10\n\ strb r5, [r0, 0x17]\n\ @@ -5321,12 +5317,12 @@ _08044324:\n\ ands r0, r1\n\ str r0, [r2]\n\ ldr r0, =gUnknown_082DB4B8\n\ - bl b_push_move_exec\n\ + bl BattleScriptPushCursorAndCallback\n\ b _080443C8\n\ .pool\n\ _08044340:\n\ ldr r0, =BattleScript_TraceActivates\n\ - bl b_push_move_exec\n\ + bl BattleScriptPushCursorAndCallback\n\ ldr r1, =gStatuses3\n\ ldr r0, [sp, 0x18]\n\ adds r1, r0, r1\n\ @@ -5445,7 +5441,7 @@ _0804443A:\n\ } #endif // NONMATCHING -void b_call_bc_move_exec(const u8* BS_ptr) +void BattleScriptExecute(const u8* BS_ptr) { gBattlescriptCurrInstr = BS_ptr; BATTLE_CALLBACKS_STACK->function[BATTLE_CALLBACKS_STACK->size++] = gBattleMainFunc; @@ -5453,7 +5449,7 @@ void b_call_bc_move_exec(const u8* BS_ptr) gFightStateTracker = 0; } -void b_push_move_exec(const u8* BS_ptr) +void BattleScriptPushCursorAndCallback(const u8* BS_ptr) { BattleScriptPushCursor(); gBattlescriptCurrInstr = BS_ptr; @@ -5549,7 +5545,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleScripting.bank = bank; gStringBank = bank; gActiveBank = gBankAttacker = bank; - b_call_bc_move_exec(BattleScript_WhiteHerbEnd2); + BattleScriptExecute(BattleScript_WhiteHerbEnd2); } break; } @@ -5566,7 +5562,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) if (gBattleMons[bank].hp + bankQuality > gBattleMons[bank].maxHP) gBattleMoveDamage = gBattleMons[bank].maxHP - gBattleMons[bank].hp; gBattleMoveDamage *= -1; - b_call_bc_move_exec(BattleScript_ItemHealHP_RemoveItem); + BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem); effect = 4; } break; @@ -5601,7 +5597,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleTextBuff1[2] = move; gBattleTextBuff1[3] = move >> 8; gBattleTextBuff1[4] = 0xFF; - b_call_bc_move_exec(BattleScript_BerryPPHealEnd2); + BattleScriptExecute(BattleScript_BerryPPHealEnd2); EmitSetMonData(0, i + REQUEST_PPMOVE1_BATTLE, 0, 1, &changedPP); MarkBufferBankForExecution(gActiveBank); effect = ITEM_PP_CHANGE; @@ -5622,7 +5618,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleScripting.bank = bank; gStringBank = bank; gActiveBank = gBankAttacker = bank; - b_call_bc_move_exec(BattleScript_WhiteHerbEnd2); + BattleScriptExecute(BattleScript_WhiteHerbEnd2); } break; case HOLD_EFFECT_LEFTOVERS: @@ -5634,7 +5630,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) if (gBattleMons[bank].hp + gBattleMoveDamage > gBattleMons[bank].maxHP) gBattleMoveDamage = gBattleMons[bank].maxHP - gBattleMons[bank].hp; gBattleMoveDamage *= -1; - b_call_bc_move_exec(BattleScript_ItemHealHP_End2); + BattleScriptExecute(BattleScript_ItemHealHP_End2); effect = ITEM_HP_CHANGE; RecordItemEffectBattle(bank, bankHoldEffect); } @@ -5654,9 +5650,9 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleMoveDamage = gBattleMons[bank].maxHP - gBattleMons[bank].hp; gBattleMoveDamage *= -1; if (GetFlavourRelationByPersonality(gBattleMons[bank].personality, FLAVOR_SPICY) < 0) - b_call_bc_move_exec(BattleScript_BerryConfuseHealEnd2); + BattleScriptExecute(BattleScript_BerryConfuseHealEnd2); else - b_call_bc_move_exec(BattleScript_ItemHealHP_RemoveItem); + BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem); effect = ITEM_HP_CHANGE; } break; @@ -5674,9 +5670,9 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleMoveDamage = gBattleMons[bank].maxHP - gBattleMons[bank].hp; gBattleMoveDamage *= -1; if (GetFlavourRelationByPersonality(gBattleMons[bank].personality, FLAVOR_DRY) < 0) - b_call_bc_move_exec(BattleScript_BerryConfuseHealEnd2); + BattleScriptExecute(BattleScript_BerryConfuseHealEnd2); else - b_call_bc_move_exec(BattleScript_ItemHealHP_RemoveItem); + BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem); effect = ITEM_HP_CHANGE; } break; @@ -5694,9 +5690,9 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleMoveDamage = gBattleMons[bank].maxHP - gBattleMons[bank].hp; gBattleMoveDamage *= -1; if (GetFlavourRelationByPersonality(gBattleMons[bank].personality, FLAVOR_SWEET) < 0) - b_call_bc_move_exec(BattleScript_BerryConfuseHealEnd2); + BattleScriptExecute(BattleScript_BerryConfuseHealEnd2); else - b_call_bc_move_exec(BattleScript_ItemHealHP_RemoveItem); + BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem); effect = ITEM_HP_CHANGE; } break; @@ -5714,9 +5710,9 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleMoveDamage = gBattleMons[bank].maxHP - gBattleMons[bank].hp; gBattleMoveDamage *= -1; if (GetFlavourRelationByPersonality(gBattleMons[bank].personality, FLAVOR_BITTER) < 0) - b_call_bc_move_exec(BattleScript_BerryConfuseHealEnd2); + BattleScriptExecute(BattleScript_BerryConfuseHealEnd2); else - b_call_bc_move_exec(BattleScript_ItemHealHP_RemoveItem); + BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem); effect = ITEM_HP_CHANGE; } break; @@ -5734,9 +5730,9 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleMoveDamage = gBattleMons[bank].maxHP - gBattleMons[bank].hp; gBattleMoveDamage *= -1; if (GetFlavourRelationByPersonality(gBattleMons[bank].personality, FLAVOR_SOUR) < 0) - b_call_bc_move_exec(BattleScript_BerryConfuseHealEnd2); + BattleScriptExecute(BattleScript_BerryConfuseHealEnd2); else - b_call_bc_move_exec(BattleScript_ItemHealHP_RemoveItem); + BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem); effect = ITEM_HP_CHANGE; } break; @@ -5759,7 +5755,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleScripting.statChanger = 0x10 + STAT_STAGE_ATK; gBattleScripting.animArg1 = 0xE + STAT_STAGE_ATK; gBattleScripting.animArg2 = 0; - b_call_bc_move_exec(BattleScript_BerryStatRaiseEnd2); + BattleScriptExecute(BattleScript_BerryStatRaiseEnd2); effect = ITEM_STATS_CHANGE; } break; @@ -5775,7 +5771,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleScripting.statChanger = 0x10 + STAT_STAGE_DEF; gBattleScripting.animArg1 = 0xE + STAT_STAGE_DEF; gBattleScripting.animArg2 = 0; - b_call_bc_move_exec(BattleScript_BerryStatRaiseEnd2); + BattleScriptExecute(BattleScript_BerryStatRaiseEnd2); effect = ITEM_STATS_CHANGE; } break; @@ -5791,7 +5787,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleScripting.statChanger = 0x10 + STAT_STAGE_SPEED; gBattleScripting.animArg1 = 0xE + STAT_STAGE_SPEED; gBattleScripting.animArg2 = 0; - b_call_bc_move_exec(BattleScript_BerryStatRaiseEnd2); + BattleScriptExecute(BattleScript_BerryStatRaiseEnd2); effect = ITEM_STATS_CHANGE; } break; @@ -5807,7 +5803,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleScripting.statChanger = 0x10 + STAT_STAGE_SPATK; gBattleScripting.animArg1 = 0xE + STAT_STAGE_SPATK; gBattleScripting.animArg2 = 0; - b_call_bc_move_exec(BattleScript_BerryStatRaiseEnd2); + BattleScriptExecute(BattleScript_BerryStatRaiseEnd2); effect = ITEM_STATS_CHANGE; } break; @@ -5823,7 +5819,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleScripting.statChanger = 0x10 + STAT_STAGE_SPDEF; gBattleScripting.animArg1 = 0xE + STAT_STAGE_SPDEF; gBattleScripting.animArg2 = 0; - b_call_bc_move_exec(BattleScript_BerryStatRaiseEnd2); + BattleScriptExecute(BattleScript_BerryStatRaiseEnd2); effect = ITEM_STATS_CHANGE; } break; @@ -5831,7 +5827,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) if (gBattleMons[bank].hp <= gBattleMons[bank].maxHP / bankQuality && !moveTurn && !(gBattleMons[bank].status2 & STATUS2_FOCUS_ENERGY)) { gBattleMons[bank].status2 |= STATUS2_FOCUS_ENERGY; - b_call_bc_move_exec(BattleScript_BerryFocusEnergyEnd2); + BattleScriptExecute(BattleScript_BerryFocusEnergyEnd2); effect = ITEM_EFFECT_OTHER; } break; @@ -5868,7 +5864,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleScripting.statChanger = 0x21 + i; gBattleScripting.animArg1 = 0x21 + i + 6; gBattleScripting.animArg2 = 0; - b_call_bc_move_exec(BattleScript_BerryStatRaiseEnd2); + BattleScriptExecute(BattleScript_BerryStatRaiseEnd2); effect = ITEM_STATS_CHANGE; } } @@ -5877,7 +5873,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) if (gBattleMons[bank].status1 & STATUS_PARALYSIS) { gBattleMons[bank].status1 &= ~(STATUS_PARALYSIS); - b_call_bc_move_exec(BattleScript_BerryCurePrlzEnd2); + BattleScriptExecute(BattleScript_BerryCurePrlzEnd2); effect = ITEM_STATUS_CHANGE; } break; @@ -5885,7 +5881,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) if (gBattleMons[bank].status1 & STATUS_PSN_ANY) { gBattleMons[bank].status1 &= ~(STATUS_PSN_ANY | STATUS_TOXIC_COUNTER); - b_call_bc_move_exec(BattleScript_BerryCurePsnEnd2); + BattleScriptExecute(BattleScript_BerryCurePsnEnd2); effect = ITEM_STATUS_CHANGE; } break; @@ -5893,7 +5889,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) if (gBattleMons[bank].status1 & STATUS_BURN) { gBattleMons[bank].status1 &= ~(STATUS_BURN); - b_call_bc_move_exec(BattleScript_BerryCureBrnEnd2); + BattleScriptExecute(BattleScript_BerryCureBrnEnd2); effect = ITEM_STATUS_CHANGE; } break; @@ -5901,7 +5897,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) if (gBattleMons[bank].status1 & STATUS_FREEZE) { gBattleMons[bank].status1 &= ~(STATUS_FREEZE); - b_call_bc_move_exec(BattleScript_BerryCureFrzEnd2); + BattleScriptExecute(BattleScript_BerryCureFrzEnd2); effect = ITEM_STATUS_CHANGE; } break; @@ -5910,7 +5906,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) { gBattleMons[bank].status1 &= ~(STATUS_SLEEP); gBattleMons[bank].status2 &= ~(STATUS2_NIGHTMARE); - b_call_bc_move_exec(BattleScript_BerryCureSlpEnd2); + BattleScriptExecute(BattleScript_BerryCureSlpEnd2); effect = ITEM_STATUS_CHANGE; } break; @@ -5918,7 +5914,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) if (gBattleMons[bank].status2 & STATUS2_CONFUSION) { gBattleMons[bank].status2 &= ~(STATUS2_CONFUSION); - b_call_bc_move_exec(BattleScript_BerryCureConfusionEnd2); + BattleScriptExecute(BattleScript_BerryCureConfusionEnd2); effect = ITEM_EFFECT_OTHER; } break; @@ -5963,7 +5959,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) gBattleCommunication[MULTISTRING_CHOOSER] = 1; gBattleMons[bank].status1 = 0; gBattleMons[bank].status2 &= ~(STATUS2_CONFUSION); - b_call_bc_move_exec(BattleScript_BerryCureChosenStatusEnd2); + BattleScriptExecute(BattleScript_BerryCureChosenStatusEnd2); effect = ITEM_STATUS_CHANGE; } break; @@ -5972,7 +5968,7 @@ u8 ItemBattleEffects(u8 caseID, u8 bank, bool8 moveTurn) { gBattleMons[bank].status2 &= ~(STATUS2_INFATUATION); StringCopy(gBattleTextBuff1, gStatusConditionString_LoveJpn); - b_call_bc_move_exec(BattleScript_BerryCureChosenStatusEnd2); + BattleScriptExecute(BattleScript_BerryCureChosenStatusEnd2); gBattleCommunication[MULTISTRING_CHOOSER] = 0; effect = ITEM_EFFECT_OTHER; } diff --git a/src/battle_4.c b/src/battle_4.c index 9ef443b70..33ac48261 100644 --- a/src/battle_4.c +++ b/src/battle_4.c @@ -30,6 +30,10 @@ #include "pokemon_item_effects.h" #include "m4a.h" #include "mail.h" +#include "event_data.h" +#include "pokemon_storage_system.h" +#include "task.h" +#include "naming_screen.h" // variables @@ -98,6 +102,11 @@ extern u16 gLastUsedMovesByBanks[BATTLE_BANKS_COUNT]; extern u16 gTrainerBattleOpponent_A; extern u16 gTrainerBattleOpponent_B; extern u8 gUnknown_020241E9; +extern u16 gBattle_BG1_X; +extern u16 gBattle_BG1_Y; +extern u16 gBattle_BG2_X; +extern u16 gBattle_BG2_Y; +extern u16 gBattle_BG3_X; extern struct MusicPlayerInfo gMPlay_BGM; struct TrainerMoney @@ -130,6 +139,14 @@ extern void sub_81A5D44(void); // battle frontier 2 extern void sub_81B8E80(u8 bank, u8, u8); // party menu extern bool8 sub_81B1250(void); // ? extern u8 GetScaledHPFraction(s16 hp, s16 maxhp, u8 scale); // battle interface +extern bool8 InBattlePike(void); +extern bool8 InBattlePyramid(void); +extern u16 GetBattlePyramidPickupItemId(void); +extern u8 sav1_map_get_light_level(void); +extern u8 sub_813B21C(void); +extern u16 get_unknown_box_id(void); +extern void c2_berry_program_update_menu(void); +extern void sub_8035AA4(void); // BattleScripts extern const u8 BattleScript_MoveEnd[]; @@ -201,13 +218,24 @@ extern const u8 BattleScript_PrintPayDayMoneyString[]; extern const u8 BattleScript_SturdyPreventsOHKO[]; extern const u8 BattleScript_ObliviousPreventsAttraction[]; extern const u8 BattleScript_PauseEffectivenessSoundResultMsgEndMove[]; +extern const u8 BattleScript_CastformChange[]; +extern const u8 BattleScript_TrainerBallBlock[]; +extern const u8 BattleScript_WallyBallThrow[]; +extern const u8 BattleScript_SuccessBallThrow[]; +extern const u8 BattleScript_ShakeBallThrow[]; +extern const u8 BattleScript_PresentDamageTarget[]; +extern const u8 BattleScript_AlreadyAtFullHp[]; +extern const u8 BattleScript_PresentHealTarget[]; +extern const u8 BattleScript_WrapFree[]; +extern const u8 BattleScript_LeechSeedFree[]; +extern const u8 BattleScript_SpikesFree[]; // strings extern const u8 gText_BattleYesNoChoice[]; // read via orr #define BSScriptRead32(ptr) ((ptr)[0] | (ptr)[1] << 8 | (ptr)[2] << 16 | (ptr)[3] << 24) -#define BSScriptRead8(ptr) (((u8)((ptr)[0]))) +#define BSScriptRead16(ptr) ((ptr)[0] | ((ptr)[1] << 8)) #define BSScriptReadPtr(ptr) ((void *)BSScriptRead32(ptr)) // read via add @@ -220,270 +248,269 @@ extern const u8 gText_BattleYesNoChoice[]; #define TARGET_TURN_DAMAGED (((gSpecialStatuses[gBankTarget].moveturnLostHP_physical || gSpecialStatuses[gBankTarget].moveturnLostHP_special))) // this file's functions -bool8 IsTwoTurnsMove(u16 move); -void DestinyBondFlagUpdate(void); -u8 AttacksThisTurn(u8 bank, u16 move); // Note: returns 1 if it's a charging turn, otherwise 2. +static bool8 IsTwoTurnsMove(u16 move); +static void DestinyBondFlagUpdate(void); +static u8 AttacksThisTurn(u8 bank, u16 move); // Note: returns 1 if it's a charging turn, otherwise 2. static void CheckWonderGuardAndLevitate(void); -u8 ChangeStatBuffs(s8 statValue, u8 statId, u8, const u8* BS_ptr); -void sub_8056A3C(u8 arg0, u8 arg1, u8 arg2, u8 arg3, u8 arg4); -bool32 IsMonGettingExpSentOut(void); -void sub_804F17C(void); -bool8 sub_804F1CC(void); -void sub_804F100(void); -void sub_804F144(void); -bool8 sub_804F344(void); -void PutMonIconOnLvlUpBox(void); -void PutLevelAndGenderOnLvlUpBox(void); - -void atk00_attackcanceler(void); -void atk01_accuracycheck(void); -void atk02_attackstring(void); -void atk03_ppreduce(void); -void atk04_critcalc(void); -void atk05_damagecalc1(void); -void atk06_typecalc(void); -void atk07_dmg_adjustment(void); -void atk08_dmg_adjustment2(void); -void atk09_attackanimation(void); -void atk0A_waitanimation(void); -void atk0B_healthbarupdate(void); -void atk0C_datahpupdate(void); -void atk0D_critmessage(void); -void atk0E_effectiveness_sound(void); -void atk0F_resultmessage(void); -void atk10_printstring(void); -void atk11_printstring_playeronly(void); -void atk12_waitmessage(void); -void atk13_printfromtable(void); -void atk14_printfromtable_playeronly(void); -void atk15_seteffectwithchance(void); -void atk16_seteffectprimary(void); -void atk17_seteffectsecondary(void); -void atk18_status_effect_clear(void); -void atk19_faint_pokemon(void); -void atk1A_faint_animation(void); -void atk1B_faint_effects_clear(void); -void atk1C_jumpifstatus(void); -void atk1D_jumpifstatus2(void); -void atk1E_jumpifability(void); -void atk1F_jumpifsideaffecting(void); -void atk20_jumpifstat(void); -void atk21_jumpifstatus3(void); -void atk22_jumpiftype(void); -void atk23_getexp(void); -void atk24(void); -void atk25_move_values_cleanup(void); -void atk26_set_multihit(void); -void atk27_decrement_multihit(void); -void atk28_goto(void); -void atk29_jumpifbyte(void); -void atk2A_jumpifhalfword(void); -void atk2B_jumpifword(void); -void atk2C_jumpifarrayequal(void); -void atk2D_jumpifarraynotequal(void); -void atk2E_setbyte(void); -void atk2F_addbyte(void); -void atk30_subbyte(void); -void atk31_copyarray(void); -void atk32_copyarray_withindex(void); -void atk33_orbyte(void); -void atk34_orhalfword(void); -void atk35_orword(void); -void atk36_bicbyte(void); -void atk37_bichalfword(void); -void atk38_bicword(void); -void atk39_pause(void); -void atk3A_waitstate(void); -void atk3B_healthbar_update(void); -void atk3C_return(void); -void atk3D_end(void); -void atk3E_end2(void); -void atk3F_end3(void); -void atk40_jump_if_move_affected_by_protect(void); -void atk41_call(void); -void atk42_jumpiftype2(void); -void atk43_jumpifabilitypresent(void); -void atk44(void); -void atk45_playanimation(void); -void atk46_playanimation2(void); -void atk47_setgraphicalstatchangevalues(void); -void atk48_playstatchangeanimation(void); -void atk49_moveend(void); -void atk4A_typecalc2(void); -void atk4B_return_atk_to_ball(void); -void atk4C_copy_poke_data(void); -void atk4D_switch_data_update(void); -void atk4E_switchin_anim(void); -void atk4F_jump_if_cannot_switch(void); -void atk50_openpartyscreen(void); -void atk51_switch_handle_order(void); -void atk52_switch_in_effects(void); -void atk53_trainer_slide(void); -void atk54_effectiveness_sound(void); -void atk55_play_sound(void); -void atk56_fainting_cry(void); -void atk57(void); -void atk58_return_to_ball(void); -void atk59_learnmove_inbattle(void); -void atk5A_yesnoboxlearnmove(void); -void atk5B_yesnoboxstoplearningmove(void); -void atk5C_hitanimation(void); -void atk5D_getmoneyreward(void); -void atk5E_8025A70(void); -void atk5F_8025B24(void); -void atk60_increment_gamestat(void); -void atk61_8025BA4(void); -void atk62_08025C6C(void); -void atk63_jumptorandomattack(void); -void atk64_statusanimation(void); -void atk65_status2animation(void); -void atk66_chosenstatusanimation(void); -void atk67_yesnobox(void); -void atk68_80246A0(void); -void atk69_dmg_adjustment3(void); -void atk6A_removeitem(void); -void atk6B_atknameinbuff1(void); -void atk6C_draw_lvlupbox(void); -void atk6D_reset_sentpokes_value(void); -void atk6E_set_atk_to_player0(void); -void atk6F_set_visible(void); -void atk70_record_last_used_ability(void); -void atk71_buffer_move_to_learn(void); -void atk72_jump_if_can_run_frombattle(void); -void atk73_hp_thresholds(void); -void atk74_hp_thresholds2(void); -void atk75_item_effect_on_opponent(void); -void atk76_various(void); -void atk77_set_protect_like(void); -void atk78_faintifabilitynotdamp(void); -void atk79_setatkhptozero(void); -void atk7A_jumpwhiletargetvalid(void); -void atk7B_healhalfHP_if_possible(void); -void atk7C_trymirrormove(void); -void atk7D_set_rain(void); -void atk7E_setreflect(void); -void atk7F_setseeded(void); -void atk80_manipulatedamage(void); -void atk81_setrest(void); -void atk82_jumpifnotfirstturn(void); -void atk83_nop(void); -void atk84_jump_if_cant_sleep(void); -void atk85_stockpile(void); -void atk86_stockpiletobasedamage(void); -void atk87_stockpiletohpheal(void); -void atk88_negativedamage(void); -void atk89_statbuffchange(void); -void atk8A_normalisebuffs(void); -void atk8B_setbide(void); -void atk8C_confuseifrepeatingattackends(void); -void atk8D_setmultihit_counter(void); -void atk8E_init_multihit_string(void); -void atk8F_forcerandomswitch(void); -void atk90_conversion_type_change(void); -void atk91_givepaydaymoney(void); -void atk92_setlightscreen(void); -void atk93_ko_move(void); -void atk94_damagetohalftargethp(void); -void atk95_setsandstorm(void); -void atk96_weatherdamage(void); -void atk97_try_infatuation(void); -void atk98_status_icon_update(void); -void atk99_setmist(void); -void atk9A_set_focusenergy(void); -void atk9B_transformdataexecution(void); -void atk9C_set_substitute(void); -void atk9D_mimicattackcopy(void); -void atk9E_metronome(void); -void atk9F_dmgtolevel(void); -void atkA0_psywavedamageeffect(void); -void atkA1_counterdamagecalculator(void); -void atkA2_mirrorcoatdamagecalculator(void); -void atkA3_disablelastusedattack(void); -void atkA4_setencore(void); -void atkA5_painsplitdmgcalc(void); -void atkA6_settypetorandomresistance(void); -void atkA7_setalwayshitflag(void); -void atkA8_copymovepermanently(void); -void atkA9_sleeptalk_choose_move(void); -void atkAA_set_destinybond(void); -void atkAB_DestinyBondFlagUpdate(void); -void atkAC_remaininghptopower(void); -void atkAD_spite_ppreduce(void); -void atkAE_heal_party_status(void); -void atkAF_cursetarget(void); -void atkB0_set_spikes(void); -void atkB1_set_foresight(void); -void atkB2_setperishsong(void); -void atkB3_rolloutdamagecalculation(void); -void atkB4_jumpifconfusedandstatmaxed(void); -void atkB5_furycuttercalc(void); -void atkB6_happinesstodamagecalculation(void); -void atkB7_presentdamagecalculation(void); -void atkB8_set_safeguard(void); -void atkB9_magnitudedamagecalculation(void); -void atkBA_jumpifnopursuitswitchdmg(void); -void atkBB_setsunny(void); -void atkBC_maxattackhalvehp(void); -void atkBD_copyfoestats(void); -void atkBE_rapidspinfree(void); -void atkBF_set_defense_curl(void); -void atkC0_recoverbasedonsunlight(void); -void atkC1_hidden_power(void); -void atkC2_selectnexttarget(void); -void atkC3_setfutureattack(void); -void atkC4_beat_up(void); -void atkC5_setsemiinvulnerablebit(void); -void atkC6_clearsemiinvulnerablebit(void); -void atkC7_setminimize(void); -void atkC8_sethail(void); -void atkC9_jumpifattackandspecialattackcannotfall(void); -void atkCA_setforcedtarget(void); -void atkCB_setcharge(void); -void atkCC_callterrainattack(void); -void atkCD_cureifburnedparalysedorpoisoned(void); -void atkCE_settorment(void); -void atkCF_jumpifnodamage(void); -void atkD0_settaunt(void); -void atkD1_set_helpinghand(void); -void atkD2_swap_items(void); -void atkD3_copy_ability(void); -void atkD4_wish_effect(void); -void atkD5_setroots(void); -void atkD6_doubledamagedealtifdamaged(void); -void atkD7_setyawn(void); -void atkD8_setdamagetohealthdifference(void); -void atkD9_scaledamagebyhealthratio(void); -void atkDA_abilityswap(void); -void atkDB_imprisoneffect(void); -void atkDC_setgrudge(void); -void atkDD_weightdamagecalculation(void); -void atkDE_asistattackselect(void); -void atkDF_setmagiccoat(void); -void atkE0_setstealstatchange(void); -void atkE1_intimidate_string_loader(void); -void atkE2_switchout_abilities(void); -void atkE3_jumpifhasnohp(void); -void atkE4_getsecretpowereffect(void); -void atkE5_pickup(void); -void atkE6_castform_change_animation(void); -void atkE7_castform_data_change(void); -void atkE8_settypebasedhalvers(void); -void atkE9_setweatherballtype(void); -void atkEA_recycleitem(void); -void atkEB_settypetoterrain(void); -void atkEC_pursuit_sth(void); -void atkED_802B4B4(void); -void atkEE_removelightscreenreflect(void); -void atkEF_pokeball_catch_calculation(void); -void atkF0_copy_caught_poke(void); -void atkF1_setpoke_as_caught(void); -void atkF2_display_dex_info(void); -void atkF3_nickname_caught_poke(void); -void atkF4_802BEF0(void); -void atkF5_removeattackerstatus1(void); -void atkF6_802BF48(void); -void atkF7_802BF54(void); -void sub_8056EF8(void); +static u8 ChangeStatBuffs(s8 statValue, u8 statId, u8, const u8* BS_ptr); +static bool32 IsMonGettingExpSentOut(void); +static void sub_804F17C(void); +static bool8 sub_804F1CC(void); +static void sub_804F100(void); +static void sub_804F144(void); +static bool8 sub_804F344(void); +static void PutMonIconOnLvlUpBox(void); +static void PutLevelAndGenderOnLvlUpBox(void); + +static void atk00_attackcanceler(void); +static void atk01_accuracycheck(void); +static void atk02_attackstring(void); +static void atk03_ppreduce(void); +static void atk04_critcalc(void); +static void atk05_damagecalc1(void); +static void atk06_typecalc(void); +static void atk07_dmg_adjustment(void); +static void atk08_dmg_adjustment2(void); +static void atk09_attackanimation(void); +static void atk0A_waitanimation(void); +static void atk0B_healthbarupdate(void); +static void atk0C_datahpupdate(void); +static void atk0D_critmessage(void); +static void atk0E_effectiveness_sound(void); +static void atk0F_resultmessage(void); +static void atk10_printstring(void); +static void atk11_printstring_playeronly(void); +static void atk12_waitmessage(void); +static void atk13_printfromtable(void); +static void atk14_printfromtable_playeronly(void); +static void atk15_seteffectwithchance(void); +static void atk16_seteffectprimary(void); +static void atk17_seteffectsecondary(void); +static void atk18_status_effect_clear(void); +static void atk19_faint_pokemon(void); +static void atk1A_faint_animation(void); +static void atk1B_faint_effects_clear(void); +static void atk1C_jumpifstatus(void); +static void atk1D_jumpifstatus2(void); +static void atk1E_jumpifability(void); +static void atk1F_jumpifsideaffecting(void); +static void atk20_jumpifstat(void); +static void atk21_jumpifstatus3(void); +static void atk22_jumpiftype(void); +static void atk23_getexp(void); +static void atk24(void); +static void atk25_move_values_cleanup(void); +static void atk26_set_multihit(void); +static void atk27_decrement_multihit(void); +static void atk28_goto(void); +static void atk29_jumpifbyte(void); +static void atk2A_jumpifhalfword(void); +static void atk2B_jumpifword(void); +static void atk2C_jumpifarrayequal(void); +static void atk2D_jumpifarraynotequal(void); +static void atk2E_setbyte(void); +static void atk2F_addbyte(void); +static void atk30_subbyte(void); +static void atk31_copyarray(void); +static void atk32_copyarray_withindex(void); +static void atk33_orbyte(void); +static void atk34_orhalfword(void); +static void atk35_orword(void); +static void atk36_bicbyte(void); +static void atk37_bichalfword(void); +static void atk38_bicword(void); +static void atk39_pause(void); +static void atk3A_waitstate(void); +static void atk3B_healthbar_update(void); +static void atk3C_return(void); +static void atk3D_end(void); +static void atk3E_end2(void); +static void atk3F_end3(void); +static void atk40_jump_if_move_affected_by_protect(void); +static void atk41_call(void); +static void atk42_jumpiftype2(void); +static void atk43_jumpifabilitypresent(void); +static void atk44(void); +static void atk45_playanimation(void); +static void atk46_playanimation2(void); +static void atk47_setgraphicalstatchangevalues(void); +static void atk48_playstatchangeanimation(void); +static void atk49_moveend(void); +static void atk4A_typecalc2(void); +static void atk4B_return_atk_to_ball(void); +static void atk4C_copy_poke_data(void); +static void atk4D_switch_data_update(void); +static void atk4E_switchin_anim(void); +static void atk4F_jump_if_cannot_switch(void); +static void atk50_openpartyscreen(void); +static void atk51_switch_handle_order(void); +static void atk52_switch_in_effects(void); +static void atk53_trainer_slide(void); +static void atk54_effectiveness_sound(void); +static void atk55_play_sound(void); +static void atk56_fainting_cry(void); +static void atk57(void); +static void atk58_return_to_ball(void); +static void atk59_learnmove_inbattle(void); +static void atk5A_yesnoboxlearnmove(void); +static void atk5B_yesnoboxstoplearningmove(void); +static void atk5C_hitanimation(void); +static void atk5D_getmoneyreward(void); +static void atk5E_8025A70(void); +static void atk5F_8025B24(void); +static void atk60_increment_gamestat(void); +static void atk61_8025BA4(void); +static void atk62_08025C6C(void); +static void atk63_jumptorandomattack(void); +static void atk64_statusanimation(void); +static void atk65_status2animation(void); +static void atk66_chosenstatusanimation(void); +static void atk67_yesnobox(void); +static void atk68_80246A0(void); +static void atk69_dmg_adjustment3(void); +static void atk6A_removeitem(void); +static void atk6B_atknameinbuff1(void); +static void atk6C_draw_lvlupbox(void); +static void atk6D_reset_sentpokes_value(void); +static void atk6E_set_atk_to_player0(void); +static void atk6F_set_visible(void); +static void atk70_record_last_used_ability(void); +static void atk71_buffer_move_to_learn(void); +static void atk72_jump_if_can_run_frombattle(void); +static void atk73_hp_thresholds(void); +static void atk74_hp_thresholds2(void); +static void atk75_item_effect_on_opponent(void); +static void atk76_various(void); +static void atk77_set_protect_like(void); +static void atk78_faintifabilitynotdamp(void); +static void atk79_setatkhptozero(void); +static void atk7A_jumpwhiletargetvalid(void); +static void atk7B_healhalfHP_if_possible(void); +static void atk7C_trymirrormove(void); +static void atk7D_set_rain(void); +static void atk7E_setreflect(void); +static void atk7F_setseeded(void); +static void atk80_manipulatedamage(void); +static void atk81_setrest(void); +static void atk82_jumpifnotfirstturn(void); +static void atk83_nop(void); +static void atk84_jump_if_cant_sleep(void); +static void atk85_stockpile(void); +static void atk86_stockpiletobasedamage(void); +static void atk87_stockpiletohpheal(void); +static void atk88_negativedamage(void); +static void atk89_statbuffchange(void); +static void atk8A_normalisebuffs(void); +static void atk8B_setbide(void); +static void atk8C_confuseifrepeatingattackends(void); +static void atk8D_setmultihit_counter(void); +static void atk8E_init_multihit_string(void); +static void atk8F_forcerandomswitch(void); +static void atk90_conversion_type_change(void); +static void atk91_givepaydaymoney(void); +static void atk92_setlightscreen(void); +static void atk93_ko_move(void); +static void atk94_damagetohalftargethp(void); +static void atk95_setsandstorm(void); +static void atk96_weatherdamage(void); +static void atk97_try_infatuation(void); +static void atk98_status_icon_update(void); +static void atk99_setmist(void); +static void atk9A_set_focusenergy(void); +static void atk9B_transformdataexecution(void); +static void atk9C_set_substitute(void); +static void atk9D_mimicattackcopy(void); +static void atk9E_metronome(void); +static void atk9F_dmgtolevel(void); +static void atkA0_psywavedamageeffect(void); +static void atkA1_counterdamagecalculator(void); +static void atkA2_mirrorcoatdamagecalculator(void); +static void atkA3_disablelastusedattack(void); +static void atkA4_setencore(void); +static void atkA5_painsplitdmgcalc(void); +static void atkA6_settypetorandomresistance(void); +static void atkA7_setalwayshitflag(void); +static void atkA8_copymovepermanently(void); +static void atkA9_sleeptalk_choose_move(void); +static void atkAA_set_destinybond(void); +static void atkAB_DestinyBondFlagUpdate(void); +static void atkAC_remaininghptopower(void); +static void atkAD_spite_ppreduce(void); +static void atkAE_heal_party_status(void); +static void atkAF_cursetarget(void); +static void atkB0_set_spikes(void); +static void atkB1_set_foresight(void); +static void atkB2_setperishsong(void); +static void atkB3_rolloutdamagecalculation(void); +static void atkB4_jumpifconfusedandstatmaxed(void); +static void atkB5_furycuttercalc(void); +static void atkB6_happinesstodamagecalculation(void); +static void atkB7_presentdamagecalculation(void); +static void atkB8_set_safeguard(void); +static void atkB9_magnitudedamagecalculation(void); +static void atkBA_jumpifnopursuitswitchdmg(void); +static void atkBB_setsunny(void); +static void atkBC_maxattackhalvehp(void); +static void atkBD_copyfoestats(void); +static void atkBE_rapidspinfree(void); +static void atkBF_set_defense_curl(void); +static void atkC0_recoverbasedonsunlight(void); +static void atkC1_hidden_power(void); +static void atkC2_selectnexttarget(void); +static void atkC3_setfutureattack(void); +static void atkC4_beat_up(void); +static void atkC5_setsemiinvulnerablebit(void); +static void atkC6_clearsemiinvulnerablebit(void); +static void atkC7_setminimize(void); +static void atkC8_sethail(void); +static void atkC9_jumpifattackandspecialattackcannotfall(void); +static void atkCA_setforcedtarget(void); +static void atkCB_setcharge(void); +static void atkCC_callterrainattack(void); +static void atkCD_cureifburnedparalysedorpoisoned(void); +static void atkCE_settorment(void); +static void atkCF_jumpifnodamage(void); +static void atkD0_settaunt(void); +static void atkD1_set_helpinghand(void); +static void atkD2_swap_items(void); +static void atkD3_copy_ability(void); +static void atkD4_wish_effect(void); +static void atkD5_setroots(void); +static void atkD6_doubledamagedealtifdamaged(void); +static void atkD7_setyawn(void); +static void atkD8_setdamagetohealthdifference(void); +static void atkD9_scaledamagebyhealthratio(void); +static void atkDA_abilityswap(void); +static void atkDB_imprisoneffect(void); +static void atkDC_setgrudge(void); +static void atkDD_weightdamagecalculation(void); +static void atkDE_asistattackselect(void); +static void atkDF_setmagiccoat(void); +static void atkE0_setstealstatchange(void); +static void atkE1_intimidate_string_loader(void); +static void atkE2_switchout_abilities(void); +static void atkE3_jumpifhasnohp(void); +static void atkE4_getsecretpowereffect(void); +static void atkE5_pickup(void); +static void atkE6_castform_change_animation(void); +static void atkE7_castform_data_change(void); +static void atkE8_settypebasedhalvers(void); +static void atkE9_setweatherballtype(void); +static void atkEA_recycleitem(void); +static void atkEB_settypetoterrain(void); +static void atkEC_pursuit_sth(void); +static void atkED_802B4B4(void); +static void atkEE_removelightscreenreflect(void); +static void atkEF_pokeball_catch_calculation(void); +static void atkF0_give_caught_mon(void); +static void atkF1_set_caught_mon_dex_flags(void); +static void atkF2_display_dex_info(void); +static void atkF3_nickname_caught_poke(void); +static void atkF4_subattackerhpbydmg(void); +static void atkF5_removeattackerstatus1(void); +static void atkF6_802BF48(void); +static void atkF7_802BF54(void); +static void atkF8_trainer_slide_back(void); void (* const gBattleScriptingCommandsTable[])(void) = { @@ -727,15 +754,15 @@ void (* const gBattleScriptingCommandsTable[])(void) = atkED_802B4B4, atkEE_removelightscreenreflect, atkEF_pokeball_catch_calculation, - atkF0_copy_caught_poke, - atkF1_setpoke_as_caught, + atkF0_give_caught_mon, + atkF1_set_caught_mon_dex_flags, atkF2_display_dex_info, atkF3_nickname_caught_poke, - atkF4_802BEF0, + atkF4_subattackerhpbydmg, atkF5_removeattackerstatus1, atkF6_802BF48, atkF7_802BF54, - sub_8056EF8 + atkF8_trainer_slide_back }; struct StatFractions @@ -877,8 +904,22 @@ extern const struct SpriteTemplate SpriteTemplate_MonIconOnLvlUpBox; extern const u16 sProtectSuccessRates[]; extern const u16 sNaturePowerMoves[]; extern const u16 sWeightToDamageTable[]; +extern const u8 sTerrainToType[]; +extern const u8 sBallCatchBonuses[]; +extern const u16 gUnknown_0831C2C8[]; +extern const u8 gUnknown_0831C2E8[]; +extern const u8 gUnknown_0831C4F8[]; +extern const u8 sFlailHpScaleToPowerTable[12]; +extern const u16 gRarePickupItems[]; +extern const u16 gPickupItems[]; +extern const u8 gPickupProbabilities[]; + +extern const u16 gMovesForbiddenToCopy[]; +#define MIMIC_FORBIDDEN_END 0xFFFE +#define METRONOME_FORBIDDEN_END 0xFFFF +#define ASSIST_FORBIDDEN_END 0xFFFF -void atk00_attackcanceler(void) +static void atk00_attackcanceler(void) { s32 i; @@ -972,7 +1013,7 @@ void atk00_attackcanceler(void) } } -void JumpIfMoveFailed(u8 adder, u16 move) +static void JumpIfMoveFailed(u8 adder, u16 move) { const void* BS_ptr = gBattlescriptCurrInstr + adder; if (gBattleMoveFlags & MOVESTATUS_NOEFFECT) @@ -990,7 +1031,7 @@ void JumpIfMoveFailed(u8 adder, u16 move) gBattlescriptCurrInstr = BS_ptr; } -void atk40_jump_if_move_affected_by_protect(void) +static void atk40_jump_if_move_affected_by_protect(void) { if (TARGET_PROTECT_AFFECTED) { @@ -1062,7 +1103,7 @@ bool8 AccuracyCalcHelper(u16 move) return FALSE; } -void atk01_accuracycheck(void) +static void atk01_accuracycheck(void) { u16 move = BS2ScriptRead16(gBattlescriptCurrInstr + 5); @@ -1154,7 +1195,7 @@ void atk01_accuracycheck(void) } } -void atk02_attackstring(void) +static void atk02_attackstring(void) { if (gBattleExecBuffer) return; @@ -1167,7 +1208,7 @@ void atk02_attackstring(void) gBattleCommunication[MSG_DISPLAY] = 0; } -void atk03_ppreduce(void) +static void atk03_ppreduce(void) { s32 ppToDeduct = 1; @@ -1214,7 +1255,7 @@ void atk03_ppreduce(void) gBattlescriptCurrInstr++; } -void atk04_critcalc(void) +static void atk04_critcalc(void) { u8 holdEffect; u16 item, critChance; @@ -1251,7 +1292,7 @@ void atk04_critcalc(void) gBattlescriptCurrInstr++; } -void atk05_damagecalc1(void) +static void atk05_damagecalc1(void) { u16 sideStatus = gSideAffecting[GET_BANK_SIDE(gBankTarget)]; gBattleMoveDamage = CalculateBaseDamage(&gBattleMons[gBankAttacker], &gBattleMons[gBankTarget], gCurrentMove, @@ -1282,7 +1323,7 @@ void AI_CalcDmg(u8 bankAtk, u8 bankDef) gBattleMoveDamage = gBattleMoveDamage * 15 / 10; } -void ModulateDmgByType(u8 multiplier) +static void ModulateDmgByType(u8 multiplier) { gBattleMoveDamage = gBattleMoveDamage * multiplier / 10; if (gBattleMoveDamage == 0 && multiplier != 0) @@ -1319,7 +1360,7 @@ void ModulateDmgByType(u8 multiplier) #define TYPE_FORESIGHT 0xFE #define TYPE_ENDTABLE 0xFF -void atk06_typecalc(void) +static void atk06_typecalc(void) { s32 i = 0; u8 moveType; @@ -1464,7 +1505,7 @@ static void CheckWonderGuardAndLevitate(void) } } -void ModulateDmgByType2(u8 multiplier, u16 move, u8* flags) // same as ModulateDmgByType except different arguments +static void ModulateDmgByType2(u8 multiplier, u16 move, u8* flags) // same as ModulateDmgByType except different arguments { gBattleMoveDamage = gBattleMoveDamage * multiplier / 10; if (gBattleMoveDamage == 0 && multiplier != 0) @@ -1615,12 +1656,12 @@ static inline void ApplyRandomDmgMultiplier(void) } } -void Unused_ApplyRandomDmgMultiplier(void) +static void Unused_ApplyRandomDmgMultiplier(void) { ApplyRandomDmgMultiplier(); } -void atk07_dmg_adjustment(void) +static void atk07_dmg_adjustment(void) { u8 holdEffect, quality; @@ -1668,7 +1709,7 @@ void atk07_dmg_adjustment(void) gBattlescriptCurrInstr++; } -void atk08_dmg_adjustment2(void) // The same as 0x7 except it doesn't check for false swipe move effect. +static void atk08_dmg_adjustment2(void) // The same as 0x7 except it doesn't check for false swipe move effect. { u8 holdEffect, quality; @@ -1714,7 +1755,7 @@ void atk08_dmg_adjustment2(void) // The same as 0x7 except it doesn't check for gBattlescriptCurrInstr++; } -void atk09_attackanimation(void) +static void atk09_attackanimation(void) { if (gBattleExecBuffer) return; @@ -1768,20 +1809,20 @@ void atk09_attackanimation(void) } } -void atk0A_waitanimation(void) +static void atk0A_waitanimation(void) { if (gBattleExecBuffer == 0) gBattlescriptCurrInstr++; } -void atk0B_healthbarupdate(void) +static void atk0B_healthbarupdate(void) { if (gBattleExecBuffer) return; if (!(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) { - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); if (gBattleMons[gActiveBank].status2 & STATUS2_SUBSTITUTE && gDisableStructs[gActiveBank].substituteHP && !(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE)) { @@ -1810,7 +1851,7 @@ void atk0B_healthbarupdate(void) gBattlescriptCurrInstr += 2; } -void atk0C_datahpupdate(void) +static void atk0C_datahpupdate(void) { u32 moveType; @@ -1826,7 +1867,7 @@ void atk0C_datahpupdate(void) if (!(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) { - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); if (gBattleMons[gActiveBank].status2 & STATUS2_SUBSTITUTE && gDisableStructs[gActiveBank].substituteHP && !(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE)) { if (gDisableStructs[gActiveBank].substituteHP >= gBattleMoveDamage) @@ -1871,7 +1912,7 @@ void atk0C_datahpupdate(void) else { gTakenDmg[gActiveBank] += gBattleMoveDamage; - if (BSScriptRead8(gBattlescriptCurrInstr + 1) == BS_GET_TARGET) + if (gBattlescriptCurrInstr[1] == BS_GET_TARGET) gTakenDmgBanks[gActiveBank] = gBankAttacker; else gTakenDmgBanks[gActiveBank] = gBankTarget; @@ -1895,7 +1936,7 @@ void atk0C_datahpupdate(void) { gProtectStructs[gActiveBank].physicalDmg = gHpDealt; gSpecialStatuses[gActiveBank].moveturnLostHP_physical = gHpDealt; - if (BSScriptRead8(gBattlescriptCurrInstr + 1) == BS_GET_TARGET) + if (gBattlescriptCurrInstr[1] == BS_GET_TARGET) { gProtectStructs[gActiveBank].physicalBank = gBankAttacker; gSpecialStatuses[gActiveBank].moveturnPhysicalBank = gBankAttacker; @@ -1910,7 +1951,7 @@ void atk0C_datahpupdate(void) { gProtectStructs[gActiveBank].specialDmg = gHpDealt; gSpecialStatuses[gActiveBank].moveturnLostHP_special = gHpDealt; - if (BSScriptRead8(gBattlescriptCurrInstr + 1) == BS_GET_TARGET) + if (gBattlescriptCurrInstr[1] == BS_GET_TARGET) { gProtectStructs[gActiveBank].specialBank = gBankAttacker; gSpecialStatuses[gActiveBank].moveturnSpecialBank = gBankAttacker; @@ -1929,14 +1970,14 @@ void atk0C_datahpupdate(void) } else { - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); if (gSpecialStatuses[gActiveBank].moveturnLostHP == 0) gSpecialStatuses[gActiveBank].moveturnLostHP = 0xFFFF; } gBattlescriptCurrInstr += 2; } -void atk0D_critmessage(void) +static void atk0D_critmessage(void) { if (gBattleExecBuffer == 0) { @@ -1949,7 +1990,7 @@ void atk0D_critmessage(void) } } -void atk0E_effectiveness_sound(void) +static void atk0E_effectiveness_sound(void) { if (gBattleExecBuffer) return; @@ -1996,7 +2037,7 @@ void atk0E_effectiveness_sound(void) gBattlescriptCurrInstr++; } -void atk0F_resultmessage(void) +static void atk0F_resultmessage(void) { u32 stringId = 0; @@ -2085,7 +2126,7 @@ void atk0F_resultmessage(void) gBattlescriptCurrInstr++; } -void atk10_printstring(void) +static void atk10_printstring(void) { if (gBattleExecBuffer == 0) { @@ -2096,7 +2137,7 @@ void atk10_printstring(void) } } -void atk11_printstring_playeronly(void) +static void atk11_printstring_playeronly(void) { gActiveBank = gBankAttacker; @@ -2107,7 +2148,7 @@ void atk11_printstring_playeronly(void) gBattleCommunication[MSG_DISPLAY] = 1; } -void atk12_waitmessage(void) +static void atk12_waitmessage(void) { if (gBattleExecBuffer == 0) { @@ -2128,7 +2169,7 @@ void atk12_waitmessage(void) } } -void atk13_printfromtable(void) +static void atk13_printfromtable(void) { if (gBattleExecBuffer == 0) { @@ -2142,7 +2183,7 @@ void atk13_printfromtable(void) } } -void atk14_printfromtable_playeronly(void) +static void atk14_printfromtable_playeronly(void) { if (gBattleExecBuffer == 0) { @@ -2868,7 +2909,7 @@ void SetMoveEffect(bool8 primary, u8 certain) gBattleCommunication[MOVE_EFFECT_BYTE] = 0; } -void atk15_seteffectwithchance(void) +static void atk15_seteffectwithchance(void) { u32 percentChance; @@ -2901,19 +2942,19 @@ void atk15_seteffectwithchance(void) gBattleScripting.field_16 = 0; } -void atk16_seteffectprimary(void) +static void atk16_seteffectprimary(void) { SetMoveEffect(TRUE, 0); } -void atk17_seteffectsecondary(void) +static void atk17_seteffectsecondary(void) { SetMoveEffect(FALSE, 0); } -void atk18_status_effect_clear(void) +static void atk18_status_effect_clear(void) { - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); if (gBattleCommunication[MOVE_EFFECT_BYTE] <= MOVE_EFFECT_TOXIC) gBattleMons[gActiveBank].status1 &= (~gStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]); @@ -2925,7 +2966,7 @@ void atk18_status_effect_clear(void) gBattleScripting.field_16 = 0; } -void atk19_faint_pokemon(void) +static void atk19_faint_pokemon(void) { const u8 *BS_ptr; @@ -3012,22 +3053,22 @@ void atk19_faint_pokemon(void) } } -void atk1A_faint_animation(void) +static void atk1A_faint_animation(void) { if (gBattleExecBuffer == 0) { - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); EmitFaintAnimation(0); MarkBufferBankForExecution(gActiveBank); gBattlescriptCurrInstr += 2; } } -void atk1B_faint_effects_clear(void) +static void atk1B_faint_effects_clear(void) { if (gBattleExecBuffer == 0) { - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); if (!(gBattleTypeFlags & BATTLE_TYPE_ARENA) || gBattleMons[gActiveBank].hp == 0) { @@ -3041,9 +3082,9 @@ void atk1B_faint_effects_clear(void) } } -void atk1C_jumpifstatus(void) +static void atk1C_jumpifstatus(void) { - u8 bank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + u8 bank = GetBattleBank(gBattlescriptCurrInstr[1]); u32 flags = BS2ScriptRead32(gBattlescriptCurrInstr + 2); const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 6); @@ -3053,9 +3094,9 @@ void atk1C_jumpifstatus(void) gBattlescriptCurrInstr += 10; } -void atk1D_jumpifstatus2(void) +static void atk1D_jumpifstatus2(void) { - u8 bank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + u8 bank = GetBattleBank(gBattlescriptCurrInstr[1]); u32 flags = BS2ScriptRead32(gBattlescriptCurrInstr + 2); const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 6); @@ -3065,13 +3106,13 @@ void atk1D_jumpifstatus2(void) gBattlescriptCurrInstr += 10; } -void atk1E_jumpifability(void) +static void atk1E_jumpifability(void) { u8 bank; - u8 ability = BSScriptRead8(gBattlescriptCurrInstr + 2); + u8 ability = gBattlescriptCurrInstr[2]; const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 3); - if (BSScriptRead8(gBattlescriptCurrInstr + 1) == BS_GET_ATTACKER_SIDE) + if (gBattlescriptCurrInstr[1] == BS_GET_ATTACKER_SIDE) { bank = AbilityBattleEffects(ABILITYEFFECT_CHECK_BANK_SIDE, gBankAttacker, ability, 0, 0); if (bank) @@ -3084,7 +3125,7 @@ void atk1E_jumpifability(void) else gBattlescriptCurrInstr += 7; } - else if (BSScriptRead8(gBattlescriptCurrInstr + 1) == BS_GET_NOT_ATTACKER_SIDE) + else if (gBattlescriptCurrInstr[1] == BS_GET_NOT_ATTACKER_SIDE) { bank = AbilityBattleEffects(ABILITYEFFECT_CHECK_OTHER_SIDE, gBankAttacker, ability, 0, 0); if (bank) @@ -3099,7 +3140,7 @@ void atk1E_jumpifability(void) } else { - bank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + bank = GetBattleBank(gBattlescriptCurrInstr[1]); if (gBattleMons[bank].ability == ability) { gLastUsedAbility = ability; @@ -3112,13 +3153,13 @@ void atk1E_jumpifability(void) } } -void atk1F_jumpifsideaffecting(void) +static void atk1F_jumpifsideaffecting(void) { u8 side; u16 flags; const u8* jumpPtr; - if (BSScriptRead8(gBattlescriptCurrInstr + 1) == BS_GET_ATTACKER) + if (gBattlescriptCurrInstr[1] == BS_GET_ATTACKER) side = GET_BANK_SIDE(gBankAttacker); else side = GET_BANK_SIDE(gBankTarget); @@ -3132,36 +3173,36 @@ void atk1F_jumpifsideaffecting(void) gBattlescriptCurrInstr += 8; } -void atk20_jumpifstat(void) +static void atk20_jumpifstat(void) { u8 ret = 0; - u8 bank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); - u8 value = gBattleMons[bank].statStages[BSScriptRead8(gBattlescriptCurrInstr + 3)]; + u8 bank = GetBattleBank(gBattlescriptCurrInstr[1]); + u8 value = gBattleMons[bank].statStages[gBattlescriptCurrInstr[3]]; - switch (BSScriptRead8(gBattlescriptCurrInstr + 2)) + switch (gBattlescriptCurrInstr[2]) { case CMP_EQUAL: - if (value == BSScriptRead8(gBattlescriptCurrInstr + 4)) + if (value == gBattlescriptCurrInstr[4]) ret++; break; case CMP_NOT_EQUAL: - if (value != BSScriptRead8(gBattlescriptCurrInstr + 4)) + if (value != gBattlescriptCurrInstr[4]) ret++; break; case CMP_GREATER_THAN: - if (value > BSScriptRead8(gBattlescriptCurrInstr + 4)) + if (value > gBattlescriptCurrInstr[4]) ret++; break; case CMP_LESS_THAN: - if (value < BSScriptRead8(gBattlescriptCurrInstr + 4)) + if (value < gBattlescriptCurrInstr[4]) ret++; break; case CMP_COMMON_BITS: - if (value & BSScriptRead8(gBattlescriptCurrInstr + 4)) + if (value & gBattlescriptCurrInstr[4]) ret++; break; case CMP_NO_COMMON_BITS: - if (!(value & BSScriptRead8(gBattlescriptCurrInstr + 4))) + if (!(value & gBattlescriptCurrInstr[4])) ret++; break; } @@ -3172,16 +3213,16 @@ void atk20_jumpifstat(void) gBattlescriptCurrInstr += 9; } -void atk21_jumpifstatus3(void) +static void atk21_jumpifstatus3(void) { u32 flags; const u8* jumpPtr; - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); flags = BS2ScriptRead32(gBattlescriptCurrInstr + 2); jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 7); - if (BSScriptRead8(gBattlescriptCurrInstr + 6)) + if (gBattlescriptCurrInstr[6]) { if ((gStatuses3[gActiveBank] & flags) != 0) gBattlescriptCurrInstr += 11; @@ -3197,10 +3238,10 @@ void atk21_jumpifstatus3(void) } } -void atk22_jumpiftype(void) +static void atk22_jumpiftype(void) { - u8 bank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); - u8 type = BSScriptRead8(gBattlescriptCurrInstr + 2); + u8 bank = GetBattleBank(gBattlescriptCurrInstr[1]); + u8 type = gBattlescriptCurrInstr[2]; const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 3); if (gBattleMons[bank].type1 == type || gBattleMons[bank].type2 == type) @@ -3209,7 +3250,7 @@ void atk22_jumpiftype(void) gBattlescriptCurrInstr += 7; } -void atk23_getexp(void) +static void atk23_getexp(void) { u16 item; s32 i; // also used as stringId @@ -3219,7 +3260,7 @@ void atk23_getexp(void) s32 viaExpShare = 0; u16* exp = &gBattleStruct->expValue; - gBank1 = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gBank1 = GetBattleBank(gBattlescriptCurrInstr[1]); sentIn = gSentPokesToOpponent[(gBank1 & 2) >> 1]; switch (gBattleScripting.atk23_state) @@ -3487,7 +3528,7 @@ void atk23_getexp(void) } #ifdef NONMATCHING -void atk24(void) +static void atk24(void) { u16 HP_count = 0; s32 i; @@ -3570,7 +3611,7 @@ void atk24(void) } #else __attribute__((naked)) -void atk24(void) +static void atk24(void) { asm("\n\ .syntax unified\n\ @@ -3864,7 +3905,7 @@ void atk24(void) #endif // NONMATCHING -void MoveValuesCleanUp(void) +static void MoveValuesCleanUp(void) { gBattleMoveFlags = 0; gBattleScripting.dmgMultiplier = 1; @@ -3875,19 +3916,19 @@ void MoveValuesCleanUp(void) gHitMarker &= ~(HITMARKER_SYNCHRONISE_EFFECT); } -void atk25_move_values_cleanup(void) +static void atk25_move_values_cleanup(void) { MoveValuesCleanUp(); gBattlescriptCurrInstr += 1; } -void atk26_set_multihit(void) +static void atk26_set_multihit(void) { - gMultiHitCounter = BSScriptRead8(gBattlescriptCurrInstr + 1); + gMultiHitCounter = gBattlescriptCurrInstr[1]; gBattlescriptCurrInstr += 2; } -void atk27_decrement_multihit(void) +static void atk27_decrement_multihit(void) { if (--gMultiHitCounter == 0) gBattlescriptCurrInstr += 5; @@ -3895,16 +3936,16 @@ void atk27_decrement_multihit(void) gBattlescriptCurrInstr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); } -void atk28_goto(void) +static void atk28_goto(void) { gBattlescriptCurrInstr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); } -void atk29_jumpifbyte(void) +static void atk29_jumpifbyte(void) { - u8 caseID = BSScriptRead8(gBattlescriptCurrInstr + 1); + u8 caseID = gBattlescriptCurrInstr[1]; const u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 2); - u8 value = BSScriptRead8(gBattlescriptCurrInstr + 6); + u8 value = gBattlescriptCurrInstr[6]; const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 7); gBattlescriptCurrInstr += 11; @@ -3938,9 +3979,9 @@ void atk29_jumpifbyte(void) } } -void atk2A_jumpifhalfword(void) +static void atk2A_jumpifhalfword(void) { - u8 caseID = BSScriptRead8(gBattlescriptCurrInstr + 1); + u8 caseID = gBattlescriptCurrInstr[1]; const u16* memHword = BS2ScriptReadPtr(gBattlescriptCurrInstr + 2); u16 value = BS2ScriptRead16(gBattlescriptCurrInstr + 6); const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 8); @@ -3976,9 +4017,9 @@ void atk2A_jumpifhalfword(void) } } -void atk2B_jumpifword(void) +static void atk2B_jumpifword(void) { - u8 caseID = BSScriptRead8(gBattlescriptCurrInstr + 1); + u8 caseID = gBattlescriptCurrInstr[1]; const u32* memWord = BS2ScriptReadPtr(gBattlescriptCurrInstr + 2); u32 value = BSScriptRead32(gBattlescriptCurrInstr + 6); const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 10); @@ -4014,11 +4055,11 @@ void atk2B_jumpifword(void) } } -void atk2C_jumpifarrayequal(void) +static void atk2C_jumpifarrayequal(void) { const u8* mem1 = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); const u8* mem2 = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5); - u32 size = BSScriptRead8(gBattlescriptCurrInstr + 9); + u32 size = gBattlescriptCurrInstr[9]; const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 10); u8 i; @@ -4036,12 +4077,12 @@ void atk2C_jumpifarrayequal(void) gBattlescriptCurrInstr = jumpPtr; } -void atk2D_jumpifarraynotequal(void) +static void atk2D_jumpifarraynotequal(void) { u8 equalBytes = 0; const u8* mem1 = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); const u8* mem2 = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5); - u32 size = BSScriptRead8(gBattlescriptCurrInstr + 9); + u32 size = gBattlescriptCurrInstr[9]; const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 10); u8 i; @@ -4060,33 +4101,33 @@ void atk2D_jumpifarraynotequal(void) gBattlescriptCurrInstr += 14; } -void atk2E_setbyte(void) +static void atk2E_setbyte(void) { u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); - *memByte = BSScriptRead8(gBattlescriptCurrInstr + 5); + *memByte = gBattlescriptCurrInstr[5]; gBattlescriptCurrInstr += 6; } -void atk2F_addbyte(void) +static void atk2F_addbyte(void) { u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); - *memByte += BSScriptRead8(gBattlescriptCurrInstr + 5); + *memByte += gBattlescriptCurrInstr[5]; gBattlescriptCurrInstr += 6; } -void atk30_subbyte(void) +static void atk30_subbyte(void) { u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); - *memByte -= BSScriptRead8(gBattlescriptCurrInstr + 5); + *memByte -= gBattlescriptCurrInstr[5]; gBattlescriptCurrInstr += 6; } -void atk31_copyarray(void) +static void atk31_copyarray(void) { u8* dest = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); const u8* src = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5); - s32 size = BSScriptRead8(gBattlescriptCurrInstr + 9); + s32 size = gBattlescriptCurrInstr[9]; s32 i; for (i = 0; i < size; i++) @@ -4097,12 +4138,12 @@ void atk31_copyarray(void) gBattlescriptCurrInstr += 10; } -void atk32_copyarray_withindex(void) +static void atk32_copyarray_withindex(void) { u8* dest = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); const u8* src = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5); const u8* index = BS2ScriptReadPtr(gBattlescriptCurrInstr + 9); - s32 size = BSScriptRead8(gBattlescriptCurrInstr + 13); + s32 size = gBattlescriptCurrInstr[13]; s32 i; for (i = 0; i < size; i++) @@ -4113,14 +4154,14 @@ void atk32_copyarray_withindex(void) gBattlescriptCurrInstr += 14; } -void atk33_orbyte(void) +static void atk33_orbyte(void) { u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); - *memByte |= BSScriptRead8(gBattlescriptCurrInstr + 5); + *memByte |= gBattlescriptCurrInstr[5]; gBattlescriptCurrInstr += 6; } -void atk34_orhalfword(void) +static void atk34_orhalfword(void) { u16* memHword = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); u16 val = BS2ScriptRead16(gBattlescriptCurrInstr + 5); @@ -4129,7 +4170,7 @@ void atk34_orhalfword(void) gBattlescriptCurrInstr += 7; } -void atk35_orword(void) +static void atk35_orword(void) { u32* memWord = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); u32 val = BS2ScriptRead32(gBattlescriptCurrInstr + 5); @@ -4138,14 +4179,14 @@ void atk35_orword(void) gBattlescriptCurrInstr += 9; } -void atk36_bicbyte(void) +static void atk36_bicbyte(void) { u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); - *memByte &= ~(BSScriptRead8(gBattlescriptCurrInstr + 5)); + *memByte &= ~(gBattlescriptCurrInstr[5]); gBattlescriptCurrInstr += 6; } -void atk37_bichalfword(void) +static void atk37_bichalfword(void) { u16* memHword = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); u16 val = BS2ScriptRead16(gBattlescriptCurrInstr + 5); @@ -4154,7 +4195,7 @@ void atk37_bichalfword(void) gBattlescriptCurrInstr += 7; } -void atk38_bicword(void) +static void atk38_bicword(void) { u32* memWord = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); u32 val = BS2ScriptRead32(gBattlescriptCurrInstr + 5); @@ -4163,7 +4204,7 @@ void atk38_bicword(void) gBattlescriptCurrInstr += 9; } -void atk39_pause(void) +static void atk39_pause(void) { if (gBattleExecBuffer == 0) { @@ -4176,15 +4217,15 @@ void atk39_pause(void) } } -void atk3A_waitstate(void) +static void atk3A_waitstate(void) { if (gBattleExecBuffer == 0) gBattlescriptCurrInstr++; } -void atk3B_healthbar_update(void) +static void atk3B_healthbar_update(void) { - if (BSScriptRead8(gBattlescriptCurrInstr + 1) == BS_GET_TARGET) + if (gBattlescriptCurrInstr[1] == BS_GET_TARGET) gActiveBank = gBankTarget; else gActiveBank = gBankAttacker; @@ -4194,12 +4235,12 @@ void atk3B_healthbar_update(void) gBattlescriptCurrInstr += 2; } -void atk3C_return(void) +static void atk3C_return(void) { BattleScriptPop(); } -void atk3D_end(void) +static void atk3D_end(void) { if (gBattleTypeFlags & BATTLE_TYPE_ARENA) sub_81A5718(gBankAttacker); @@ -4209,13 +4250,13 @@ void atk3D_end(void) gFightStateTracker = 0xB; } -void atk3E_end2(void) +static void atk3E_end2(void) { gActiveBank = 0; gFightStateTracker = 0xB; } -void atk3F_end3(void) // pops the main function stack +static void atk3F_end3(void) // pops the main function stack { BattleScriptPop(); if (BATTLE_CALLBACKS_STACK->size) @@ -4223,40 +4264,40 @@ void atk3F_end3(void) // pops the main function stack gBattleMainFunc = BATTLE_CALLBACKS_STACK->function[BATTLE_CALLBACKS_STACK->size]; } -void atk41_call(void) +static void atk41_call(void) { BattleScriptPush(gBattlescriptCurrInstr + 5); gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); } -void atk42_jumpiftype2(void) +static void atk42_jumpiftype2(void) { - u8 bank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + u8 bank = GetBattleBank(gBattlescriptCurrInstr[1]); - if (BSScriptRead8(gBattlescriptCurrInstr + 2) == gBattleMons[bank].type1 || BSScriptRead8(gBattlescriptCurrInstr + 2) == gBattleMons[bank].type2) + if (gBattlescriptCurrInstr[2] == gBattleMons[bank].type1 || gBattlescriptCurrInstr[2] == gBattleMons[bank].type2) gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 3); else gBattlescriptCurrInstr += 7; } -void atk43_jumpifabilitypresent(void) +static void atk43_jumpifabilitypresent(void) { - if (AbilityBattleEffects(ABILITYEFFECT_CHECK_ON_FIELD, 0, BSScriptRead8(gBattlescriptCurrInstr + 1), 0, 0)) + if (AbilityBattleEffects(ABILITYEFFECT_CHECK_ON_FIELD, 0, gBattlescriptCurrInstr[1], 0, 0)) gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); else gBattlescriptCurrInstr += 6; } -void atk44(void) +static void atk44(void) { *(gBankAttacker + gBattleStruct->field_54) = 1; } -void atk45_playanimation(void) +static void atk45_playanimation(void) { const u16* argumentPtr; - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); argumentPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 3); if (gBattlescriptCurrInstr[2] == B_ANIM_STATS_CHANGE @@ -4293,12 +4334,12 @@ void atk45_playanimation(void) } } -void atk46_playanimation2(void) // animation Id is stored in the first pointer +static void atk46_playanimation2(void) // animation Id is stored in the first pointer { const u16* argumentPtr; const u8* animationIdPtr; - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); animationIdPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 2); argumentPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 6); @@ -4335,7 +4376,7 @@ void atk46_playanimation2(void) // animation Id is stored in the first pointer } } -void atk47_setgraphicalstatchangevalues(void) +static void atk47_setgraphicalstatchangevalues(void) { u8 value = 0; switch (gBattleScripting.statChanger & 0xF0) @@ -4359,7 +4400,7 @@ void atk47_setgraphicalstatchangevalues(void) } #ifdef NONMATCHING -void atk48_playstatchangeanimation(void) +static void atk48_playstatchangeanimation(void) { u32 currStat = 0; s16 statAnimId = 0; @@ -4450,7 +4491,7 @@ void atk48_playstatchangeanimation(void) } #else __attribute__((naked)) -void atk48_playstatchangeanimation(void) +static void atk48_playstatchangeanimation(void) { asm("\n\ .syntax unified\n\ @@ -4706,7 +4747,7 @@ _0804BBBA:\n\ #define ATK49_LAST_CASE 17 -void atk49_moveend(void) +static void atk49_moveend(void) { s32 i; bool32 effect; @@ -4992,7 +5033,7 @@ void atk49_moveend(void) gBattlescriptCurrInstr += 3; } -void atk4A_typecalc2(void) +static void atk4A_typecalc2(void) { u8 flags = 0; s32 i = 0; @@ -5087,7 +5128,7 @@ void atk4A_typecalc2(void) gBattlescriptCurrInstr++; } -void atk4B_return_atk_to_ball(void) +static void atk4B_return_atk_to_ball(void) { gActiveBank = gBankAttacker; if (!(gHitMarker & HITMARKER_FAINTED(gActiveBank))) @@ -5098,12 +5139,12 @@ void atk4B_return_atk_to_ball(void) gBattlescriptCurrInstr++; } -void atk4C_copy_poke_data(void) +static void atk4C_copy_poke_data(void) { if (gBattleExecBuffer) return; - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); gBattlePartyID[gActiveBank] = *(gBattleStruct->field_5C + gActiveBank); @@ -5113,7 +5154,7 @@ void atk4C_copy_poke_data(void) gBattlescriptCurrInstr += 2; } -void atk4D_switch_data_update(void) +static void atk4D_switch_data_update(void) { struct BattlePokemon oldData; s32 i; @@ -5122,7 +5163,7 @@ void atk4D_switch_data_update(void) if (gBattleExecBuffer) return; - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); oldData = gBattleMons[gActiveBank]; monData = (u8*)(&gBattleMons[gActiveBank]); @@ -5169,12 +5210,12 @@ void atk4D_switch_data_update(void) gBattlescriptCurrInstr += 2; } -void atk4E_switchin_anim(void) +static void atk4E_switchin_anim(void) { if (gBattleExecBuffer) return; - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); if (GetBankSide(gActiveBank) == SIDE_OPPONENT && !(gBattleTypeFlags & (BATTLE_TYPE_LINK @@ -5195,7 +5236,7 @@ void atk4E_switchin_anim(void) sub_81A56B4(); } -void atk4F_jump_if_cannot_switch(void) +static void atk4F_jump_if_cannot_switch(void) { s32 val = 0; s32 compareVar = 0; @@ -5349,7 +5390,7 @@ void atk4F_jump_if_cannot_switch(void) } } -void sub_804CF10(u8 arg0) +static void sub_804CF10(u8 arg0) { *(gBattleStruct->field_58 + gActiveBank) = gBattlePartyID[gActiveBank]; *(gBattleStruct->field_5C + gActiveBank) = 6; @@ -5359,7 +5400,7 @@ void sub_804CF10(u8 arg0) MarkBufferBankForExecution(gActiveBank); } -void atk50_openpartyscreen(void) +static void atk50_openpartyscreen(void) { u32 flags; u8 hitmarkerFaintBits; @@ -5649,15 +5690,15 @@ void atk50_openpartyscreen(void) } } -void atk51_switch_handle_order(void) +static void atk51_switch_handle_order(void) { s32 i; if (gBattleExecBuffer) return; - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - switch (BSScriptRead8(gBattlescriptCurrInstr + 2)) + switch (gBattlescriptCurrInstr[2]) { case 0: for (i = 0; i < gNoOfAllBanks; i++) @@ -5716,11 +5757,11 @@ void atk51_switch_handle_order(void) gBattlescriptCurrInstr += 3; } -void atk52_switch_in_effects(void) +static void atk52_switch_in_effects(void) { s32 i; - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); sub_803FA70(gActiveBank); gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); @@ -5747,9 +5788,9 @@ void atk52_switch_in_effects(void) gBattleScripting.bank = gActiveBank; BattleScriptPushCursor(); - if (BSScriptRead8(gBattlescriptCurrInstr + 1) == 0) + if (gBattlescriptCurrInstr[1] == 0) gBattlescriptCurrInstr = gUnknown_082DAE90; - else if (BSScriptRead8(gBattlescriptCurrInstr + 1) == 1) + else if (gBattlescriptCurrInstr[1] == 1) gBattlescriptCurrInstr = gUnknown_082DAE59; else gBattlescriptCurrInstr = gUnknown_082DAEC7; @@ -5778,7 +5819,7 @@ void atk52_switch_in_effects(void) *hpOnSwitchout = gBattleMons[i].hp; } - if (BSScriptRead8(gBattlescriptCurrInstr + 1) == 5) + if (gBattlescriptCurrInstr[1] == 5) { u32 hitmarkerFaintBits = gHitMarker >> 0x1C; @@ -5797,7 +5838,7 @@ void atk52_switch_in_effects(void) } } -void atk53_trainer_slide(void) +static void atk53_trainer_slide(void) { gActiveBank = GetBankByIdentity(gBattlescriptCurrInstr[1]); EmitTrainerSlide(0); @@ -5806,7 +5847,7 @@ void atk53_trainer_slide(void) gBattlescriptCurrInstr += 2; } -void atk54_effectiveness_sound(void) +static void atk54_effectiveness_sound(void) { gActiveBank = gBankAttacker; EmitEffectivenessSound(0, BS2ScriptRead16(gBattlescriptCurrInstr + 1)); @@ -5815,7 +5856,7 @@ void atk54_effectiveness_sound(void) gBattlescriptCurrInstr += 3; } -void atk55_play_sound(void) +static void atk55_play_sound(void) { gActiveBank = gBankAttacker; EmitPlaySound(0, BS2ScriptRead16(gBattlescriptCurrInstr + 1), 0); @@ -5824,16 +5865,16 @@ void atk55_play_sound(void) gBattlescriptCurrInstr += 3; } -void atk56_fainting_cry(void) +static void atk56_fainting_cry(void) { - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); EmitFaintingCry(0); MarkBufferBankForExecution(gActiveBank); gBattlescriptCurrInstr += 2; } -void atk57(void) +static void atk57(void) { gActiveBank = GetBankByIdentity(0); Emit_x37(0, gBattleOutcome); @@ -5842,21 +5883,21 @@ void atk57(void) gBattlescriptCurrInstr += 1; } -void atk58_return_to_ball(void) +static void atk58_return_to_ball(void) { - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); EmitReturnPokeToBall(0, 1); MarkBufferBankForExecution(gActiveBank); gBattlescriptCurrInstr += 2; } -void atk59_learnmove_inbattle(void) +static void atk59_learnmove_inbattle(void) { const u8* jumpPtr1 = BSScriptReadPtr(gBattlescriptCurrInstr + 1); const u8* jumpPtr2 = BSScriptReadPtr(gBattlescriptCurrInstr + 5); - u16 ret = MonTryLearningNewMove(&gPlayerParty[gBattleStruct->expGetterId], BSScriptRead8(gBattlescriptCurrInstr + 9)); + u16 ret = MonTryLearningNewMove(&gPlayerParty[gBattleStruct->expGetterId], gBattlescriptCurrInstr[9]); while (ret == 0xFFFE) ret = MonTryLearningNewMove(&gPlayerParty[gBattleStruct->expGetterId], 0); @@ -5891,7 +5932,7 @@ void atk59_learnmove_inbattle(void) } } -void atk5A_yesnoboxlearnmove(void) +static void atk5A_yesnoboxlearnmove(void) { gActiveBank = 0; @@ -6010,7 +6051,7 @@ void atk5A_yesnoboxlearnmove(void) } } -void atk5B_yesnoboxstoplearningmove(void) +static void atk5B_yesnoboxstoplearningmove(void) { switch (gBattleScripting.learnMoveState) { @@ -6057,9 +6098,9 @@ void atk5B_yesnoboxstoplearningmove(void) } } -void atk5C_hitanimation(void) +static void atk5C_hitanimation(void) { - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); if (gBattleMoveFlags & MOVESTATUS_NOEFFECT) { @@ -6134,7 +6175,7 @@ static u32 GetTrainerMoneyToGive(u16 trainerId) return moneyReward; } -void atk5D_getmoneyreward(void) +static void atk5D_getmoneyreward(void) { u32 moneyReward = GetTrainerMoneyToGive(gTrainerBattleOpponent_A); if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) @@ -6147,9 +6188,9 @@ void atk5D_getmoneyreward(void) gBattlescriptCurrInstr++; } -void atk5E_8025A70(void) +static void atk5E_8025A70(void) { - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); switch (gBattleCommunication[0]) { @@ -6174,7 +6215,7 @@ void atk5E_8025A70(void) } } -void atk5F_8025B24(void) +static void atk5F_8025B24(void) { gActiveBank = gBankAttacker; gBankAttacker = gBankTarget; @@ -6188,15 +6229,15 @@ void atk5F_8025B24(void) gBattlescriptCurrInstr++; } -void atk60_increment_gamestat(void) +static void atk60_increment_gamestat(void) { if (GetBankSide(gBankAttacker) == SIDE_PLAYER) - IncrementGameStat(BSScriptRead8(gBattlescriptCurrInstr + 1)); + IncrementGameStat(gBattlescriptCurrInstr[1]); gBattlescriptCurrInstr += 2; } -void atk61_8025BA4(void) +static void atk61_8025BA4(void) { s32 i; struct Pokemon* party; @@ -6205,7 +6246,7 @@ void atk61_8025BA4(void) if (gBattleExecBuffer) return; - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); if (GetBankSide(gActiveBank) == SIDE_PLAYER) party = gPlayerParty; @@ -6233,18 +6274,18 @@ void atk61_8025BA4(void) gBattlescriptCurrInstr += 2; } -void atk62_08025C6C(void) +static void atk62_08025C6C(void) { - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); EmitCmd49(0); MarkBufferBankForExecution(gActiveBank); gBattlescriptCurrInstr += 2; } -void atk63_jumptorandomattack(void) +static void atk63_jumptorandomattack(void) { - if (BSScriptRead8(gBattlescriptCurrInstr + 1) != 0) + if (gBattlescriptCurrInstr[1] != 0) gCurrentMove = gRandomMove; else gLastUsedMove = gCurrentMove = gRandomMove; @@ -6252,11 +6293,11 @@ void atk63_jumptorandomattack(void) gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]; } -void atk64_statusanimation(void) +static void atk64_statusanimation(void) { if (gBattleExecBuffer == 0) { - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); if (!(gStatuses3[gActiveBank] & STATUS3_SEMI_INVULNERABLE) && gDisableStructs[gActiveBank].substituteHP == 0 && !(gHitMarker & HITMARKER_NO_ANIMATIONS)) @@ -6268,13 +6309,13 @@ void atk64_statusanimation(void) } } -void atk65_status2animation(void) +static void atk65_status2animation(void) { u32 wantedToAnimate; if (gBattleExecBuffer == 0) { - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); wantedToAnimate = BSScriptRead32(gBattlescriptCurrInstr + 2); if (!(gStatuses3[gActiveBank] & STATUS3_SEMI_INVULNERABLE) && gDisableStructs[gActiveBank].substituteHP == 0 @@ -6287,26 +6328,26 @@ void atk65_status2animation(void) } } -void atk66_chosenstatusanimation(void) +static void atk66_chosenstatusanimation(void) { u32 wantedStatus; if (gBattleExecBuffer == 0) { - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); wantedStatus = BSScriptRead32(gBattlescriptCurrInstr + 3); if (!(gStatuses3[gActiveBank] & STATUS3_SEMI_INVULNERABLE) && gDisableStructs[gActiveBank].substituteHP == 0 && !(gHitMarker & HITMARKER_NO_ANIMATIONS)) { - EmitStatusAnimation(0, BSScriptRead8(gBattlescriptCurrInstr + 2), wantedStatus); + EmitStatusAnimation(0, gBattlescriptCurrInstr[2], wantedStatus); MarkBufferBankForExecution(gActiveBank); } gBattlescriptCurrInstr += 7; } } -void atk67_yesnobox(void) +static void atk67_yesnobox(void) { switch (gBattleCommunication[0]) { @@ -6349,7 +6390,7 @@ void atk67_yesnobox(void) } } -void atk68_80246A0(void) +static void atk68_80246A0(void) { s32 i; @@ -6359,7 +6400,7 @@ void atk68_80246A0(void) gBattlescriptCurrInstr++; } -void atk69_dmg_adjustment3(void) // The same as 0x7, except there's no random damage multiplier. +static void atk69_dmg_adjustment3(void) // The same as 0x7, except there's no random damage multiplier. { u8 holdEffect, quality; @@ -6405,11 +6446,11 @@ void atk69_dmg_adjustment3(void) // The same as 0x7, except there's no random da gBattlescriptCurrInstr++; } -void atk6A_removeitem(void) +static void atk6A_removeitem(void) { u16* usedHeldItem; - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); usedHeldItem = &gBattleStruct->usedHeldItems[gActiveBank]; *usedHeldItem = gBattleMons[gActiveBank].item; @@ -6421,19 +6462,14 @@ void atk6A_removeitem(void) gBattlescriptCurrInstr += 2; } -void atk6B_atknameinbuff1(void) +static void atk6B_atknameinbuff1(void) { PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, gBankAttacker, gBattlePartyID[gBankAttacker]) gBattlescriptCurrInstr++; } -extern u16 gBattle_BG1_X; -extern u16 gBattle_BG1_Y; -extern u16 gBattle_BG2_X; -extern u16 gBattle_BG2_Y; - -void atk6C_draw_lvlupbox(void) +static void atk6C_draw_lvlupbox(void) { if (gBattleScripting.atk6C_state == 0) { @@ -6525,7 +6561,7 @@ void atk6C_draw_lvlupbox(void) } } -void sub_804F100(void) +static void sub_804F100(void) { struct StatsArray currentStats; @@ -6533,7 +6569,7 @@ void sub_804F100(void) sub_81D3640(0xD, gBattleResources->statsBeforeLvlUp, ¤tStats, 0xE, 0xD, 0xF); } -void sub_804F144(void) +static void sub_804F144(void) { struct StatsArray currentStats; @@ -6541,10 +6577,7 @@ void sub_804F144(void) sub_81D3784(0xD, ¤tStats, 0xE, 0xD, 0xF); } -extern const u16 gUnknown_0831C2C8[]; -extern const u8 gUnknown_0831C2E8[]; - -void sub_804F17C(void) +static void sub_804F17C(void) { gBattle_BG2_Y = 0; gBattle_BG2_X = 0x1A0; @@ -6557,7 +6590,7 @@ void sub_804F17C(void) PutMonIconOnLvlUpBox(); } -bool8 sub_804F1CC(void) +static bool8 sub_804F1CC(void) { if (IsDma3ManagerBusyWithBgCopy()) return TRUE; @@ -6575,7 +6608,7 @@ bool8 sub_804F1CC(void) return (gBattle_BG2_X != 0x200); } -void PutLevelAndGenderOnLvlUpBox(void) +static void PutLevelAndGenderOnLvlUpBox(void) { u16 monLevel; u8 monGender; @@ -6638,7 +6671,7 @@ void PutLevelAndGenderOnLvlUpBox(void) CopyWindowToVram(14, 2); } -bool8 sub_804F344(void) +static bool8 sub_804F344(void) { if (gBattle_BG2_X == 0x1A0) return FALSE; @@ -6656,7 +6689,7 @@ bool8 sub_804F344(void) #define sDestroy data0 #define sSavedLvlUpBoxXPosition data1 -void PutMonIconOnLvlUpBox(void) +static void PutMonIconOnLvlUpBox(void) { u8 spriteId; const u16* iconPal; @@ -6702,7 +6735,7 @@ void SpriteCB_MonIconOnLvlUpBox(struct Sprite* sprite) #undef sDestroy #undef sSavedLvlUpBoxXPosition -bool32 IsMonGettingExpSentOut(void) +static bool32 IsMonGettingExpSentOut(void) { if (gBattlePartyID[0] == gBattleStruct->expGetterId) return TRUE; @@ -6712,30 +6745,30 @@ bool32 IsMonGettingExpSentOut(void) return FALSE; } -void atk6D_reset_sentpokes_value(void) +static void atk6D_reset_sentpokes_value(void) { ResetSentPokesToOpponentValue(); gBattlescriptCurrInstr++; } -void atk6E_set_atk_to_player0(void) +static void atk6E_set_atk_to_player0(void) { gBankAttacker = GetBankByIdentity(0); gBattlescriptCurrInstr++; } -void atk6F_set_visible(void) +static void atk6F_set_visible(void) { - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); EmitSpriteInvisibility(0, FALSE); MarkBufferBankForExecution(gActiveBank); gBattlescriptCurrInstr += 2; } -void atk70_record_last_used_ability(void) +static void atk70_record_last_used_ability(void) { - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); RecordAbilityBattle(gActiveBank, gLastUsedAbility); gBattlescriptCurrInstr += 1; // UB: Should be + 2, one byte for command and one byte for bank argument. } @@ -6745,13 +6778,13 @@ void BufferMoveToLearnIntoBattleTextBuff2(void) PREPARE_MOVE_BUFFER(gBattleTextBuff2, gMoveToLearn); } -void atk71_buffer_move_to_learn(void) +static void atk71_buffer_move_to_learn(void) { BufferMoveToLearnIntoBattleTextBuff2(); gBattlescriptCurrInstr++; } -void atk72_jump_if_can_run_frombattle(void) +static void atk72_jump_if_can_run_frombattle(void) { if (CanRunFromBattle(gBank1)) gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); @@ -6759,14 +6792,14 @@ void atk72_jump_if_can_run_frombattle(void) gBattlescriptCurrInstr += 5; } -void atk73_hp_thresholds(void) +static void atk73_hp_thresholds(void) { u8 opposingBank; s32 result; if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) { - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); opposingBank = gActiveBank ^ BIT_SIDE; result = gBattleMons[opposingBank].hp * 100 / gBattleMons[opposingBank].maxHP; @@ -6786,7 +6819,7 @@ void atk73_hp_thresholds(void) gBattlescriptCurrInstr += 2; } -void atk74_hp_thresholds2(void) +static void atk74_hp_thresholds2(void) { u8 opposingBank; s32 result; @@ -6794,7 +6827,7 @@ void atk74_hp_thresholds2(void) if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) { - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); opposingBank = gActiveBank ^ BIT_SIDE; hpSwitchout = *(gBattleStruct->hpOnSwitchout + GetBankSide(opposingBank)); result = (hpSwitchout - gBattleMons[opposingBank].hp) * 100 / hpSwitchout; @@ -6812,7 +6845,7 @@ void atk74_hp_thresholds2(void) gBattlescriptCurrInstr += 2; } -void atk75_item_effect_on_opponent(void) +static void atk75_item_effect_on_opponent(void) { gBankInMenu = gBankAttacker; ExecuteTableBasedItemEffect(&gEnemyParty[gBattlePartyID[gBankAttacker]], gLastUsedItem, gBattlePartyID[gBankAttacker], 0, 1); @@ -6820,10 +6853,7 @@ void atk75_item_effect_on_opponent(void) gBattlescriptCurrInstr += 1; } -extern const u8 gUnknown_0831C4F8[]; -extern const u8* const gRefereeStringsTable[]; - -void atk76_various(void) +static void atk76_various(void) { u8 side; s32 i; @@ -7002,7 +7032,7 @@ void atk76_various(void) gBattlescriptCurrInstr += 3; } -void atk77_set_protect_like(void) // protect and endure +static void atk77_set_protect_like(void) // protect and endure { bool8 notLastTurn = TRUE; u16 lastMove = gUnknown_02024260[gBankAttacker]; @@ -7037,7 +7067,7 @@ void atk77_set_protect_like(void) // protect and endure gBattlescriptCurrInstr++; } -void atk78_faintifabilitynotdamp(void) +static void atk78_faintifabilitynotdamp(void) { if (gBattleExecBuffer) return; @@ -7072,7 +7102,7 @@ void atk78_faintifabilitynotdamp(void) } } -void atk79_setatkhptozero(void) +static void atk79_setatkhptozero(void) { if (gBattleExecBuffer) return; @@ -7085,7 +7115,7 @@ void atk79_setatkhptozero(void) gBattlescriptCurrInstr++; } -void atk7A_jumpwhiletargetvalid(void) // Used by intimidate to loop through all targets. +static void atk7A_jumpwhiletargetvalid(void) // Used by intimidate to loop through all targets. { const u8* jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); @@ -7108,11 +7138,11 @@ void atk7A_jumpwhiletargetvalid(void) // Used by intimidate to loop through all gBattlescriptCurrInstr += 5; } -void atk7B_healhalfHP_if_possible(void) +static void atk7B_healhalfHP_if_possible(void) { const u8* failPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - if (BSScriptRead8(gBattlescriptCurrInstr + 5) == BS_GET_ATTACKER) + if (gBattlescriptCurrInstr[5] == BS_GET_ATTACKER) gBankTarget = gBankAttacker; gBattleMoveDamage = gBattleMons[gBankTarget].maxHP / 2; @@ -7126,7 +7156,7 @@ void atk7B_healhalfHP_if_possible(void) gBattlescriptCurrInstr += 6; } -void atk7C_trymirrormove(void) +static void atk7C_trymirrormove(void) { s32 validMovesCount; s32 i; @@ -7176,7 +7206,7 @@ void atk7C_trymirrormove(void) } } -void atk7D_set_rain(void) +static void atk7D_set_rain(void) { if (gBattleWeather & WEATHER_RAIN_ANY) { @@ -7192,7 +7222,7 @@ void atk7D_set_rain(void) gBattlescriptCurrInstr++; } -void atk7E_setreflect(void) +static void atk7E_setreflect(void) { if (gSideAffecting[GET_BANK_SIDE(gBankAttacker)] & SIDE_STATUS_REFLECT) { @@ -7213,7 +7243,7 @@ void atk7E_setreflect(void) gBattlescriptCurrInstr++; } -void atk7F_setseeded(void) +static void atk7F_setseeded(void) { if (gBattleMoveFlags & MOVESTATUS_NOEFFECT || gStatuses3[gBankTarget] & STATUS3_LEECHSEED) { @@ -7235,9 +7265,9 @@ void atk7F_setseeded(void) gBattlescriptCurrInstr++; } -void atk80_manipulatedamage(void) +static void atk80_manipulatedamage(void) { - switch (BSScriptRead8(gBattlescriptCurrInstr + 1)) + switch (gBattlescriptCurrInstr[1]) { case ATK80_DMG_CHANGE_SIGN: gBattleMoveDamage *= -1; @@ -7257,7 +7287,7 @@ void atk80_manipulatedamage(void) gBattlescriptCurrInstr += 2; } -void atk81_setrest(void) +static void atk81_setrest(void) { const u8* failJump = BSScriptReadPtr(gBattlescriptCurrInstr + 1); gActiveBank = gBankTarget = gBankAttacker; @@ -7281,7 +7311,7 @@ void atk81_setrest(void) } } -void atk82_jumpifnotfirstturn(void) +static void atk82_jumpifnotfirstturn(void) { const u8* failJump = BSScriptReadPtr(gBattlescriptCurrInstr + 1); @@ -7291,7 +7321,7 @@ void atk82_jumpifnotfirstturn(void) gBattlescriptCurrInstr = failJump; } -void atk83_nop(void) +static void atk83_nop(void) { gBattlescriptCurrInstr++; } @@ -7323,7 +7353,7 @@ bool8 UproarWakeUpCheck(u8 bank) return TRUE; } -void atk84_jump_if_cant_sleep(void) +static void atk84_jump_if_cant_sleep(void) { const u8* jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); @@ -7345,7 +7375,7 @@ void atk84_jump_if_cant_sleep(void) } } -void atk85_stockpile(void) +static void atk85_stockpile(void) { if (gDisableStructs[gBankAttacker].stockpileCounter == 3) { @@ -7363,7 +7393,7 @@ void atk85_stockpile(void) gBattlescriptCurrInstr++; } -void atk86_stockpiletobasedamage(void) +static void atk86_stockpiletobasedamage(void) { const u8* jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); if (gDisableStructs[gBankAttacker].stockpileCounter == 0) @@ -7389,7 +7419,7 @@ void atk86_stockpiletobasedamage(void) } } -void atk87_stockpiletohpheal(void) +static void atk87_stockpiletohpheal(void) { const u8* jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); @@ -7420,7 +7450,7 @@ void atk87_stockpiletohpheal(void) } } -void atk88_negativedamage(void) +static void atk88_negativedamage(void) { gBattleMoveDamage = -(gHpDealt / 2); if (gBattleMoveDamage == 0) @@ -7429,7 +7459,7 @@ void atk88_negativedamage(void) gBattlescriptCurrInstr++; } -u8 ChangeStatBuffs(s8 statValue, u8 statId, u8 flags, const u8* BS_ptr) +static u8 ChangeStatBuffs(s8 statValue, u8 statId, u8 flags, const u8* BS_ptr) { bool8 certain = 0; bool8 notProtectAffected = FALSE; @@ -7599,14 +7629,14 @@ u8 ChangeStatBuffs(s8 statValue, u8 statId, u8 flags, const u8* BS_ptr) return STAT_CHANGE_WORKED; } -void atk89_statbuffchange(void) +static void atk89_statbuffchange(void) { const u8* jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); - if (ChangeStatBuffs(gBattleScripting.statChanger & 0xF0, GET_STAT_BUFF_ID(gBattleScripting.statChanger), BSScriptRead8(gBattlescriptCurrInstr + 1), jumpPtr) == STAT_CHANGE_WORKED) + if (ChangeStatBuffs(gBattleScripting.statChanger & 0xF0, GET_STAT_BUFF_ID(gBattleScripting.statChanger), gBattlescriptCurrInstr[1], jumpPtr) == STAT_CHANGE_WORKED) gBattlescriptCurrInstr += 6; } -void atk8A_normalisebuffs(void) // haze +static void atk8A_normalisebuffs(void) // haze { s32 i, j; @@ -7619,7 +7649,7 @@ void atk8A_normalisebuffs(void) // haze gBattlescriptCurrInstr++; } -void atk8B_setbide(void) +static void atk8B_setbide(void) { gBattleMons[gBankAttacker].status2 |= STATUS2_MULTIPLETURNS; gLockedMoves[gBankAttacker] = gCurrentMove; @@ -7629,7 +7659,7 @@ void atk8B_setbide(void) gBattlescriptCurrInstr++; } -void atk8C_confuseifrepeatingattackends(void) +static void atk8C_confuseifrepeatingattackends(void) { if (!(gBattleMons[gBankAttacker].status2 & STATUS2_LOCK_CONFUSE)) gBattleCommunication[MOVE_EFFECT_BYTE] = (MOVE_EFFECT_THRASH | MOVE_EFFECT_AFFECTS_USER); @@ -7637,11 +7667,11 @@ void atk8C_confuseifrepeatingattackends(void) gBattlescriptCurrInstr++; } -void atk8D_setmultihit_counter(void) +static void atk8D_setmultihit_counter(void) { - if (BSScriptRead8(gBattlescriptCurrInstr + 1)) + if (gBattlescriptCurrInstr[1]) { - gMultiHitCounter = BSScriptRead8(gBattlescriptCurrInstr + 1); + gMultiHitCounter = gBattlescriptCurrInstr[1]; } else { @@ -7655,14 +7685,14 @@ void atk8D_setmultihit_counter(void) gBattlescriptCurrInstr += 2; } -void atk8E_init_multihit_string(void) +static void atk8E_init_multihit_string(void) { PREPARE_BYTE_NUMBER_BUFFER(gBattleScripting.multihitString, 1, 0) gBattlescriptCurrInstr++; } -bool8 sub_8051064(void) +static bool8 sub_8051064(void) { if (gBattleMons[gBankAttacker].level >= gBattleMons[gBankTarget].level) { @@ -7683,7 +7713,7 @@ bool8 sub_8051064(void) return TRUE; } -void atk8F_forcerandomswitch(void) +static void atk8F_forcerandomswitch(void) { s32 i; s32 bank1PartyId = 0; @@ -7844,7 +7874,7 @@ void atk8F_forcerandomswitch(void) } } -void atk90_conversion_type_change(void) // randomly changes user's type to one of its moves' type +static void atk90_conversion_type_change(void) // randomly changes user's type to one of its moves' type { u8 validMoves = 0; u8 moveChecked; @@ -7908,7 +7938,7 @@ void atk90_conversion_type_change(void) // randomly changes user's type to one o } } -void atk91_givepaydaymoney(void) +static void atk91_givepaydaymoney(void) { if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000)) && gPaydayMoney != 0) { @@ -7926,7 +7956,7 @@ void atk91_givepaydaymoney(void) } } -void atk92_setlightscreen(void) +static void atk92_setlightscreen(void) { if (gSideAffecting[GET_BANK_SIDE(gBankAttacker)] & SIDE_STATUS_LIGHTSCREEN) { @@ -7948,7 +7978,7 @@ void atk92_setlightscreen(void) gBattlescriptCurrInstr++; } -void atk93_ko_move(void) +static void atk93_ko_move(void) { u8 holdEffect, param; @@ -8034,7 +8064,7 @@ void atk93_ko_move(void) } } -void atk94_damagetohalftargethp(void) // super fang +static void atk94_damagetohalftargethp(void) // super fang { gBattleMoveDamage = gBattleMons[gBankTarget].hp / 2; if (gBattleMoveDamage == 0) @@ -8043,7 +8073,7 @@ void atk94_damagetohalftargethp(void) // super fang gBattlescriptCurrInstr++; } -void atk95_setsandstorm(void) +static void atk95_setsandstorm(void) { if (gBattleWeather & WEATHER_SANDSTORM_ANY) { @@ -8059,7 +8089,7 @@ void atk95_setsandstorm(void) gBattlescriptCurrInstr++; } -void atk96_weatherdamage(void) +static void atk96_weatherdamage(void) { if (WEATHER_HAS_EFFECT) { @@ -8112,7 +8142,7 @@ void atk96_weatherdamage(void) gBattlescriptCurrInstr++; } -void atk97_try_infatuation(void) +static void atk97_try_infatuation(void) { struct Pokemon *monAttacker, *monTarget; u16 speciesAttacker, speciesTarget; @@ -8157,14 +8187,14 @@ void atk97_try_infatuation(void) } } -void atk98_status_icon_update(void) +static void atk98_status_icon_update(void) { if (gBattleExecBuffer) return; - if (BSScriptRead8(gBattlescriptCurrInstr + 1) != BS_ATTACKER_WITH_PARTNER) + if (gBattlescriptCurrInstr[1] != BS_ATTACKER_WITH_PARTNER) { - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); EmitStatusIconUpdate(0, gBattleMons[gActiveBank].status1, gBattleMons[gActiveBank].status2); MarkBufferBankForExecution(gActiveBank); gBattlescriptCurrInstr += 2; @@ -8190,7 +8220,7 @@ void atk98_status_icon_update(void) } } -void atk99_setmist(void) +static void atk99_setmist(void) { if (gSideTimers[GET_BANK_SIDE(gBankAttacker)].mistTimer) { @@ -8207,7 +8237,7 @@ void atk99_setmist(void) gBattlescriptCurrInstr++; } -void atk9A_set_focusenergy(void) +static void atk9A_set_focusenergy(void) { if (gBattleMons[gBankAttacker].status2 & STATUS2_FOCUS_ENERGY) { @@ -8222,7 +8252,7 @@ void atk9A_set_focusenergy(void) gBattlescriptCurrInstr++; } -void atk9B_transformdataexecution(void) +static void atk9B_transformdataexecution(void) { gLastUsedMove = 0xFFFF; gBattlescriptCurrInstr++; @@ -8266,7 +8296,7 @@ void atk9B_transformdataexecution(void) } } -void atk9C_set_substitute(void) +static void atk9C_set_substitute(void) { u32 hp = gBattleMons[gBankAttacker].maxHP / 4; if (gBattleMons[gBankAttacker].maxHP / 4 == 0) @@ -8293,11 +8323,6 @@ void atk9C_set_substitute(void) gBattlescriptCurrInstr++; } -extern const u16 gMovesForbiddenToCopy[]; -#define MIMIC_FORBIDDEN_END 0xFFFE -#define METRONOME_FORBIDDEN_END 0xFFFF -#define ASSIST_FORBIDDEN_END 0xFFFF - static bool8 IsMoveUncopyableByMimic(u16 move) { s32 i; @@ -8307,7 +8332,7 @@ static bool8 IsMoveUncopyableByMimic(u16 move) return (gMovesForbiddenToCopy[i] != MIMIC_FORBIDDEN_END); } -void atk9D_mimicattackcopy(void) +static void atk9D_mimicattackcopy(void) { gLastUsedMove = 0xFFFF; @@ -8350,7 +8375,7 @@ void atk9D_mimicattackcopy(void) } #ifdef NONMATCHING -void atk9E_metronome(void) +static void atk9E_metronome(void) { while (1) { @@ -8382,7 +8407,7 @@ void atk9E_metronome(void) #else __attribute__((naked)) -void atk9E_metronome(void) +static void atk9E_metronome(void) { asm( "\n\ @@ -8459,13 +8484,13 @@ _0805251C:\n\ #endif // NONMATCHING -void atk9F_dmgtolevel(void) +static void atk9F_dmgtolevel(void) { gBattleMoveDamage = gBattleMons[gBankAttacker].level; gBattlescriptCurrInstr++; } -void atkA0_psywavedamageeffect(void) +static void atkA0_psywavedamageeffect(void) { s32 randDamage; @@ -8476,7 +8501,7 @@ void atkA0_psywavedamageeffect(void) gBattlescriptCurrInstr++; } -void atkA1_counterdamagecalculator(void) +static void atkA1_counterdamagecalculator(void) { u8 sideAttacker = GetBankSide(gBankAttacker); u8 sideTarget = GetBankSide(gProtectStructs[gBankAttacker].physicalBank); @@ -8501,7 +8526,7 @@ void atkA1_counterdamagecalculator(void) } } -void atkA2_mirrorcoatdamagecalculator(void) // a copy of atkA1 with the physical -> special field changes +static void atkA2_mirrorcoatdamagecalculator(void) // a copy of atkA1 with the physical -> special field changes { u8 sideAttacker = GetBankSide(gBankAttacker); u8 sideTarget = GetBankSide(gProtectStructs[gBankAttacker].specialBank); @@ -8524,7 +8549,7 @@ void atkA2_mirrorcoatdamagecalculator(void) // a copy of atkA1 with the physical } } -void atkA3_disablelastusedattack(void) +static void atkA3_disablelastusedattack(void) { s32 i; @@ -8549,7 +8574,7 @@ void atkA3_disablelastusedattack(void) } } -void atkA4_setencore(void) +static void atkA4_setencore(void) { s32 i; @@ -8581,7 +8606,7 @@ void atkA4_setencore(void) } } -void atkA5_painsplitdmgcalc(void) +static void atkA5_painsplitdmgcalc(void) { if (!(gBattleMons[gBankTarget].status2 & STATUS2_SUBSTITUTE)) { @@ -8606,7 +8631,7 @@ void atkA5_painsplitdmgcalc(void) } #ifdef NONMATCHING -void atkA6_settypetorandomresistance(void) // conversion 2 +static void atkA6_settypetorandomresistance(void) // conversion 2 { if (gUnknown_02024250[gBankAttacker] == 0 || gUnknown_02024250[gBankAttacker] == 0xFFFF) @@ -8673,7 +8698,7 @@ void atkA6_settypetorandomresistance(void) // conversion 2 #else __attribute__((naked)) -void atkA6_settypetorandomresistance(void) // conversion 2 +static void atkA6_settypetorandomresistance(void) // conversion 2 { asm(".syntax unified\n\ push {r4-r7,lr}\n\ @@ -8912,7 +8937,7 @@ _08052D08:\n\ } #endif // NONMATCHING -void atkA7_setalwayshitflag(void) +static void atkA7_setalwayshitflag(void) { gStatuses3[gBankTarget] &= ~(STATUS3_ALWAYS_HITS); gStatuses3[gBankTarget] |= 0x10; @@ -8920,7 +8945,7 @@ void atkA7_setalwayshitflag(void) gBattlescriptCurrInstr++; } -void atkA8_copymovepermanently(void) // sketch +static void atkA8_copymovepermanently(void) // sketch { gLastUsedMove = 0xFFFF; @@ -8973,7 +8998,7 @@ void atkA8_copymovepermanently(void) // sketch } } -bool8 IsTwoTurnsMove(u16 move) +static bool8 IsTwoTurnsMove(u16 move) { if (gBattleMoves[move].effect == EFFECT_SKULL_BASH || gBattleMoves[move].effect == EFFECT_RAZOR_WIND @@ -8995,7 +9020,7 @@ static bool8 IsInvalidForSleepTalkOrAssist(u16 move) return FALSE; } -u8 AttacksThisTurn(u8 bank, u16 move) // Note: returns 1 if it's a charging turn, otherwise 2 +static u8 AttacksThisTurn(u8 bank, u16 move) // Note: returns 1 if it's a charging turn, otherwise 2 { // first argument is unused if (gBattleMoves[move].effect == EFFECT_SOLARBEAM @@ -9015,7 +9040,7 @@ u8 AttacksThisTurn(u8 bank, u16 move) // Note: returns 1 if it's a charging turn return 2; } -void atkA9_sleeptalk_choose_move(void) +static void atkA9_sleeptalk_choose_move(void) { s32 i; u8 unusableMovesBits = 0; @@ -9054,13 +9079,13 @@ void atkA9_sleeptalk_choose_move(void) } } -void atkAA_set_destinybond(void) +static void atkAA_set_destinybond(void) { gBattleMons[gBankAttacker].status2 |= STATUS2_DESTINY_BOND; gBattlescriptCurrInstr++; } -void DestinyBondFlagUpdate(void) +static void DestinyBondFlagUpdate(void) { u8 sideAttacker = GetBankSide(gBankAttacker); u8 sideTarget = GetBankSide(gBankTarget); @@ -9072,15 +9097,13 @@ void DestinyBondFlagUpdate(void) } } -void atkAB_DestinyBondFlagUpdate(void) +static void atkAB_DestinyBondFlagUpdate(void) { DestinyBondFlagUpdate(); gBattlescriptCurrInstr++; } -extern const u8 sFlailHpScaleToPowerTable[12]; - -void atkAC_remaininghptopower(void) +static void atkAC_remaininghptopower(void) { s32 i; s32 hpFraction = GetScaledHPFraction(gBattleMons[gBankAttacker].hp, gBattleMons[gBankAttacker].maxHP, 48); @@ -9095,7 +9118,7 @@ void atkAC_remaininghptopower(void) gBattlescriptCurrInstr++; } -void atkAD_spite_ppreduce(void) +static void atkAD_spite_ppreduce(void) { if (gLastUsedMovesByBanks[gBankTarget] != 0 && gLastUsedMovesByBanks[gBankTarget] != 0xFFFF) @@ -9146,7 +9169,7 @@ void atkAD_spite_ppreduce(void) } } -void atkAE_heal_party_status(void) +static void atkAE_heal_party_status(void) { u32 zero = 0; u8 toHeal = 0; @@ -9242,7 +9265,7 @@ void atkAE_heal_party_status(void) gBattlescriptCurrInstr++; } -void atkAF_cursetarget(void) +static void atkAF_cursetarget(void) { if (gBattleMons[gBankTarget].status2 & STATUS2_CURSED) { @@ -9259,7 +9282,7 @@ void atkAF_cursetarget(void) } } -void atkB0_set_spikes(void) +static void atkB0_set_spikes(void) { u8 targetSide = GetBankSide(gBankAttacker) ^ BIT_SIDE; @@ -9276,13 +9299,13 @@ void atkB0_set_spikes(void) } } -void atkB1_set_foresight(void) +static void atkB1_set_foresight(void) { gBattleMons[gBankTarget].status2 |= STATUS2_FORESIGHT; gBattlescriptCurrInstr++; } -void atkB2_setperishsong(void) +static void atkB2_setperishsong(void) { s32 i; s32 notAffectedCount = 0; @@ -9310,7 +9333,7 @@ void atkB2_setperishsong(void) gBattlescriptCurrInstr += 5; } -void atkB3_rolloutdamagecalculation(void) +static void atkB3_rolloutdamagecalculation(void) { if (gBattleMoveFlags & MOVESTATUS_NOEFFECT) { @@ -9345,7 +9368,7 @@ void atkB3_rolloutdamagecalculation(void) } } -void atkB4_jumpifconfusedandstatmaxed(void) +static void atkB4_jumpifconfusedandstatmaxed(void) { if (gBattleMons[gBankTarget].status2 & STATUS2_CONFUSION && gBattleMons[gBankTarget].statStages[gBattlescriptCurrInstr[1]] == 0xC) @@ -9354,7 +9377,7 @@ void atkB4_jumpifconfusedandstatmaxed(void) gBattlescriptCurrInstr += 6; } -void atkB5_furycuttercalc(void) +static void atkB5_furycuttercalc(void) { if (gBattleMoveFlags & MOVESTATUS_NOEFFECT) { @@ -9377,7 +9400,7 @@ void atkB5_furycuttercalc(void) } } -void atkB6_happinesstodamagecalculation(void) +static void atkB6_happinesstodamagecalculation(void) { if (gBattleMoves[gCurrentMove].effect == EFFECT_RETURN) gDynamicBasePower = 10 * (gBattleMons[gBankAttacker].friendship) / 25; @@ -9387,11 +9410,7 @@ void atkB6_happinesstodamagecalculation(void) gBattlescriptCurrInstr++; } -extern const u8 BattleScript_PresentDamageTarget[]; -extern const u8 BattleScript_AlreadyAtFullHp[]; -extern const u8 BattleScript_PresentHealTarget[]; - -void atkB7_presentdamagecalculation(void) +static void atkB7_presentdamagecalculation(void) { s32 rand = Random() & 0xFF; @@ -9419,7 +9438,7 @@ void atkB7_presentdamagecalculation(void) } } -void atkB8_set_safeguard(void) +static void atkB8_set_safeguard(void) { if (gSideAffecting[GET_BANK_SIDE(gBankAttacker)] & SIDE_STATUS_SAFEGUARD) { @@ -9437,7 +9456,7 @@ void atkB8_set_safeguard(void) gBattlescriptCurrInstr++; } -void atkB9_magnitudedamagecalculation(void) +static void atkB9_magnitudedamagecalculation(void) { s32 magnitude = Random() % 100; @@ -9491,7 +9510,7 @@ void atkB9_magnitudedamagecalculation(void) gBattlescriptCurrInstr++; } -void atkBA_jumpifnopursuitswitchdmg(void) +static void atkBA_jumpifnopursuitswitchdmg(void) { if (gMultiHitCounter == 1) { @@ -9535,7 +9554,7 @@ void atkBA_jumpifnopursuitswitchdmg(void) } } -void atkBB_setsunny(void) +static void atkBB_setsunny(void) { if (gBattleWeather & WEATHER_SUN_ANY) { @@ -9552,7 +9571,7 @@ void atkBB_setsunny(void) gBattlescriptCurrInstr++; } -void atkBC_maxattackhalvehp(void) // belly drum +static void atkBC_maxattackhalvehp(void) // belly drum { u32 halfHp = gBattleMons[gBankAttacker].maxHP / 2; @@ -9575,7 +9594,7 @@ void atkBC_maxattackhalvehp(void) // belly drum } } -void atkBD_copyfoestats(void) // psych up +static void atkBD_copyfoestats(void) // psych up { s32 i; @@ -9587,11 +9606,7 @@ void atkBD_copyfoestats(void) // psych up gBattlescriptCurrInstr += 5; // Has an unused jump ptr(possibly for a failed attempt) parameter. } -extern const u8 BattleScript_WrapFree[]; -extern const u8 BattleScript_LeechSeedFree[]; -extern const u8 BattleScript_SpikesFree[]; - -void atkBE_rapidspinfree(void) +static void atkBE_rapidspinfree(void) { if (gBattleMons[gBankAttacker].status2 & STATUS2_WRAPPED) { @@ -9628,13 +9643,13 @@ void atkBE_rapidspinfree(void) } } -void atkBF_set_defense_curl(void) +static void atkBF_set_defense_curl(void) { gBattleMons[gBankAttacker].status2 |= STATUS2_DEFENSE_CURL; gBattlescriptCurrInstr++; } -void atkC0_recoverbasedonsunlight(void) +static void atkC0_recoverbasedonsunlight(void) { gBankTarget = gBankAttacker; @@ -9660,7 +9675,7 @@ void atkC0_recoverbasedonsunlight(void) } #ifdef NONMATCHING -void atkC1_hidden_power(void) +static void atkC1_hidden_power(void) { s32 powerBits; s32 typeBits; @@ -9691,7 +9706,7 @@ void atkC1_hidden_power(void) #else __attribute__((naked)) -void atkC1_hidden_power(void) +static void atkC1_hidden_power(void) { asm(".syntax unified\n\ push {r4-r7,lr}\n\ @@ -9834,7 +9849,7 @@ _080544F0:\n\ } #endif // NONMATCHING -void atkC2_selectnexttarget(void) +static void atkC2_selectnexttarget(void) { for (gBankTarget = 0; gBankTarget < gNoOfAllBanks; gBankTarget++) { @@ -9846,7 +9861,7 @@ void atkC2_selectnexttarget(void) gBattlescriptCurrInstr++; } -void atkC3_setfutureattack(void) +static void atkC3_setfutureattack(void) { if (gWishFutureKnock.futureSightCounter[gBankTarget] != 0) { @@ -9874,7 +9889,7 @@ void atkC3_setfutureattack(void) } } -void atkC4_beat_up(void) +static void atkC4_beat_up(void) { struct Pokemon* party; @@ -9921,7 +9936,7 @@ void atkC4_beat_up(void) } } -void atkC5_setsemiinvulnerablebit(void) +static void atkC5_setsemiinvulnerablebit(void) { switch (gCurrentMove) { @@ -9940,7 +9955,7 @@ void atkC5_setsemiinvulnerablebit(void) gBattlescriptCurrInstr++; } -void atkC6_clearsemiinvulnerablebit(void) +static void atkC6_clearsemiinvulnerablebit(void) { switch (gCurrentMove) { @@ -9959,7 +9974,7 @@ void atkC6_clearsemiinvulnerablebit(void) gBattlescriptCurrInstr++; } -void atkC7_setminimize(void) +static void atkC7_setminimize(void) { if (gHitMarker & HITMARKER_OBEYS) gStatuses3[gBankAttacker] |= STATUS3_MINIMIZED; @@ -9967,7 +9982,7 @@ void atkC7_setminimize(void) gBattlescriptCurrInstr++; } -void atkC8_sethail(void) +static void atkC8_sethail(void) { if (gBattleWeather & WEATHER_HAIL_ANY) { @@ -9984,7 +9999,7 @@ void atkC8_sethail(void) gBattlescriptCurrInstr++; } -void atkC9_jumpifattackandspecialattackcannotfall(void) // memento +static void atkC9_jumpifattackandspecialattackcannotfall(void) // memento { if (gBattleMons[gBankTarget].statStages[STAT_STAGE_ATK] == 0 && gBattleMons[gBankTarget].statStages[STAT_STAGE_SPATK] == 0 @@ -10002,14 +10017,14 @@ void atkC9_jumpifattackandspecialattackcannotfall(void) // memento } } -void atkCA_setforcedtarget(void) // follow me +static void atkCA_setforcedtarget(void) // follow me { gSideTimers[GetBankSide(gBankAttacker)].followmeTimer = 1; gSideTimers[GetBankSide(gBankAttacker)].followmeTarget = gBankAttacker; gBattlescriptCurrInstr++; } -void atkCB_setcharge(void) +static void atkCB_setcharge(void) { gStatuses3[gBankAttacker] |= STATUS3_CHARGED_UP; gDisableStructs[gBankAttacker].chargeTimer1 = 2; @@ -10017,7 +10032,7 @@ void atkCB_setcharge(void) gBattlescriptCurrInstr++; } -void atkCC_callterrainattack(void) // nature power +static void atkCC_callterrainattack(void) // nature power { gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); gCurrentMove = sNaturePowerMoves[gBattleTerrain]; @@ -10026,7 +10041,7 @@ void atkCC_callterrainattack(void) // nature power gBattlescriptCurrInstr++; } -void atkCD_cureifburnedparalysedorpoisoned(void) // refresh +static void atkCD_cureifburnedparalysedorpoisoned(void) // refresh { if (gBattleMons[gBankAttacker].status1 & (STATUS_POISON | STATUS_BURN | STATUS_PARALYSIS | STATUS_TOXIC_POISON)) { @@ -10042,7 +10057,7 @@ void atkCD_cureifburnedparalysedorpoisoned(void) // refresh } } -void atkCE_settorment(void) +static void atkCE_settorment(void) { if (gBattleMons[gBankTarget].status2 & STATUS2_TORMENT) { @@ -10055,7 +10070,7 @@ void atkCE_settorment(void) } } -void atkCF_jumpifnodamage(void) +static void atkCF_jumpifnodamage(void) { if (gProtectStructs[gBankAttacker].physicalDmg || gProtectStructs[gBankAttacker].specialDmg) gBattlescriptCurrInstr += 5; @@ -10063,7 +10078,7 @@ void atkCF_jumpifnodamage(void) gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); } -void atkD0_settaunt(void) +static void atkD0_settaunt(void) { if (gDisableStructs[gBankTarget].tauntTimer1 == 0) { @@ -10077,7 +10092,7 @@ void atkD0_settaunt(void) } } -void atkD1_set_helpinghand(void) +static void atkD1_set_helpinghand(void) { gBankTarget = GetBankByIdentity(GetBankIdentity(gBankAttacker) ^ BIT_MON); @@ -10095,7 +10110,7 @@ void atkD1_set_helpinghand(void) } } -void atkD2_swap_items(void) // trick +static void atkD2_swap_items(void) // trick { // opponent can't swap items with player in regular battles if (gBattleTypeFlags & BATTLE_TYPE_x4000000 @@ -10182,7 +10197,7 @@ void atkD2_swap_items(void) // trick } } -void atkD3_copy_ability(void) // role play +static void atkD3_copy_ability(void) // role play { if (gBattleMons[gBankTarget].ability != 0 && gBattleMons[gBankTarget].ability != ABILITY_WONDER_GUARD) @@ -10197,9 +10212,9 @@ void atkD3_copy_ability(void) // role play } } -void atkD4_wish_effect(void) +static void atkD4_wish_effect(void) { - switch (BSScriptRead8(gBattlescriptCurrInstr + 1)) + switch (gBattlescriptCurrInstr[1]) { case 0: // use wish if (gWishFutureKnock.wishCounter[gBankAttacker] == 0) @@ -10230,7 +10245,7 @@ void atkD4_wish_effect(void) } } -void atkD5_setroots(void) // ingrain +static void atkD5_setroots(void) // ingrain { if (gStatuses3[gBankAttacker] & STATUS3_ROOTED) { @@ -10243,7 +10258,7 @@ void atkD5_setroots(void) // ingrain } } -void atkD6_doubledamagedealtifdamaged(void) +static void atkD6_doubledamagedealtifdamaged(void) { if ((gProtectStructs[gBankAttacker].physicalDmg && gProtectStructs[gBankAttacker].physicalBank == gBankTarget) @@ -10256,7 +10271,7 @@ void atkD6_doubledamagedealtifdamaged(void) gBattlescriptCurrInstr++; } -void atkD7_setyawn(void) +static void atkD7_setyawn(void) { if (gStatuses3[gBankTarget] & STATUS3_YAWN || gBattleMons[gBankTarget].status1 & STATUS_ANY) @@ -10270,7 +10285,7 @@ void atkD7_setyawn(void) } } -void atkD8_setdamagetohealthdifference(void) +static void atkD8_setdamagetohealthdifference(void) { if (gBattleMons[gBankTarget].hp <= gBattleMons[gBankAttacker].hp) { @@ -10283,7 +10298,7 @@ void atkD8_setdamagetohealthdifference(void) } } -void atkD9_scaledamagebyhealthratio(void) +static void atkD9_scaledamagebyhealthratio(void) { if (gDynamicBasePower == 0) { @@ -10295,7 +10310,7 @@ void atkD9_scaledamagebyhealthratio(void) gBattlescriptCurrInstr++; } -void atkDA_abilityswap(void) // skill swap +static void atkDA_abilityswap(void) // skill swap { if ((gBattleMons[gBankAttacker].ability == 0 && gBattleMons[gBankTarget].ability == 0) @@ -10315,7 +10330,7 @@ void atkDA_abilityswap(void) // skill swap } } -void atkDB_imprisoneffect(void) +static void atkDB_imprisoneffect(void) { if ((gStatuses3[gBankAttacker] & STATUS3_IMPRISONED_OTHERS)) { @@ -10357,7 +10372,7 @@ void atkDB_imprisoneffect(void) } } -void atkDC_setgrudge(void) +static void atkDC_setgrudge(void) { if (gStatuses3[gBankAttacker] & STATUS3_GRUDGE) { @@ -10370,7 +10385,7 @@ void atkDC_setgrudge(void) } } -void atkDD_weightdamagecalculation(void) +static void atkDD_weightdamagecalculation(void) { s32 i; for (i = 0; sWeightToDamageTable[i] != 0xFFFF; i += 2) @@ -10387,7 +10402,7 @@ void atkDD_weightdamagecalculation(void) gBattlescriptCurrInstr++; } -void atkDE_asistattackselect(void) +static void atkDE_asistattackselect(void) { s32 chooseableMovesNo = 0; struct Pokemon* party; @@ -10440,7 +10455,7 @@ void atkDE_asistattackselect(void) } } -void atkDF_setmagiccoat(void) +static void atkDF_setmagiccoat(void) { gBankTarget = gBankAttacker; gSpecialStatuses[gBankAttacker].flag20 = 1; @@ -10455,7 +10470,7 @@ void atkDF_setmagiccoat(void) } } -void atkE0_setstealstatchange(void) // snatch +static void atkE0_setstealstatchange(void) // snatch { gSpecialStatuses[gBankAttacker].flag20 = 1; if (gCurrentMoveTurn == gNoOfAllBanks - 1) // moves last turn @@ -10469,7 +10484,7 @@ void atkE0_setstealstatchange(void) // snatch } } -void atkE1_intimidate_string_loader(void) +static void atkE1_intimidate_string_loader(void) { u8 side; @@ -10492,9 +10507,9 @@ void atkE1_intimidate_string_loader(void) gBattlescriptCurrInstr += 5; } -void atkE2_switchout_abilities(void) +static void atkE2_switchout_abilities(void) { - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); switch (gBattleMons[gActiveBank].ability) { @@ -10508,9 +10523,9 @@ void atkE2_switchout_abilities(void) gBattlescriptCurrInstr += 2; } -void atkE3_jumpifhasnohp(void) +static void atkE3_jumpifhasnohp(void) { - gActiveBank = GetBattleBank(BSScriptRead8(gBattlescriptCurrInstr + 1)); + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); if (gBattleMons[gActiveBank].hp == 0) gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); @@ -10518,7 +10533,7 @@ void atkE3_jumpifhasnohp(void) gBattlescriptCurrInstr += 6; } -void atkE4_getsecretpowereffect(void) +static void atkE4_getsecretpowereffect(void) { switch (gBattleTerrain) { @@ -10553,15 +10568,7 @@ void atkE4_getsecretpowereffect(void) gBattlescriptCurrInstr++; } -extern bool8 InBattlePike(void); -extern bool8 InBattlePyramid(void); -extern u16 GetBattlePyramidPickupItemId(void); - -extern const u16 gRarePickupItems[]; -extern const u16 gPickupItems[]; -extern const u8 gPickupProbabilities[]; - -void atkE5_pickup(void) +static void atkE5_pickup(void) { if (!InBattlePike()) { @@ -10636,3 +10643,600 @@ void atkE5_pickup(void) gBattlescriptCurrInstr++; } + +static void atkE6_castform_change_animation(void) +{ + gActiveBank = gBattleScripting.bank; + + if (gBattleMons[gActiveBank].status2 & STATUS2_SUBSTITUTE) + *(&gBattleStruct->formToChangeInto) |= 0x80; + + EmitBattleAnimation(0, B_ANIM_CASTFORM_CHANGE, gBattleStruct->formToChangeInto); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr++; +} + +static void atkE7_castform_data_change(void) +{ + u8 form; + + gBattlescriptCurrInstr++; + form = CastformDataTypeChange(gBattleScripting.bank); + if (form) + { + BattleScriptPushCursorAndCallback(BattleScript_CastformChange); + *(&gBattleStruct->formToChangeInto) = form - 1; + } +} + +static void atkE8_settypebasedhalvers(void) // water and mud sport +{ + bool8 worked = FALSE; + + if (gBattleMoves[gCurrentMove].effect == EFFECT_MUD_SPORT) + { + if (!(gStatuses3[gBankAttacker] & STATUS3_MUDSPORT)) + { + gStatuses3[gBankAttacker] |= STATUS3_MUDSPORT; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + worked = TRUE; + } + } + else // water sport + { + if (!(gStatuses3[gBankAttacker] & STATUS3_WATERSPORT)) + { + gStatuses3[gBankAttacker] |= STATUS3_WATERSPORT; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + worked = TRUE; + } + } + + if (worked) + gBattlescriptCurrInstr += 5; + else + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); +} + +static void atkE9_setweatherballtype(void) +{ + if (WEATHER_HAS_EFFECT) + { + if (gBattleWeather & WEATHER_ANY) + gBattleScripting.dmgMultiplier = 2; + if (gBattleWeather & WEATHER_RAIN_ANY) + *(&gBattleStruct->dynamicMoveType) = TYPE_WATER | 0x80; + else if (gBattleWeather & WEATHER_SANDSTORM_ANY) + *(&gBattleStruct->dynamicMoveType) = TYPE_ROCK | 0x80; + else if (gBattleWeather & WEATHER_SUN_ANY) + *(&gBattleStruct->dynamicMoveType) = TYPE_FIRE | 0x80; + else if (gBattleWeather & WEATHER_HAIL_ANY) + *(&gBattleStruct->dynamicMoveType) = TYPE_ICE | 0x80; + else + *(&gBattleStruct->dynamicMoveType) = TYPE_NORMAL | 0x80; + } + + gBattlescriptCurrInstr++; +} + +static void atkEA_recycleitem(void) +{ + u16 *usedHeldItem; + + gActiveBank = gBankAttacker; + usedHeldItem = &gBattleStruct->usedHeldItems[gActiveBank]; + if (*usedHeldItem != 0 && gBattleMons[gActiveBank].item == 0) + { + gLastUsedItem = *usedHeldItem; + *usedHeldItem = 0; + gBattleMons[gActiveBank].item = gLastUsedItem; + + EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gActiveBank].item); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkEB_settypetoterrain(void) +{ + if (gBattleMons[gBankAttacker].type1 != sTerrainToType[gBattleTerrain] + && gBattleMons[gBankAttacker].type2 != sTerrainToType[gBattleTerrain]) + { + gBattleMons[gBankAttacker].type1 = sTerrainToType[gBattleTerrain]; + gBattleMons[gBankAttacker].type2 = sTerrainToType[gBattleTerrain]; + + PREPARE_TYPE_BUFFER(gBattleTextBuff1, sTerrainToType[gBattleTerrain]) + + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkEC_pursuit_sth(void) +{ + gActiveBank = GetBankByIdentity(GetBankIdentity(gBankAttacker) ^ BIT_MON); + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && !(gAbsentBankFlags & gBitTable[gActiveBank]) + && gActionForBanks[gActiveBank] == 0 + && gChosenMovesByBanks[gActiveBank] == MOVE_PURSUIT) + { + gUnknown_0202407A[gActiveBank] = 11; + gCurrentMove = MOVE_PURSUIT; + gBattlescriptCurrInstr += 5; + gBattleScripting.animTurn = 1; + gBattleScripting.field_20 = gBankAttacker; + gBankAttacker = gActiveBank; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkED_802B4B4(void) +{ + gEffectBank = gBankAttacker; + + if (gBankAttacker == gBankTarget) + gBankAttacker = gBankTarget = gBattleScripting.bank; + else + gBankTarget = gBattleScripting.bank; + + gBattleScripting.bank = gEffectBank; + gBattlescriptCurrInstr++; +} + +static void atkEE_removelightscreenreflect(void) // brick break +{ + u8 opposingSide = GetBankSide(gBankAttacker) ^ BIT_SIDE; + + if (gSideTimers[opposingSide].reflectTimer || gSideTimers[opposingSide].lightscreenTimer) + { + gSideAffecting[opposingSide] &= ~(SIDE_STATUS_REFLECT); + gSideAffecting[opposingSide] &= ~(SIDE_STATUS_LIGHTSCREEN); + gSideTimers[opposingSide].reflectTimer = 0; + gSideTimers[opposingSide].lightscreenTimer = 0; + gBattleScripting.animTurn = 1; + gBattleScripting.animTargetsHit = 1; + } + else + { + gBattleScripting.animTurn = 0; + gBattleScripting.animTargetsHit = 0; + } + + gBattlescriptCurrInstr++; +} + +static void atkEF_pokeball_catch_calculation(void) +{ + u8 ballMultiplier = 0; + + if (gBattleExecBuffer) + return; + + gActiveBank = gBankAttacker; + gBankTarget = gBankAttacker ^ BIT_SIDE; + + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + { + EmitBallThrow(0, BALL_TRAINER_BLOCK); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr = BattleScript_TrainerBallBlock; + } + else if (gBattleTypeFlags & BATTLE_TYPE_WALLY_TUTORIAL) + { + EmitBallThrow(0, BALL_3_SHAKES_SUCCESS); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr = BattleScript_WallyBallThrow; + } + else + { + u32 odds; + u8 catchRate; + + if (gLastUsedItem == ITEM_SAFARI_BALL) + catchRate = gBattleStruct->field_7C * 1275 / 100; + else + catchRate = gBaseStats[gBattleMons[gBankTarget].species].catchRate; + + if (gLastUsedItem > ITEM_SAFARI_BALL) + { + switch (gLastUsedItem) + { + case ITEM_NET_BALL: + if (gBattleMons[gBankTarget].type1 == TYPE_WATER + || gBattleMons[gBankTarget].type2 == TYPE_WATER + || gBattleMons[gBankTarget].type1 == TYPE_BUG + || gBattleMons[gBankTarget].type2 == TYPE_BUG) + ballMultiplier = 30; + else + ballMultiplier = 10; + break; + case ITEM_DIVE_BALL: + if (sav1_map_get_light_level() == 5) + ballMultiplier = 35; + else + ballMultiplier = 10; + break; + case ITEM_NEST_BALL: + if (gBattleMons[gBankTarget].level <= 39) + { + ballMultiplier = 40 - gBattleMons[gBankTarget].level; + if (ballMultiplier <= 9) + ballMultiplier = 10; + } + else + { + ballMultiplier = 10; + } + break; + case ITEM_REPEAT_BALL: + if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gBankTarget].species), FLAG_GET_CAUGHT)) + ballMultiplier = 30; + else + ballMultiplier = 10; + break; + case ITEM_TIMER_BALL: + ballMultiplier = gBattleResults.battleTurnCounter + 10; + if (ballMultiplier > 40) + ballMultiplier = 40; + break; + case ITEM_LUXURY_BALL: + case ITEM_PREMIER_BALL: + ballMultiplier = 10; + break; + } + } + else + ballMultiplier = sBallCatchBonuses[gLastUsedItem - 2]; + + odds = (catchRate * ballMultiplier / 10) + * (gBattleMons[gBankTarget].maxHP * 3 - gBattleMons[gBankTarget].hp * 2) + / (3 * gBattleMons[gBankTarget].maxHP); + + if (gBattleMons[gBankTarget].status1 & (STATUS_SLEEP | STATUS_FREEZE)) + odds *= 2; + if (gBattleMons[gBankTarget].status1 & (STATUS_POISON | STATUS_BURN | STATUS_PARALYSIS | STATUS_TOXIC_POISON)) + odds = (odds * 15) / 10; + + if (gLastUsedItem != ITEM_SAFARI_BALL) + { + if (gLastUsedItem == ITEM_MASTER_BALL) + { + gBattleResults.unk5_1 = 1; + } + else + { + if (gBattleResults.catchAttempts[gLastUsedItem - ITEM_ULTRA_BALL] < 0xFF) + gBattleResults.catchAttempts[gLastUsedItem - ITEM_ULTRA_BALL]++; + } + } + + if (odds > 254) // mon caught + { + EmitBallThrow(0, BALL_3_SHAKES_SUCCESS); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr = BattleScript_SuccessBallThrow; + SetMonData(&gEnemyParty[gBattlePartyID[gBankTarget]], MON_DATA_POKEBALL, &gLastUsedItem); + + if (CalculatePlayerPartyCount() == 6) + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + else // mon may be caught, calculate shakes + { + u8 shakes; + + odds = Sqrt(Sqrt(16711680 / odds)); + odds = 1048560 / odds; + + for (shakes = 0; shakes < 4 && Random() < odds; shakes++); + + if (gLastUsedItem == ITEM_MASTER_BALL) + shakes = BALL_3_SHAKES_SUCCESS; // why calculate the shakes before that check? + + EmitBallThrow(0, shakes); + MarkBufferBankForExecution(gActiveBank); + + if (shakes == BALL_3_SHAKES_SUCCESS) // mon caught, copy of the code above + { + gBattlescriptCurrInstr = BattleScript_SuccessBallThrow; + SetMonData(&gEnemyParty[gBattlePartyID[gBankTarget]], MON_DATA_POKEBALL, &gLastUsedItem); + + if (CalculatePlayerPartyCount() == 6) + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + else // not caught + { + gBattleCommunication[MULTISTRING_CHOOSER] = shakes; + gBattlescriptCurrInstr = BattleScript_ShakeBallThrow; + } + } + } +} + +static void atkF0_give_caught_mon(void) +{ + if (GiveMonToPlayer(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]]) != MON_GIVEN_TO_PARTY) + { + if (!sub_813B21C()) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + StringCopy(gStringVar1, GetBoxNamePtr(VarGet(VAR_STORAGE_UNKNOWN))); + GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_NICKNAME, gStringVar2); + } + else + { + StringCopy(gStringVar1, GetBoxNamePtr(VarGet(VAR_STORAGE_UNKNOWN))); + GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_NICKNAME, gStringVar2); + StringCopy(gStringVar3, GetBoxNamePtr(get_unknown_box_id())); + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + } + + if (FlagGet(SYS_PC_LANETTE)) + gBattleCommunication[MULTISTRING_CHOOSER]++; + } + + gBattleResults.caughtMonSpecies = GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_SPECIES, NULL); + GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_NICKNAME, gBattleResults.caughtMonNick); + gBattleResults.caughtMonBall = GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_POKEBALL, NULL); + + gBattlescriptCurrInstr++; +} + +static void atkF1_set_caught_mon_dex_flags(void) +{ + u16 species = GetMonData(&gEnemyParty[0], MON_DATA_SPECIES, NULL); + u32 personality = GetMonData(&gEnemyParty[0], MON_DATA_PERSONALITY, NULL); + + if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_GET_CAUGHT)) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + HandleSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_SET_CAUGHT, personality); + gBattlescriptCurrInstr += 5; + } +} + +static void atkF2_display_dex_info(void) +{ + u16 species = GetMonData(&gEnemyParty[0], MON_DATA_SPECIES, NULL); + + switch (gBattleCommunication[0]) + { + case 0: + BeginNormalPaletteFade(-1, 0, 0, 0x10, 0); + gBattleCommunication[0]++; + break; + case 1: + if (!gPaletteFade.active) + { + FreeAllWindowBuffers(); + gBattleCommunication[TASK_ID] = CreateDexDisplayMonDataTask(SpeciesToNationalPokedexNum(species), + gBattleMons[gBankTarget].otId, + gBattleMons[gBankTarget].personality); + gBattleCommunication[0]++; + } + break; + case 2: + if (!gPaletteFade.active + && gMain.callback2 == BattleMainCB2 + && !gTasks[gBattleCommunication[TASK_ID]].isActive) + { + SetVBlankCallback(VBlankCB_Battle); + gBattleCommunication[0]++; + } + break; + case 3: + c2_berry_program_update_menu(); + sub_8035AA4(); + gBattle_BG3_X = 0x100; + gBattleCommunication[0]++; + break; + case 4: + if (!IsDma3ManagerBusyWithBgCopy()) + { + BeginNormalPaletteFade(0xFFFF, 0, 0x10, 0, 0); + ShowBg(0); + ShowBg(3); + gBattleCommunication[0]++; + } + break; + case 5: + if (!gPaletteFade.active) + gBattlescriptCurrInstr++; + break; + } +} + +void sub_8056A3C(u8 xStart, u8 yStart, u8 xEnd, u8 yEnd, u8 flags) +{ + s32 destY, destX; + u16 var = 0; + + for (destY = yStart; destY <= yEnd; destY++) + { + for (destX = xStart; destX <= xEnd; destX++) + { + if (destY == yStart) + { + if (destX == xStart) + var = 0x1022; + else if (destX == xEnd) + var = 0x1024; + else + var = 0x1023; + } + else if (destY == yEnd) + { + if (destX == xStart) + var = 0x1028; + else if (destX == xEnd) + var = 0x102A; + else + var = 0x1029; + } + else + { + if (destX == xStart) + var = 0x1025; + else if (destX == xEnd) + var = 0x1027; + else + var = 0x1026; + } + + if (flags & 1) + var = 0; + + if (flags & 0x80) + CopyToBgTilemapBufferRect_ChangePalette(1, &var, destX, destY, 1, 1, 0x11); + else + CopyToBgTilemapBufferRect_ChangePalette(0, &var, destX, destY, 1, 1, 0x11); + } + } +} + +void BattleCreateCursorAt(u8 cursorPosition) +{ + u16 src[2]; + src[0] = 1; + src[1] = 2; + + CopyToBgTilemapBufferRect_ChangePalette(0, src, 0x19, 9 + (2 * cursorPosition), 1, 2, 0x11); + CopyBgTilemapBufferToVram(0); +} + +void BattleDestroyCursorAt(u8 cursorPosition) +{ + u16 src[2]; + src[0] = 0x1016; + src[1] = 0x1016; + + CopyToBgTilemapBufferRect_ChangePalette(0, src, 0x19, 9 + (2 * cursorPosition), 1, 2, 0x11); + CopyBgTilemapBufferToVram(0); +} + +static void atkF3_nickname_caught_poke(void) +{ + switch (gBattleCommunication[MULTIUSE_STATE]) + { + case 0: + sub_8056A3C(0x18, 8, 0x1D, 0xD, 0); + sub_814F9EC(gText_BattleYesNoChoice, 0xC); + gBattleCommunication[MULTIUSE_STATE]++; + gBattleCommunication[CURSOR_POSITION] = 0; + BattleCreateCursorAt(0); + break; + case 1: + if (gMain.newKeys & DPAD_UP && gBattleCommunication[CURSOR_POSITION] != 0) + { + PlaySE(SE_SELECT); + BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); + gBattleCommunication[CURSOR_POSITION] = 0; + BattleCreateCursorAt(0); + } + if (gMain.newKeys & DPAD_DOWN && gBattleCommunication[CURSOR_POSITION] == 0) + { + PlaySE(SE_SELECT); + BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); + gBattleCommunication[CURSOR_POSITION] = 1; + BattleCreateCursorAt(1); + } + if (gMain.newKeys & A_BUTTON) + { + PlaySE(SE_SELECT); + if (gBattleCommunication[CURSOR_POSITION] == 0) + { + gBattleCommunication[MULTIUSE_STATE]++; + BeginFastPaletteFade(3); + } + else + { + gBattleCommunication[MULTIUSE_STATE] = 4; + } + } + else if (gMain.newKeys & B_BUTTON) + { + PlaySE(SE_SELECT); + gBattleCommunication[MULTIUSE_STATE] = 4; + } + break; + case 2: + if (!gPaletteFade.active) + { + GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_NICKNAME, gBattleStruct->caughtMonNick); + FreeAllWindowBuffers(); + + DoNamingScreen(NAMING_SCREEN_CAUGHT_MON, gBattleStruct->caughtMonNick, + GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_SPECIES), + GetMonGender(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]]), + GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_PERSONALITY, NULL), + BattleMainCB2); + + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 3: + if (gMain.callback2 == BattleMainCB2 && !gPaletteFade.active ) + { + SetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_NICKNAME, gBattleStruct->caughtMonNick); + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + break; + case 4: + if (CalculatePlayerPartyCount() == 6) + gBattlescriptCurrInstr += 5; + else + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + break; + } +} + +static void atkF4_subattackerhpbydmg(void) +{ + gBattleMons[gBankAttacker].hp -= gBattleMoveDamage; + gBattlescriptCurrInstr++; +} + +static void atkF5_removeattackerstatus1(void) +{ + gBattleMons[gBankAttacker].status1 = 0; + gBattlescriptCurrInstr++; +} + +static void atkF6_802BF48(void) +{ + gFightStateTracker = 0xC; +} + +static void atkF7_802BF54(void) +{ + gFightStateTracker = 0xC; + gCurrentMoveTurn = gNoOfAllBanks; +} + +static void atkF8_trainer_slide_back(void) +{ + gActiveBank = GetBankByIdentity(gBattlescriptCurrInstr[1]); + EmitTrainerSlideBack(0); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 2; +} -- cgit v1.2.3 From 7273b8f26277e3f9a1b562454e2e7f88e5523731 Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Thu, 28 Sep 2017 16:51:24 +0200 Subject: battle 4 is all done --- src/battle_4.c | 120 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 72 insertions(+), 48 deletions(-) (limited to 'src') diff --git a/src/battle_4.c b/src/battle_4.c index 414025695..e82f78570 100644 --- a/src/battle_4.c +++ b/src/battle_4.c @@ -773,7 +773,7 @@ struct StatFractions u8 divisor; }; -const struct StatFractions gAccuracyStageRatios[] = +static const struct StatFractions sAccuracyStageRatios[] = { { 33, 100}, // -6 { 36, 100}, // -5 @@ -791,9 +791,9 @@ const struct StatFractions gAccuracyStageRatios[] = }; // The chance is 1/N for each stage. -const u16 gCriticalHitChance[] = {16, 8, 4, 3, 2}; +static const u16 sCriticalHitChance[] = {16, 8, 4, 3, 2}; -const u32 gStatusFlagsForMoveEffects[] = +static const u32 sStatusFlagsForMoveEffects[] = { 0x00000000, STATUS_SLEEP, @@ -857,7 +857,7 @@ const u32 gStatusFlagsForMoveEffects[] = 0x00000000 }; -const u8* const gMoveEffectBS_Ptrs[] = +static const u8* const sMoveEffectBS_Ptrs[] = { BattleScript_MoveEffectSleep, // 0 BattleScript_MoveEffectSleep, // MOVE_EFFECT_SLEEP @@ -902,8 +902,8 @@ const u8* const gMoveEffectBS_Ptrs[] = static const struct WindowTemplate sUnusedWinTemplate = {0, 1, 3, 7, 0xF, 0x1F, 0x3F}; -const u16 gUnknown_0831C2C8[] = INCBIN_U16("graphics/battle_interface/unk_battlebox.gbapal"); -const u8 gUnknown_0831C2E8[] = INCBIN_U8("graphics/battle_interface/unk_battlebox.4bpp.lz"); +static const u16 sUnknown_0831C2C8[] = INCBIN_U16("graphics/battle_interface/unk_battlebox.gbapal"); +static const u8 sUnknown_0831C2E8[] = INCBIN_U8("graphics/battle_interface/unk_battlebox.4bpp.lz"); // unused static const u8 sRubyLevelUpStatBoxStats[] = @@ -914,7 +914,7 @@ static const u8 sRubyLevelUpStatBoxStats[] = #define MON_ICON_LVLUP_BOX_TAG 0xD75A -const struct OamData gUnknown_0831C3B8 = +static const struct OamData sOamData_MonIconOnLvlUpBox = { .y = 0, .affineMode = 0, @@ -931,24 +931,24 @@ const struct OamData gUnknown_0831C3B8 = .affineParam = 0, }; -const struct SpriteTemplate SpriteTemplate_MonIconOnLvlUpBox = +static const struct SpriteTemplate sSpriteTemplate_MonIconOnLvlUpBox = { .tileTag = MON_ICON_LVLUP_BOX_TAG, .paletteTag = MON_ICON_LVLUP_BOX_TAG, - .oam = &gUnknown_0831C3B8, + .oam = &sOamData_MonIconOnLvlUpBox, .anims = gDummySpriteAnimTable, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCB_MonIconOnLvlUpBox }; -const u16 sProtectSuccessRates[] = {0xFFFF, 0x7FFF, 0x3FFF, 0x1FFF}; +static const u16 sProtectSuccessRates[] = {USHRT_MAX, USHRT_MAX / 2, USHRT_MAX / 4, USHRT_MAX / 8}; #define MIMIC_FORBIDDEN_END 0xFFFE #define METRONOME_FORBIDDEN_END 0xFFFF #define ASSIST_FORBIDDEN_END 0xFFFF -static const u16 gMovesForbiddenToCopy[] = +static const u16 sMovesForbiddenToCopy[] = { MOVE_METRONOME, MOVE_STRUGGLE, @@ -1007,7 +1007,7 @@ static const u16 sWeightToDamageTable[] = 0xFFFF, 0xFFFF }; -static const u16 gPickupItems[] = +static const u16 sPickupItems[] = { ITEM_POTION, ITEM_ANTIDOTE, @@ -1029,7 +1029,7 @@ static const u16 gPickupItems[] = ITEM_MAX_ELIXIR, }; -static const u16 gRarePickupItems[] = +static const u16 sRarePickupItems[] = { ITEM_HYPER_POTION, ITEM_NUGGET, @@ -1044,7 +1044,7 @@ static const u16 gRarePickupItems[] = ITEM_TM26, }; -static const u8 gPickupProbabilities[] = +static const u8 sPickupProbabilities[] = { 30, 40, 50, 60, 70, 80, 90, 94, 98 }; @@ -1057,8 +1057,8 @@ static const u8 sTerrainToType[] = TYPE_WATER, // underwater TYPE_WATER, // water TYPE_WATER, // pond water - TYPE_ROCK , // rock - TYPE_ROCK , // cave + TYPE_ROCK, // rock + TYPE_ROCK, // cave TYPE_NORMAL, // building TYPE_NORMAL, // plain }; @@ -1068,7 +1068,31 @@ static const u8 sBallCatchBonuses[] = 20, 15, 10, 15 // Ultra, Great, Poke, Safari }; -extern const u8 gUnknown_0831C4F8[]; +// could be a 2d array or a struct +const ALIGNED(4) u8 gUnknown_0831C494[] = +{ + 0x3d, 0x44, 0x3d, 0x44, 0x14, 0x2d, 0x54, 0x5c, + 0x46, 0x55, 0x20, 0x5c, 0x26, 0x45, 0x46, 0x55, + 0x14, 0x5a, 0x46, 0x5c, 0x1e, 0x32, 0x20, 0x5a, + 0x38, 0x4e, 0x38, 0x4e, 0x19, 0x28, 0x4b, 0x5a, + 0x45, 0x4b, 0x1c, 0x53, 0x23, 0x2d, 0x1d, 0x23, + 0x3e, 0x48, 0x1e, 0x32, 0x3a, 0x5f, 0x58, 0x5e, + 0x22, 0x2d, 0x1d, 0x28, 0x23, 0x28, 0x23, 0x5f, + 0x38, 0x4e, 0x38, 0x4e, 0x23, 0x50, 0x22, 0x5e, + 0x2c, 0x5e, 0x22, 0x28, 0x38, 0x4e, 0x38, 0x4e, + 0x1e, 0x58, 0x1e, 0x58, 0x1e, 0x2b, 0x1b, 0x21, + 0x28, 0x5a, 0x19, 0x57, 0x12, 0x58, 0x5a, 0x5f, + 0x58, 0x5e, 0x16, 0x2a, 0x2a, 0x5c, 0x2a, 0x2f, + 0x38, 0x4e, 0x38, 0x4e +}; + +static const u8 sUnknown_0831C4F8[] = +{ + 0x03, 0x00, 0x01, 0x00, 0x00, 0x01, 0x03, 0x00, + 0x01, 0x02, 0x02, 0x00, 0x03, 0x01, 0x03, 0x01, + 0x02, 0x03, 0x03, 0x02, 0x01, 0x00, 0x02, 0x02, + 0x03, 0x00, 0x00, 0x00 +}; static void atk00_attackcanceler(void) { @@ -1304,8 +1328,8 @@ static void atk01_accuracycheck(void) if (WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_SUN_ANY && gBattleMoves[move].effect == EFFECT_THUNDER) moveAcc = 50; - calc = gAccuracyStageRatios[buff].dividend * moveAcc; - calc /= gAccuracyStageRatios[buff].divisor; + calc = sAccuracyStageRatios[buff].dividend * moveAcc; + calc /= sAccuracyStageRatios[buff].divisor; if (gBattleMons[gBankAttacker].ability == ABILITY_COMPOUND_EYES) calc = (calc * 130) / 100; // 1.3 compound eyes boost @@ -1435,7 +1459,7 @@ static void atk04_critcalc(void) if ((gBattleMons[gBankTarget].ability != ABILITY_BATTLE_ARMOR && gBattleMons[gBankTarget].ability != ABILITY_SHELL_ARMOR) && !(gStatuses3[gBankAttacker] & STATUS3_CANT_SCORE_A_CRIT) && !(gBattleTypeFlags & (BATTLE_TYPE_WALLY_TUTORIAL | BATTLE_TYPE_FIRST_BATTLE)) - && !(Random() % gCriticalHitChance[critChance])) + && !(Random() % sCriticalHitChance[critChance])) gCritMultiplier = 2; else gCritMultiplier = 1; @@ -2411,7 +2435,7 @@ void SetMoveEffect(bool8 primary, u8 certain) if (gBattleCommunication[MOVE_EFFECT_BYTE] <= 6) // status change { - switch (gStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]) + switch (sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]) { case STATUS_SLEEP: // check active uproar @@ -2630,12 +2654,12 @@ void SetMoveEffect(bool8 primary, u8 certain) { BattleScriptPush(gBattlescriptCurrInstr + 1); - if (gStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]] == STATUS_SLEEP) + if (sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]] == STATUS_SLEEP) gBattleMons[gEffectBank].status1 |= ((Random() & 3) + 2); else - gBattleMons[gEffectBank].status1 |= gStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]; + gBattleMons[gEffectBank].status1 |= sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]; - gBattlescriptCurrInstr = gMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; + gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; gActiveBank = gEffectBank; EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gEffectBank].status1); @@ -2674,7 +2698,7 @@ void SetMoveEffect(bool8 primary, u8 certain) } else { - if (gBattleMons[gEffectBank].status2 & gStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]) + if (gBattleMons[gEffectBank].status2 & sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]) { gBattlescriptCurrInstr++; } @@ -2694,7 +2718,7 @@ void SetMoveEffect(bool8 primary, u8 certain) gBattleMons[gEffectBank].status2 |= (((Random()) % 0x4)) + 2; BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = gMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; + gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; } break; case MOVE_EFFECT_FLINCH: @@ -2714,7 +2738,7 @@ void SetMoveEffect(bool8 primary, u8 certain) else { if (BankGetTurnOrder(gEffectBank) > gCurrentMoveTurn) - gBattleMons[gEffectBank].status2 |= gStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]; + gBattleMons[gEffectBank].status2 |= sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]; gBattlescriptCurrInstr++; } break; @@ -2727,7 +2751,7 @@ void SetMoveEffect(bool8 primary, u8 certain) gBattleMons[gEffectBank].status2 |= ((Random() & 3) + 2) << 4; BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = gMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; + gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; } else { @@ -2743,7 +2767,7 @@ void SetMoveEffect(bool8 primary, u8 certain) gPaydayMoney = 0xFFFF; } BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = gMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; + gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; break; case MOVE_EFFECT_TRI_ATTACK: if (gBattleMons[gEffectBank].status1) @@ -2776,7 +2800,7 @@ void SetMoveEffect(bool8 primary, u8 certain) *(gBattleStruct->wrappedBy + gEffectBank) = gBankAttacker; BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = gMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; + gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; for (gBattleCommunication[MULTISTRING_CHOOSER] = 0; ; gBattleCommunication[MULTISTRING_CHOOSER]++) { @@ -2793,7 +2817,7 @@ void SetMoveEffect(bool8 primary, u8 certain) gBattleMoveDamage = 1; BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = gMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; + gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; break; case MOVE_EFFECT_ATK_PLUS_1: case MOVE_EFFECT_DEF_PLUS_1: @@ -3001,7 +3025,7 @@ void SetMoveEffect(bool8 primary, u8 certain) gBattleMoveDamage = 1; BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = gMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; + gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; break; case MOVE_EFFECT_THRASH: if (gBattleMons[gEffectBank].status2 & STATUS2_LOCK_CONFUSE) @@ -3108,9 +3132,9 @@ static void atk18_status_effect_clear(void) gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); if (gBattleCommunication[MOVE_EFFECT_BYTE] <= MOVE_EFFECT_TOXIC) - gBattleMons[gActiveBank].status1 &= (~gStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]); + gBattleMons[gActiveBank].status1 &= (~sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]); else - gBattleMons[gActiveBank].status2 &= (~gStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]); + gBattleMons[gActiveBank].status2 &= (~sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]); gBattleCommunication[MOVE_EFFECT_BYTE] = 0; gBattlescriptCurrInstr += 2; @@ -6733,8 +6757,8 @@ static void sub_804F17C(void) gBattle_BG2_Y = 0; gBattle_BG2_X = 0x1A0; - LoadPalette(gUnknown_0831C2C8, 0x60, 0x20); - CopyToWindowPixelBuffer(14, gUnknown_0831C2E8, 0, 0); + LoadPalette(sUnknown_0831C2C8, 0x60, 0x20); + CopyToWindowPixelBuffer(14, sUnknown_0831C2E8, 0, 0); PutWindowTilemap(14); CopyWindowToVram(14, 3); @@ -6860,7 +6884,7 @@ static void PutMonIconOnLvlUpBox(void) LoadSpriteSheet(&iconSheet); LoadSpritePalette(&iconPalSheet); - spriteId = CreateSprite(&SpriteTemplate_MonIconOnLvlUpBox, 256, 10, 0); + spriteId = CreateSprite(&sSpriteTemplate_MonIconOnLvlUpBox, 256, 10, 0); gSprites[spriteId].sDestroy = FALSE; gSprites[spriteId].sSavedLvlUpBoxXPosition = gBattle_BG2_X; } @@ -7078,7 +7102,7 @@ static void atk76_various(void) { gBattleStruct->field_92 |= gBitTable[gActiveBank]; gBattleCommunication[0] = 1; - gBattleCommunication[MULTISTRING_CHOOSER] = gUnknown_0831C4F8[GetNatureFromPersonality(gBattleMons[gActiveBank].personality)]; + gBattleCommunication[MULTISTRING_CHOOSER] = sUnknown_0831C4F8[GetNatureFromPersonality(gBattleMons[gActiveBank].personality)]; } break; case 9: @@ -8475,10 +8499,10 @@ static void atk9C_set_substitute(void) static bool8 IsMoveUncopyableByMimic(u16 move) { s32 i; - for (i = 0; gMovesForbiddenToCopy[i] != MIMIC_FORBIDDEN_END - && gMovesForbiddenToCopy[i] != move; i++); + for (i = 0; sMovesForbiddenToCopy[i] != MIMIC_FORBIDDEN_END + && sMovesForbiddenToCopy[i] != move; i++); - return (gMovesForbiddenToCopy[i] != MIMIC_FORBIDDEN_END); + return (sMovesForbiddenToCopy[i] != MIMIC_FORBIDDEN_END); } static void atk9D_mimicattackcopy(void) @@ -8537,7 +8561,7 @@ static void atk9E_metronome(void) for (i = 0; i < 4; i++); // ? - for (move = gMovesForbiddenToCopy; ; move++) + for (move = sMovesForbiddenToCopy; ; move++) { if (*move == gCurrentMove) break; @@ -8567,7 +8591,7 @@ static void atk9E_metronome(void) ldr r7, =gCurrentMove\n\ movs r6, 0xB1\n\ lsls r6, 1\n\ - ldr r5, =gMovesForbiddenToCopy\n\ + ldr r5, =sMovesForbiddenToCopy\n\ ldr r0, =gBattlescriptCurrInstr\n\ mov r8, r0\n\ _080524EE:\n\ @@ -10580,9 +10604,9 @@ static void atkDE_asistattackselect(void) if (IsInvalidForSleepTalkOrAssist(move)) continue; - for (; gMovesForbiddenToCopy[i] != ASSIST_FORBIDDEN_END && move != gMovesForbiddenToCopy[i]; i++); + for (; sMovesForbiddenToCopy[i] != ASSIST_FORBIDDEN_END && move != sMovesForbiddenToCopy[i]; i++); - if (gMovesForbiddenToCopy[i] != ASSIST_FORBIDDEN_END) + if (sMovesForbiddenToCopy[i] != ASSIST_FORBIDDEN_END) continue; if (move == MOVE_NONE) continue; @@ -10774,14 +10798,14 @@ static void atkE5_pickup(void) for (j = 0; j < 9; j++) { - if (gPickupProbabilities[j] > rand) + if (sPickupProbabilities[j] > rand) { - SetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM, &gPickupItems[lvlDivBy10 + j]); + SetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM, &sPickupItems[lvlDivBy10 + j]); break; } else if (rand == 99 || rand == 98) { - SetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM, &gRarePickupItems[lvlDivBy10 + (99 - rand)]); + SetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM, &sRarePickupItems[lvlDivBy10 + (99 - rand)]); break; } } -- cgit v1.2.3 From 6d4d58a8a7759517b327a4017e05332888662e84 Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Thu, 28 Sep 2017 17:38:07 +0200 Subject: rename battle4 and battleai --- src/battle_3.c | 3 +- src/battle_4.c | 11415 -------------------------------------- src/battle_ai.c | 2922 ---------- src/battle_ai_script_commands.c | 2922 ++++++++++ src/battle_script_commands.c | 11415 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 14338 insertions(+), 14339 deletions(-) delete mode 100644 src/battle_4.c delete mode 100644 src/battle_ai.c create mode 100644 src/battle_ai_script_commands.c create mode 100644 src/battle_script_commands.c (limited to 'src') diff --git a/src/battle_3.c b/src/battle_3.c index e81d527d0..e42d9317d 100644 --- a/src/battle_3.c +++ b/src/battle_3.c @@ -13,7 +13,7 @@ #include "text.h" #include "string_util.h" #include "battle_message.h" -#include "battle_ai.h" +#include "battle_ai_script_commands.h" #include "battle_controllers.h" #include "event_data.h" #include "calculate_base_damage.h" @@ -57,7 +57,6 @@ extern u8 gCurrMovePos; extern u8 gUnknown_020241E9; extern const struct BattleMove gBattleMoves[]; -extern void (* const gBattleScriptingCommandsTable[])(void); // scripts extern const u8 gUnknown_082DAE2A[]; diff --git a/src/battle_4.c b/src/battle_4.c deleted file mode 100644 index e82f78570..000000000 --- a/src/battle_4.c +++ /dev/null @@ -1,11415 +0,0 @@ -#include "global.h" -#include "battle.h" -#include "battle_move_effects.h" -#include "battle_message.h" -#include "battle_ai.h" -#include "moves.h" -#include "abilities.h" -#include "item.h" -#include "items.h" -#include "hold_effects.h" -#include "util.h" -#include "pokemon.h" -#include "calculate_base_damage.h" -#include "rng.h" -#include "battle_controllers.h" -#include "species.h" -#include "songs.h" -#include "text.h" -#include "sound.h" -#include "pokedex.h" -#include "recorded_battle.h" -#include "window.h" -#include "reshow_battle_screen.h" -#include "main.h" -#include "palette.h" -#include "money.h" -#include "bg.h" -#include "string_util.h" -#include "pokemon_icon.h" -#include "pokemon_item_effects.h" -#include "m4a.h" -#include "mail.h" -#include "event_data.h" -#include "pokemon_storage_system.h" -#include "task.h" -#include "naming_screen.h" - -// variables - -extern u8 gCritMultiplier; -extern s32 gBattleMoveDamage; -extern u32 gStatuses3[BATTLE_BANKS_COUNT]; -extern u32 gBattleTypeFlags; -extern struct BattleEnigmaBerry gEnigmaBerries[BATTLE_BANKS_COUNT]; -extern struct BattlePokemon gBattleMons[BATTLE_BANKS_COUNT]; -extern u8 gActiveBank; -extern u32 gBattleExecBuffer; -extern u8 gNoOfAllBanks; -extern u16 gBattlePartyID[BATTLE_BANKS_COUNT]; -extern u8 gTurnOrder[BATTLE_BANKS_COUNT]; -extern u8 gUnknown_0202407A[BATTLE_BANKS_COUNT]; -extern u16 gCurrentMove; -extern u8 gLastUsedAbility; -extern u16 gBattleWeather; -extern u8 gStringBank; -extern u8 gEffectBank; -extern u8 gAbsentBankFlags; -extern u8 gMultiHitCounter; -extern u16 gChosenMovesByBanks[BATTLE_BANKS_COUNT]; -extern u16 gSideAffecting[2]; -extern u16 gPauseCounterBattle; -extern u16 gPaydayMoney; -extern u16 gRandomTurnNumber; -extern u8 gBattleOutcome; -extern u8 gBattleTerrain; -extern u8 gBankAttacker; -extern u8 gBankTarget; -extern const u8* gBattlescriptCurrInstr; -extern u8 gCurrMovePos; -extern u8 gFightStateTracker; -extern u32 gHitMarker; -extern u8 gBattleMoveFlags; -extern u8 gBattleCommunication[]; -extern u16 gUnknown_02024250[4]; -extern u16 gUnknown_02024258[4]; -extern u16 gUnknown_02024260[4]; -extern u8 gUnknown_02024270[4]; -extern u8 gStringBank; -extern u16 gDynamicBasePower; -extern u16 gLastUsedItem; -extern u16 gBattleMovePower; -extern s32 gHpDealt; -extern s32 gTakenDmg[BATTLE_BANKS_COUNT]; -extern u8 gTakenDmgBanks[BATTLE_BANKS_COUNT]; -extern u8 gSentPokesToOpponent[2]; -extern u8 gBank1; -extern u16 gExpShareExp; -extern u8 gLeveledUpInBattle; -extern void (*gBattleMainFunc)(void); -extern u8 gPlayerPartyCount; -extern u16 gMoveToLearn; -extern u16 gRandomMove; -extern u8 gBankInMenu; -extern u8 gActionForBanks[BATTLE_BANKS_COUNT]; -extern u8 gCurrentMoveTurn; -extern u8 gBattleBufferB[BATTLE_BANKS_COUNT][0x200]; -extern u16 gLockedMoves[BATTLE_BANKS_COUNT]; -extern u16 gPartnerTrainerId; -extern u16 gLastUsedMove; -extern u16 gUnknownMovesUsedByBanks[BATTLE_BANKS_COUNT]; -extern u16 gLastUsedMovesByBanks[BATTLE_BANKS_COUNT]; -extern u16 gTrainerBattleOpponent_A; -extern u16 gTrainerBattleOpponent_B; -extern u8 gUnknown_020241E9; -extern u16 gBattle_BG1_X; -extern u16 gBattle_BG1_Y; -extern u16 gBattle_BG2_X; -extern u16 gBattle_BG2_Y; -extern u16 gBattle_BG3_X; -extern struct MusicPlayerInfo gMPlay_BGM; - -struct TrainerMoney -{ - u8 classId; - u8 value; -}; - -extern const struct BattleMove gBattleMoves[]; -extern const struct BaseStats gBaseStats[]; -extern const u8 gTypeEffectiveness[]; -extern const u16 gMissStringIds[]; -extern const u16 gTrappingMoves[]; -extern const struct TrainerMoney gTrainerMoneyTable[]; -extern const u8* const gBattleScriptsForMoveEffects[]; - -// functions -extern void sub_81A5718(u8 bank); // battle frontier 2 -extern void sub_81A56B4(void); // battle frontier 2 -extern void sub_81BFA38(struct Pokemon* party, u8 monPartyId, u8 monCount, void (*callback)(void), u16 move); // pokemon summary screen -extern u8 sub_81C1B94(void); // pokemon summary screen -extern void IncrementGameStat(u8 statId); // rom_4 -extern void sub_81D388C(struct Pokemon* mon, void* statStoreLocation); // pokenav.s -extern void sub_81D3640(u8 arg0, void* statStoreLocation1, void* statStoreLocation2, u8 arg3, u8 arg4, u8 arg5); // pokenav.s -extern void sub_81D3784(u8 arg0, void* statStoreLocation1, u8 arg2, u8 arg3, u8 arg4); // pokenav.s -extern u8* GetMonNickname(struct Pokemon* mon, u8* dst); // party_menu -extern u8 sub_81A5258(u8* arg0); // battle frontier 2 -extern void sub_81A5BF8(void); // battle frontier 2 -extern void sub_81A5D44(void); // battle frontier 2 -extern void sub_81B8E80(u8 bank, u8, u8); // party menu -extern bool8 sub_81B1250(void); // ? -extern u8 GetScaledHPFraction(s16 hp, s16 maxhp, u8 scale); // battle interface -extern bool8 InBattlePike(void); -extern bool8 InBattlePyramid(void); -extern u16 GetBattlePyramidPickupItemId(void); -extern u8 sav1_map_get_light_level(void); -extern u8 sub_813B21C(void); -extern u16 get_unknown_box_id(void); -extern void c2_berry_program_update_menu(void); -extern void sub_8035AA4(void); - -// BattleScripts -extern const u8 BattleScript_MoveEnd[]; -extern const u8 BattleScript_NoPPForMove[]; -extern const u8 BattleScript_MagicCoatBounce[]; -extern const u8 BattleScript_TookAttack[]; -extern const u8 BattleScript_SnatchedMove[]; -extern const u8 BattleScript_Pausex20[]; -extern const u8 BattleScript_SubstituteFade[]; -extern const u8 BattleScript_HangedOnMsg[]; -extern const u8 BattleScript_OneHitKOMsg[]; -extern const u8 BattleScript_EnduredMsg[]; -extern const u8 BattleScript_PSNPrevention[]; -extern const u8 BattleScript_BRNPrevention[]; -extern const u8 BattleScript_PRLZPrevention[]; -extern const u8 BattleScript_FlinchPrevention[]; -extern const u8 BattleScript_StatUp[]; -extern const u8 BattleScript_StatDown[]; -extern const u8 BattleScript_NoItemSteal[]; -extern const u8 BattleScript_ItemSteal[]; -extern const u8 BattleScript_RapidSpinAway[]; -extern const u8 BattleScript_TargetPRLZHeal[]; -extern const u8 BattleScript_KnockedOff[]; -extern const u8 BattleScript_StickyHoldActivates[]; -extern const u8 BattleScript_AllStatsUp[]; -extern const u8 BattleScript_AtkDefDown[]; -extern const u8 BattleScript_SAtkDown2[]; -extern const u8 BattleScript_LevelUp[]; -extern const u8 BattleScript_WrapFree[]; -extern const u8 BattleScript_LeechSeedFree[]; -extern const u8 BattleScript_SpikesFree[]; -extern const u8 BattleScript_ButItFailed[]; -extern const u8 BattleScript_ObliviousPreventsAttraction[]; -extern const u8 BattleScript_MistProtected[]; -extern const u8 BattleScript_AbilityNoStatLoss[]; -extern const u8 BattleScript_AbilityNoSpecificStatLoss[]; -extern const u8 BattleScript_TrainerBallBlock[]; -extern const u8 BattleScript_WallyBallThrow[]; -extern const u8 BattleScript_SuccessBallThrow[]; -extern const u8 BattleScript_ShakeBallThrow[]; -extern const u8 BattleScript_FaintAttacker[]; -extern const u8 BattleScript_FaintTarget[]; -extern const u8 BattleScript_DestinyBondTakesLife[]; -extern const u8 BattleScript_GrudgeTakesPp[]; -extern const u8 BattleScript_RageIsBuilding[]; -extern const u8 BattleScript_DefrostedViaFireMove[]; -extern const u8 gUnknown_082DB87D[]; -extern const u8 gUnknown_082DAE90[]; -extern const u8 gUnknown_082DAE59[]; -extern const u8 gUnknown_082DAEC7[]; -extern const u8 BattleScript_MoveEffectSleep[]; -extern const u8 BattleScript_MoveEffectPoison[]; -extern const u8 BattleScript_MoveEffectBurn[]; -extern const u8 BattleScript_MoveEffectFreeze[]; -extern const u8 BattleScript_MoveEffectParalysis[]; -extern const u8 BattleScript_MoveEffectToxic[]; -extern const u8 BattleScript_MoveEffectConfusion[]; -extern const u8 BattleScript_MoveEffectUproar[]; -extern const u8 BattleScript_MoveEffectPayDay[]; -extern const u8 BattleScript_MoveEffectWrap[]; -extern const u8 BattleScript_MoveEffectRecoil33[]; -extern const u8 BattleScript_DampStopsExplosion[]; -extern const u8 BattleScript_MistProtected[]; -extern const u8 BattleScript_AbilityNoStatLoss[]; -extern const u8 BattleScript_AbilityNoSpecificStatLoss[]; -extern const u8 BattleScript_ButItFailed[]; -extern const u8 gUnknown_082DADD8[]; -extern const u8 BattleScript_PrintPayDayMoneyString[]; -extern const u8 BattleScript_SturdyPreventsOHKO[]; -extern const u8 BattleScript_ObliviousPreventsAttraction[]; -extern const u8 BattleScript_PauseEffectivenessSoundResultMsgEndMove[]; -extern const u8 BattleScript_CastformChange[]; -extern const u8 BattleScript_TrainerBallBlock[]; -extern const u8 BattleScript_WallyBallThrow[]; -extern const u8 BattleScript_SuccessBallThrow[]; -extern const u8 BattleScript_ShakeBallThrow[]; -extern const u8 BattleScript_PresentDamageTarget[]; -extern const u8 BattleScript_AlreadyAtFullHp[]; -extern const u8 BattleScript_PresentHealTarget[]; -extern const u8 BattleScript_WrapFree[]; -extern const u8 BattleScript_LeechSeedFree[]; -extern const u8 BattleScript_SpikesFree[]; - -// strings -extern const u8 gText_BattleYesNoChoice[]; - -// read via orr -#define BSScriptRead32(ptr) ((ptr)[0] | (ptr)[1] << 8 | (ptr)[2] << 16 | (ptr)[3] << 24) -#define BSScriptRead16(ptr) ((ptr)[0] | ((ptr)[1] << 8)) -#define BSScriptReadPtr(ptr) ((void *)BSScriptRead32(ptr)) - -// read via add -#define BS2ScriptRead32(ptr) ((ptr)[0] + ((ptr)[1] << 8) + ((ptr)[2] << 16) + ((ptr)[3] << 24)) -#define BS2ScriptRead16(ptr) ((ptr)[0] + ((ptr)[1] << 8)) -#define BS2ScriptReadPtr(ptr) ((void *)BS2ScriptRead32(ptr)) - -#define TARGET_PROTECT_AFFECTED ((gProtectStructs[gBankTarget].protected && gBattleMoves[gCurrentMove].flags & FLAG_PROTECT_AFFECTED)) - -#define TARGET_TURN_DAMAGED (((gSpecialStatuses[gBankTarget].moveturnLostHP_physical || gSpecialStatuses[gBankTarget].moveturnLostHP_special))) - -// this file's functions -static bool8 IsTwoTurnsMove(u16 move); -static void DestinyBondFlagUpdate(void); -static u8 AttacksThisTurn(u8 bank, u16 move); // Note: returns 1 if it's a charging turn, otherwise 2. -static void CheckWonderGuardAndLevitate(void); -static u8 ChangeStatBuffs(s8 statValue, u8 statId, u8, const u8* BS_ptr); -static bool32 IsMonGettingExpSentOut(void); -static void sub_804F17C(void); -static bool8 sub_804F1CC(void); -static void sub_804F100(void); -static void sub_804F144(void); -static bool8 sub_804F344(void); -static void PutMonIconOnLvlUpBox(void); -static void PutLevelAndGenderOnLvlUpBox(void); - -static void SpriteCB_MonIconOnLvlUpBox(struct Sprite* sprite); - -static void atk00_attackcanceler(void); -static void atk01_accuracycheck(void); -static void atk02_attackstring(void); -static void atk03_ppreduce(void); -static void atk04_critcalc(void); -static void atk05_damagecalc1(void); -static void atk06_typecalc(void); -static void atk07_dmg_adjustment(void); -static void atk08_dmg_adjustment2(void); -static void atk09_attackanimation(void); -static void atk0A_waitanimation(void); -static void atk0B_healthbarupdate(void); -static void atk0C_datahpupdate(void); -static void atk0D_critmessage(void); -static void atk0E_effectiveness_sound(void); -static void atk0F_resultmessage(void); -static void atk10_printstring(void); -static void atk11_printstring_playeronly(void); -static void atk12_waitmessage(void); -static void atk13_printfromtable(void); -static void atk14_printfromtable_playeronly(void); -static void atk15_seteffectwithchance(void); -static void atk16_seteffectprimary(void); -static void atk17_seteffectsecondary(void); -static void atk18_status_effect_clear(void); -static void atk19_faint_pokemon(void); -static void atk1A_faint_animation(void); -static void atk1B_faint_effects_clear(void); -static void atk1C_jumpifstatus(void); -static void atk1D_jumpifstatus2(void); -static void atk1E_jumpifability(void); -static void atk1F_jumpifsideaffecting(void); -static void atk20_jumpifstat(void); -static void atk21_jumpifstatus3(void); -static void atk22_jumpiftype(void); -static void atk23_getexp(void); -static void atk24(void); -static void atk25_move_values_cleanup(void); -static void atk26_set_multihit(void); -static void atk27_decrement_multihit(void); -static void atk28_goto(void); -static void atk29_jumpifbyte(void); -static void atk2A_jumpifhalfword(void); -static void atk2B_jumpifword(void); -static void atk2C_jumpifarrayequal(void); -static void atk2D_jumpifarraynotequal(void); -static void atk2E_setbyte(void); -static void atk2F_addbyte(void); -static void atk30_subbyte(void); -static void atk31_copyarray(void); -static void atk32_copyarray_withindex(void); -static void atk33_orbyte(void); -static void atk34_orhalfword(void); -static void atk35_orword(void); -static void atk36_bicbyte(void); -static void atk37_bichalfword(void); -static void atk38_bicword(void); -static void atk39_pause(void); -static void atk3A_waitstate(void); -static void atk3B_healthbar_update(void); -static void atk3C_return(void); -static void atk3D_end(void); -static void atk3E_end2(void); -static void atk3F_end3(void); -static void atk40_jump_if_move_affected_by_protect(void); -static void atk41_call(void); -static void atk42_jumpiftype2(void); -static void atk43_jumpifabilitypresent(void); -static void atk44(void); -static void atk45_playanimation(void); -static void atk46_playanimation2(void); -static void atk47_setgraphicalstatchangevalues(void); -static void atk48_playstatchangeanimation(void); -static void atk49_moveend(void); -static void atk4A_typecalc2(void); -static void atk4B_return_atk_to_ball(void); -static void atk4C_copy_poke_data(void); -static void atk4D_switch_data_update(void); -static void atk4E_switchin_anim(void); -static void atk4F_jump_if_cannot_switch(void); -static void atk50_openpartyscreen(void); -static void atk51_switch_handle_order(void); -static void atk52_switch_in_effects(void); -static void atk53_trainer_slide(void); -static void atk54_effectiveness_sound(void); -static void atk55_play_sound(void); -static void atk56_fainting_cry(void); -static void atk57(void); -static void atk58_return_to_ball(void); -static void atk59_learnmove_inbattle(void); -static void atk5A_yesnoboxlearnmove(void); -static void atk5B_yesnoboxstoplearningmove(void); -static void atk5C_hitanimation(void); -static void atk5D_getmoneyreward(void); -static void atk5E_8025A70(void); -static void atk5F_8025B24(void); -static void atk60_increment_gamestat(void); -static void atk61_8025BA4(void); -static void atk62_08025C6C(void); -static void atk63_jumptorandomattack(void); -static void atk64_statusanimation(void); -static void atk65_status2animation(void); -static void atk66_chosenstatusanimation(void); -static void atk67_yesnobox(void); -static void atk68_80246A0(void); -static void atk69_dmg_adjustment3(void); -static void atk6A_removeitem(void); -static void atk6B_atknameinbuff1(void); -static void atk6C_draw_lvlupbox(void); -static void atk6D_reset_sentpokes_value(void); -static void atk6E_set_atk_to_player0(void); -static void atk6F_set_visible(void); -static void atk70_record_last_used_ability(void); -static void atk71_buffer_move_to_learn(void); -static void atk72_jump_if_can_run_frombattle(void); -static void atk73_hp_thresholds(void); -static void atk74_hp_thresholds2(void); -static void atk75_item_effect_on_opponent(void); -static void atk76_various(void); -static void atk77_set_protect_like(void); -static void atk78_faintifabilitynotdamp(void); -static void atk79_setatkhptozero(void); -static void atk7A_jumpwhiletargetvalid(void); -static void atk7B_healhalfHP_if_possible(void); -static void atk7C_trymirrormove(void); -static void atk7D_set_rain(void); -static void atk7E_setreflect(void); -static void atk7F_setseeded(void); -static void atk80_manipulatedamage(void); -static void atk81_setrest(void); -static void atk82_jumpifnotfirstturn(void); -static void atk83_nop(void); -static void atk84_jump_if_cant_sleep(void); -static void atk85_stockpile(void); -static void atk86_stockpiletobasedamage(void); -static void atk87_stockpiletohpheal(void); -static void atk88_negativedamage(void); -static void atk89_statbuffchange(void); -static void atk8A_normalisebuffs(void); -static void atk8B_setbide(void); -static void atk8C_confuseifrepeatingattackends(void); -static void atk8D_setmultihit_counter(void); -static void atk8E_init_multihit_string(void); -static void atk8F_forcerandomswitch(void); -static void atk90_conversion_type_change(void); -static void atk91_givepaydaymoney(void); -static void atk92_setlightscreen(void); -static void atk93_ko_move(void); -static void atk94_damagetohalftargethp(void); -static void atk95_setsandstorm(void); -static void atk96_weatherdamage(void); -static void atk97_try_infatuation(void); -static void atk98_status_icon_update(void); -static void atk99_setmist(void); -static void atk9A_set_focusenergy(void); -static void atk9B_transformdataexecution(void); -static void atk9C_set_substitute(void); -static void atk9D_mimicattackcopy(void); -static void atk9E_metronome(void); -static void atk9F_dmgtolevel(void); -static void atkA0_psywavedamageeffect(void); -static void atkA1_counterdamagecalculator(void); -static void atkA2_mirrorcoatdamagecalculator(void); -static void atkA3_disablelastusedattack(void); -static void atkA4_setencore(void); -static void atkA5_painsplitdmgcalc(void); -static void atkA6_settypetorandomresistance(void); -static void atkA7_setalwayshitflag(void); -static void atkA8_copymovepermanently(void); -static void atkA9_sleeptalk_choose_move(void); -static void atkAA_set_destinybond(void); -static void atkAB_DestinyBondFlagUpdate(void); -static void atkAC_remaininghptopower(void); -static void atkAD_spite_ppreduce(void); -static void atkAE_heal_party_status(void); -static void atkAF_cursetarget(void); -static void atkB0_set_spikes(void); -static void atkB1_set_foresight(void); -static void atkB2_setperishsong(void); -static void atkB3_rolloutdamagecalculation(void); -static void atkB4_jumpifconfusedandstatmaxed(void); -static void atkB5_furycuttercalc(void); -static void atkB6_happinesstodamagecalculation(void); -static void atkB7_presentdamagecalculation(void); -static void atkB8_set_safeguard(void); -static void atkB9_magnitudedamagecalculation(void); -static void atkBA_jumpifnopursuitswitchdmg(void); -static void atkBB_setsunny(void); -static void atkBC_maxattackhalvehp(void); -static void atkBD_copyfoestats(void); -static void atkBE_rapidspinfree(void); -static void atkBF_set_defense_curl(void); -static void atkC0_recoverbasedonsunlight(void); -static void atkC1_hidden_power(void); -static void atkC2_selectnexttarget(void); -static void atkC3_setfutureattack(void); -static void atkC4_beat_up(void); -static void atkC5_setsemiinvulnerablebit(void); -static void atkC6_clearsemiinvulnerablebit(void); -static void atkC7_setminimize(void); -static void atkC8_sethail(void); -static void atkC9_jumpifattackandspecialattackcannotfall(void); -static void atkCA_setforcedtarget(void); -static void atkCB_setcharge(void); -static void atkCC_callterrainattack(void); -static void atkCD_cureifburnedparalysedorpoisoned(void); -static void atkCE_settorment(void); -static void atkCF_jumpifnodamage(void); -static void atkD0_settaunt(void); -static void atkD1_set_helpinghand(void); -static void atkD2_swap_items(void); -static void atkD3_copy_ability(void); -static void atkD4_wish_effect(void); -static void atkD5_setroots(void); -static void atkD6_doubledamagedealtifdamaged(void); -static void atkD7_setyawn(void); -static void atkD8_setdamagetohealthdifference(void); -static void atkD9_scaledamagebyhealthratio(void); -static void atkDA_abilityswap(void); -static void atkDB_imprisoneffect(void); -static void atkDC_setgrudge(void); -static void atkDD_weightdamagecalculation(void); -static void atkDE_asistattackselect(void); -static void atkDF_setmagiccoat(void); -static void atkE0_setstealstatchange(void); -static void atkE1_intimidate_string_loader(void); -static void atkE2_switchout_abilities(void); -static void atkE3_jumpifhasnohp(void); -static void atkE4_getsecretpowereffect(void); -static void atkE5_pickup(void); -static void atkE6_castform_change_animation(void); -static void atkE7_castform_data_change(void); -static void atkE8_settypebasedhalvers(void); -static void atkE9_setweatherballtype(void); -static void atkEA_recycleitem(void); -static void atkEB_settypetoterrain(void); -static void atkEC_pursuit_sth(void); -static void atkED_802B4B4(void); -static void atkEE_removelightscreenreflect(void); -static void atkEF_pokeball_catch_calculation(void); -static void atkF0_give_caught_mon(void); -static void atkF1_set_caught_mon_dex_flags(void); -static void atkF2_display_dex_info(void); -static void atkF3_nickname_caught_poke(void); -static void atkF4_subattackerhpbydmg(void); -static void atkF5_removeattackerstatus1(void); -static void atkF6_802BF48(void); -static void atkF7_802BF54(void); -static void atkF8_trainer_slide_back(void); - -void (* const gBattleScriptingCommandsTable[])(void) = -{ - atk00_attackcanceler, - atk01_accuracycheck, - atk02_attackstring, - atk03_ppreduce, - atk04_critcalc, - atk05_damagecalc1, - atk06_typecalc, - atk07_dmg_adjustment, - atk08_dmg_adjustment2, - atk09_attackanimation, - atk0A_waitanimation, - atk0B_healthbarupdate, - atk0C_datahpupdate, - atk0D_critmessage, - atk0E_effectiveness_sound, - atk0F_resultmessage, - atk10_printstring, - atk11_printstring_playeronly, - atk12_waitmessage, - atk13_printfromtable, - atk14_printfromtable_playeronly, - atk15_seteffectwithchance, - atk16_seteffectprimary, - atk17_seteffectsecondary, - atk18_status_effect_clear, - atk19_faint_pokemon, - atk1A_faint_animation, - atk1B_faint_effects_clear, - atk1C_jumpifstatus, - atk1D_jumpifstatus2, - atk1E_jumpifability, - atk1F_jumpifsideaffecting, - atk20_jumpifstat, - atk21_jumpifstatus3, - atk22_jumpiftype, - atk23_getexp, - atk24, - atk25_move_values_cleanup, - atk26_set_multihit, - atk27_decrement_multihit, - atk28_goto, - atk29_jumpifbyte, - atk2A_jumpifhalfword, - atk2B_jumpifword, - atk2C_jumpifarrayequal, - atk2D_jumpifarraynotequal, - atk2E_setbyte, - atk2F_addbyte, - atk30_subbyte, - atk31_copyarray, - atk32_copyarray_withindex, - atk33_orbyte, - atk34_orhalfword, - atk35_orword, - atk36_bicbyte, - atk37_bichalfword, - atk38_bicword, - atk39_pause, - atk3A_waitstate, - atk3B_healthbar_update, - atk3C_return, - atk3D_end, - atk3E_end2, - atk3F_end3, - atk40_jump_if_move_affected_by_protect, - atk41_call, - atk42_jumpiftype2, - atk43_jumpifabilitypresent, - atk44, - atk45_playanimation, - atk46_playanimation2, - atk47_setgraphicalstatchangevalues, - atk48_playstatchangeanimation, - atk49_moveend, - atk4A_typecalc2, - atk4B_return_atk_to_ball, - atk4C_copy_poke_data, - atk4D_switch_data_update, - atk4E_switchin_anim, - atk4F_jump_if_cannot_switch, - atk50_openpartyscreen, - atk51_switch_handle_order, - atk52_switch_in_effects, - atk53_trainer_slide, - atk54_effectiveness_sound, - atk55_play_sound, - atk56_fainting_cry, - atk57, - atk58_return_to_ball, - atk59_learnmove_inbattle, - atk5A_yesnoboxlearnmove, - atk5B_yesnoboxstoplearningmove, - atk5C_hitanimation, - atk5D_getmoneyreward, - atk5E_8025A70, - atk5F_8025B24, - atk60_increment_gamestat, - atk61_8025BA4, - atk62_08025C6C, - atk63_jumptorandomattack, - atk64_statusanimation, - atk65_status2animation, - atk66_chosenstatusanimation, - atk67_yesnobox, - atk68_80246A0, - atk69_dmg_adjustment3, - atk6A_removeitem, - atk6B_atknameinbuff1, - atk6C_draw_lvlupbox, - atk6D_reset_sentpokes_value, - atk6E_set_atk_to_player0, - atk6F_set_visible, - atk70_record_last_used_ability, - atk71_buffer_move_to_learn, - atk72_jump_if_can_run_frombattle, - atk73_hp_thresholds, - atk74_hp_thresholds2, - atk75_item_effect_on_opponent, - atk76_various, - atk77_set_protect_like, - atk78_faintifabilitynotdamp, - atk79_setatkhptozero, - atk7A_jumpwhiletargetvalid, - atk7B_healhalfHP_if_possible, - atk7C_trymirrormove, - atk7D_set_rain, - atk7E_setreflect, - atk7F_setseeded, - atk80_manipulatedamage, - atk81_setrest, - atk82_jumpifnotfirstturn, - atk83_nop, - atk84_jump_if_cant_sleep, - atk85_stockpile, - atk86_stockpiletobasedamage, - atk87_stockpiletohpheal, - atk88_negativedamage, - atk89_statbuffchange, - atk8A_normalisebuffs, - atk8B_setbide, - atk8C_confuseifrepeatingattackends, - atk8D_setmultihit_counter, - atk8E_init_multihit_string, - atk8F_forcerandomswitch, - atk90_conversion_type_change, - atk91_givepaydaymoney, - atk92_setlightscreen, - atk93_ko_move, - atk94_damagetohalftargethp, - atk95_setsandstorm, - atk96_weatherdamage, - atk97_try_infatuation, - atk98_status_icon_update, - atk99_setmist, - atk9A_set_focusenergy, - atk9B_transformdataexecution, - atk9C_set_substitute, - atk9D_mimicattackcopy, - atk9E_metronome, - atk9F_dmgtolevel, - atkA0_psywavedamageeffect, - atkA1_counterdamagecalculator, - atkA2_mirrorcoatdamagecalculator, - atkA3_disablelastusedattack, - atkA4_setencore, - atkA5_painsplitdmgcalc, - atkA6_settypetorandomresistance, - atkA7_setalwayshitflag, - atkA8_copymovepermanently, - atkA9_sleeptalk_choose_move, - atkAA_set_destinybond, - atkAB_DestinyBondFlagUpdate, - atkAC_remaininghptopower, - atkAD_spite_ppreduce, - atkAE_heal_party_status, - atkAF_cursetarget, - atkB0_set_spikes, - atkB1_set_foresight, - atkB2_setperishsong, - atkB3_rolloutdamagecalculation, - atkB4_jumpifconfusedandstatmaxed, - atkB5_furycuttercalc, - atkB6_happinesstodamagecalculation, - atkB7_presentdamagecalculation, - atkB8_set_safeguard, - atkB9_magnitudedamagecalculation, - atkBA_jumpifnopursuitswitchdmg, - atkBB_setsunny, - atkBC_maxattackhalvehp, - atkBD_copyfoestats, - atkBE_rapidspinfree, - atkBF_set_defense_curl, - atkC0_recoverbasedonsunlight, - atkC1_hidden_power, - atkC2_selectnexttarget, - atkC3_setfutureattack, - atkC4_beat_up, - atkC5_setsemiinvulnerablebit, - atkC6_clearsemiinvulnerablebit, - atkC7_setminimize, - atkC8_sethail, - atkC9_jumpifattackandspecialattackcannotfall, - atkCA_setforcedtarget, - atkCB_setcharge, - atkCC_callterrainattack, - atkCD_cureifburnedparalysedorpoisoned, - atkCE_settorment, - atkCF_jumpifnodamage, - atkD0_settaunt, - atkD1_set_helpinghand, - atkD2_swap_items, - atkD3_copy_ability, - atkD4_wish_effect, - atkD5_setroots, - atkD6_doubledamagedealtifdamaged, - atkD7_setyawn, - atkD8_setdamagetohealthdifference, - atkD9_scaledamagebyhealthratio, - atkDA_abilityswap, - atkDB_imprisoneffect, - atkDC_setgrudge, - atkDD_weightdamagecalculation, - atkDE_asistattackselect, - atkDF_setmagiccoat, - atkE0_setstealstatchange, - atkE1_intimidate_string_loader, - atkE2_switchout_abilities, - atkE3_jumpifhasnohp, - atkE4_getsecretpowereffect, - atkE5_pickup, - atkE6_castform_change_animation, - atkE7_castform_data_change, - atkE8_settypebasedhalvers, - atkE9_setweatherballtype, - atkEA_recycleitem, - atkEB_settypetoterrain, - atkEC_pursuit_sth, - atkED_802B4B4, - atkEE_removelightscreenreflect, - atkEF_pokeball_catch_calculation, - atkF0_give_caught_mon, - atkF1_set_caught_mon_dex_flags, - atkF2_display_dex_info, - atkF3_nickname_caught_poke, - atkF4_subattackerhpbydmg, - atkF5_removeattackerstatus1, - atkF6_802BF48, - atkF7_802BF54, - atkF8_trainer_slide_back -}; - -struct StatFractions -{ - u8 dividend; - u8 divisor; -}; - -static const struct StatFractions sAccuracyStageRatios[] = -{ - { 33, 100}, // -6 - { 36, 100}, // -5 - { 43, 100}, // -4 - { 50, 100}, // -3 - { 60, 100}, // -2 - { 75, 100}, // -1 - { 1, 1}, // 0 - {133, 100}, // +1 - {166, 100}, // +2 - { 2, 1}, // +3 - {233, 100}, // +4 - {133, 50}, // +5 - { 3, 1}, // +6 -}; - -// The chance is 1/N for each stage. -static const u16 sCriticalHitChance[] = {16, 8, 4, 3, 2}; - -static const u32 sStatusFlagsForMoveEffects[] = -{ - 0x00000000, - STATUS_SLEEP, - STATUS_POISON, - STATUS_BURN, - STATUS_FREEZE, - STATUS_PARALYSIS, - STATUS_TOXIC_POISON, - STATUS2_CONFUSION, - STATUS2_FLINCHED, - 0x00000000, - STATUS2_UPROAR, - 0x00000000, - STATUS2_MULTIPLETURNS, - STATUS2_WRAPPED, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - STATUS2_RECHARGE, - 0x00000000, - 0x00000000, - STATUS2_ESCAPE_PREVENTION, - 0x08000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - STATUS2_LOCK_CONFUSE, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000 -}; - -static const u8* const sMoveEffectBS_Ptrs[] = -{ - BattleScript_MoveEffectSleep, // 0 - BattleScript_MoveEffectSleep, // MOVE_EFFECT_SLEEP - BattleScript_MoveEffectPoison, // MOVE_EFFECT_POISON - BattleScript_MoveEffectBurn, // MOVE_EFFECT_BURN - BattleScript_MoveEffectFreeze, // MOVE_EFFECT_FREEZE - BattleScript_MoveEffectParalysis, // MOVE_EFFECT_PARALYSIS - BattleScript_MoveEffectToxic, // MOVE_EFFECT_TOXIC - BattleScript_MoveEffectConfusion, // MOVE_EFFECT_CONFUSION - BattleScript_MoveEffectSleep, // MOVE_EFFECT_FLINCH - BattleScript_MoveEffectSleep, // MOVE_EFFECT_TRI_ATTACK - BattleScript_MoveEffectUproar, // MOVE_EFFECT_UPROAR - BattleScript_MoveEffectPayDay, // MOVE_EFFECT_PAYDAY - BattleScript_MoveEffectSleep, // MOVE_EFFECT_CHARGING - BattleScript_MoveEffectWrap, // MOVE_EFFECT_WRAP - BattleScript_MoveEffectRecoil33, // MOVE_EFFECT_RECOIL_25 - BattleScript_MoveEffectSleep, // MOVE_EFFECT_ATK_PLUS_1 - BattleScript_MoveEffectSleep, // MOVE_EFFECT_DEF_PLUS_1 - BattleScript_MoveEffectSleep, // MOVE_EFFECT_SPD_PLUS_1 - BattleScript_MoveEffectSleep, // MOVE_EFFECT_SP_ATK_PLUS_1 - BattleScript_MoveEffectSleep, // MOVE_EFFECT_SP_DEF_PLUS_1 - BattleScript_MoveEffectSleep, // MOVE_EFFECT_ACC_PLUS_1 - BattleScript_MoveEffectSleep, // MOVE_EFFECT_EVS_PLUS_1 - BattleScript_MoveEffectSleep, // MOVE_EFFECT_ATK_MINUS_1 - BattleScript_MoveEffectSleep, // MOVE_EFFECT_DEF_MINUS_1 - BattleScript_MoveEffectSleep, // MOVE_EFFECT_SPD_MINUS_1 - BattleScript_MoveEffectSleep, // MOVE_EFFECT_SP_ATK_MINUS_1 - BattleScript_MoveEffectSleep, // MOVE_EFFECT_SP_DEF_MINUS_1 - BattleScript_MoveEffectSleep, // MOVE_EFFECT_ACC_MINUS_1 - BattleScript_MoveEffectSleep, // MOVE_EFFECT_EVS_MINUS_1 - BattleScript_MoveEffectSleep, // MOVE_EFFECT_RECHARGE - BattleScript_MoveEffectSleep, // MOVE_EFFECT_RAGE - BattleScript_MoveEffectSleep, // MOVE_EFFECT_STEAL_ITEM - BattleScript_MoveEffectSleep, // MOVE_EFFECT_PREVENT_ESCAPE - BattleScript_MoveEffectSleep, // MOVE_EFFECT_NIGHTMARE - BattleScript_MoveEffectSleep, // MOVE_EFFECT_ALL_STATS_UP - BattleScript_MoveEffectSleep, // MOVE_EFFECT_RAPIDSPIN - BattleScript_MoveEffectSleep, // MOVE_EFFECT_REMOVE_PARALYSIS - BattleScript_MoveEffectSleep, // MOVE_EFFECT_ATK_DEF_DOWN - BattleScript_MoveEffectRecoil33, // MOVE_EFFECT_RECOIL_33_PARALYSIS -}; - -static const struct WindowTemplate sUnusedWinTemplate = {0, 1, 3, 7, 0xF, 0x1F, 0x3F}; - -static const u16 sUnknown_0831C2C8[] = INCBIN_U16("graphics/battle_interface/unk_battlebox.gbapal"); -static const u8 sUnknown_0831C2E8[] = INCBIN_U8("graphics/battle_interface/unk_battlebox.4bpp.lz"); - -// unused -static const u8 sRubyLevelUpStatBoxStats[] = -{ - MON_DATA_MAX_HP, MON_DATA_SPATK, MON_DATA_ATK, - MON_DATA_SPDEF, MON_DATA_DEF, MON_DATA_SPD -}; - -#define MON_ICON_LVLUP_BOX_TAG 0xD75A - -static const struct OamData sOamData_MonIconOnLvlUpBox = -{ - .y = 0, - .affineMode = 0, - .objMode = 0, - .mosaic = 0, - .bpp = 0, - .shape = 0, - .x = 0, - .matrixNum = 0, - .size = 2, - .tileNum = 0, - .priority = 0, - .paletteNum = 0, - .affineParam = 0, -}; - -static const struct SpriteTemplate sSpriteTemplate_MonIconOnLvlUpBox = -{ - .tileTag = MON_ICON_LVLUP_BOX_TAG, - .paletteTag = MON_ICON_LVLUP_BOX_TAG, - .oam = &sOamData_MonIconOnLvlUpBox, - .anims = gDummySpriteAnimTable, - .images = NULL, - .affineAnims = gDummySpriteAffineAnimTable, - .callback = SpriteCB_MonIconOnLvlUpBox -}; - -static const u16 sProtectSuccessRates[] = {USHRT_MAX, USHRT_MAX / 2, USHRT_MAX / 4, USHRT_MAX / 8}; - -#define MIMIC_FORBIDDEN_END 0xFFFE -#define METRONOME_FORBIDDEN_END 0xFFFF -#define ASSIST_FORBIDDEN_END 0xFFFF - -static const u16 sMovesForbiddenToCopy[] = -{ - MOVE_METRONOME, - MOVE_STRUGGLE, - MOVE_SKETCH, - MOVE_MIMIC, - MIMIC_FORBIDDEN_END, - MOVE_COUNTER, - MOVE_MIRROR_COAT, - MOVE_PROTECT, - MOVE_DETECT, - MOVE_ENDURE, - MOVE_DESTINY_BOND, - MOVE_SLEEP_TALK, - MOVE_THIEF, - MOVE_FOLLOW_ME, - MOVE_SNATCH, - MOVE_HELPING_HAND, - MOVE_COVET, - MOVE_TRICK, - MOVE_FOCUS_PUNCH, - METRONOME_FORBIDDEN_END -}; - -static const u8 sFlailHpScaleToPowerTable[] = -{ - 1, 200, - 4, 150, - 9, 100, - 16, 80, - 32, 40, - 48, 20 -}; - -static const u16 sNaturePowerMoves[] = -{ - MOVE_STUN_SPORE, - MOVE_RAZOR_LEAF, - MOVE_EARTHQUAKE, - MOVE_HYDRO_PUMP, - MOVE_SURF, - MOVE_BUBBLE_BEAM, - MOVE_ROCK_SLIDE, - MOVE_SHADOW_BALL, - MOVE_SWIFT, - MOVE_SWIFT -}; - -// format: min. weight (hectograms), base power -static const u16 sWeightToDamageTable[] = -{ - 100, 20, - 250, 40, - 500, 60, - 1000, 80, - 2000, 100, - 0xFFFF, 0xFFFF -}; - -static const u16 sPickupItems[] = -{ - ITEM_POTION, - ITEM_ANTIDOTE, - ITEM_SUPER_POTION, - ITEM_GREAT_BALL, - ITEM_REPEL, - ITEM_ESCAPE_ROPE, - ITEM_X_ATTACK, - ITEM_FULL_HEAL, - ITEM_ULTRA_BALL, - ITEM_HYPER_POTION, - ITEM_RARE_CANDY, - ITEM_PROTEIN, - ITEM_REVIVE, - ITEM_HP_UP, - ITEM_FULL_RESTORE, - ITEM_MAX_REVIVE, - ITEM_PP_UP, - ITEM_MAX_ELIXIR, -}; - -static const u16 sRarePickupItems[] = -{ - ITEM_HYPER_POTION, - ITEM_NUGGET, - ITEM_KINGS_ROCK, - ITEM_FULL_RESTORE, - ITEM_ETHER, - ITEM_WHITE_HERB, - ITEM_TM44, - ITEM_ELIXIR, - ITEM_TM01, - ITEM_LEFTOVERS, - ITEM_TM26, -}; - -static const u8 sPickupProbabilities[] = -{ - 30, 40, 50, 60, 70, 80, 90, 94, 98 -}; - -static const u8 sTerrainToType[] = -{ - TYPE_GRASS, // tall grass - TYPE_GRASS, // long grass - TYPE_GROUND, // sand - TYPE_WATER, // underwater - TYPE_WATER, // water - TYPE_WATER, // pond water - TYPE_ROCK, // rock - TYPE_ROCK, // cave - TYPE_NORMAL, // building - TYPE_NORMAL, // plain -}; - -static const u8 sBallCatchBonuses[] = -{ - 20, 15, 10, 15 // Ultra, Great, Poke, Safari -}; - -// could be a 2d array or a struct -const ALIGNED(4) u8 gUnknown_0831C494[] = -{ - 0x3d, 0x44, 0x3d, 0x44, 0x14, 0x2d, 0x54, 0x5c, - 0x46, 0x55, 0x20, 0x5c, 0x26, 0x45, 0x46, 0x55, - 0x14, 0x5a, 0x46, 0x5c, 0x1e, 0x32, 0x20, 0x5a, - 0x38, 0x4e, 0x38, 0x4e, 0x19, 0x28, 0x4b, 0x5a, - 0x45, 0x4b, 0x1c, 0x53, 0x23, 0x2d, 0x1d, 0x23, - 0x3e, 0x48, 0x1e, 0x32, 0x3a, 0x5f, 0x58, 0x5e, - 0x22, 0x2d, 0x1d, 0x28, 0x23, 0x28, 0x23, 0x5f, - 0x38, 0x4e, 0x38, 0x4e, 0x23, 0x50, 0x22, 0x5e, - 0x2c, 0x5e, 0x22, 0x28, 0x38, 0x4e, 0x38, 0x4e, - 0x1e, 0x58, 0x1e, 0x58, 0x1e, 0x2b, 0x1b, 0x21, - 0x28, 0x5a, 0x19, 0x57, 0x12, 0x58, 0x5a, 0x5f, - 0x58, 0x5e, 0x16, 0x2a, 0x2a, 0x5c, 0x2a, 0x2f, - 0x38, 0x4e, 0x38, 0x4e -}; - -static const u8 sUnknown_0831C4F8[] = -{ - 0x03, 0x00, 0x01, 0x00, 0x00, 0x01, 0x03, 0x00, - 0x01, 0x02, 0x02, 0x00, 0x03, 0x01, 0x03, 0x01, - 0x02, 0x03, 0x03, 0x02, 0x01, 0x00, 0x02, 0x02, - 0x03, 0x00, 0x00, 0x00 -}; - -static void atk00_attackcanceler(void) -{ - s32 i; - - if (gBattleOutcome) - { - gFightStateTracker = 0xC; - return; - } - if (gBattleMons[gBankAttacker].hp == 0 && !(gHitMarker & HITMARKER_NO_ATTACKSTRING)) - { - gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - gBattlescriptCurrInstr = BattleScript_MoveEnd; - return; - } - if (AtkCanceller_UnableToUseMove()) - return; - if (AbilityBattleEffects(ABILITYEFFECT_MOVES_BLOCK, gBankTarget, 0, 0, 0)) - return; - if (!gBattleMons[gBankAttacker].pp[gCurrMovePos] && gCurrentMove != MOVE_STRUGGLE && !(gHitMarker & 0x800200) - && !(gBattleMons[gBankAttacker].status2 & STATUS2_MULTIPLETURNS)) - { - gBattlescriptCurrInstr = BattleScript_NoPPForMove; - gBattleMoveFlags |= MOVESTATUS_MISSED; - return; - } - - gHitMarker &= ~(HITMARKER_x800000); - - if (!(gHitMarker & HITMARKER_OBEYS) && !(gBattleMons[gBankAttacker].status2 & STATUS2_MULTIPLETURNS)) - { - i = IsPokeDisobedient(); // why use the 'i' variable...? - switch (i) - { - case 0: - break; - case 2: - gHitMarker |= HITMARKER_OBEYS; - return; - default: - gBattleMoveFlags |= MOVESTATUS_MISSED; - return; - } - } - - gHitMarker |= HITMARKER_OBEYS; - - if (gProtectStructs[gBankTarget].bounceMove && gBattleMoves[gCurrentMove].flags & FLAG_MAGICCOAT_AFFECTED) - { - PressurePPLose(gBankAttacker, gBankTarget, MOVE_MAGIC_COAT); - gProtectStructs[gBankTarget].bounceMove = 0; - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_MagicCoatBounce; - return; - } - - for (i = 0; i < gNoOfAllBanks; i++) - { - if ((gProtectStructs[gTurnOrder[i]].stealMove) && gBattleMoves[gCurrentMove].flags & FLAG_SNATCH_AFFECTED) - { - PressurePPLose(gBankAttacker, gTurnOrder[i], MOVE_SNATCH); - gProtectStructs[gTurnOrder[i]].stealMove = 0; - gBattleScripting.bank = gTurnOrder[i]; - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_SnatchedMove; - return; - } - } - - if (gSpecialStatuses[gBankTarget].lightningRodRedirected) - { - gSpecialStatuses[gBankTarget].lightningRodRedirected = 0; - gLastUsedAbility = ABILITY_LIGHTNING_ROD; - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_TookAttack; - RecordAbilityBattle(gBankTarget, gLastUsedAbility); - } - else if (TARGET_PROTECT_AFFECTED - && (gCurrentMove != MOVE_CURSE || (gBattleMons[gBankAttacker].type1 == TYPE_GHOST || gBattleMons[gBankAttacker].type2 == TYPE_GHOST)) - && ((!IsTwoTurnsMove(gCurrentMove) || (gBattleMons[gBankAttacker].status2 & STATUS2_MULTIPLETURNS)))) - { - CancelMultiTurnMoves(gBankAttacker); - gBattleMoveFlags |= MOVESTATUS_MISSED; - gUnknown_02024250[gBankTarget] = 0; - gUnknown_02024258[gBankTarget] = 0; - gBattleCommunication[6] = 1; - gBattlescriptCurrInstr++; - } - else - { - gBattlescriptCurrInstr++; - } -} - -static void JumpIfMoveFailed(u8 adder, u16 move) -{ - const void* BS_ptr = gBattlescriptCurrInstr + adder; - if (gBattleMoveFlags & MOVESTATUS_NOEFFECT) - { - gUnknown_02024250[gBankTarget] = 0; - gUnknown_02024258[gBankTarget] = 0; - BS_ptr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - else - { - DestinyBondFlagUpdate(); - if (AbilityBattleEffects(ABILITYEFFECT_ABSORBING, gBankTarget, 0, 0, move)) - return; - } - gBattlescriptCurrInstr = BS_ptr; -} - -static void atk40_jump_if_move_affected_by_protect(void) -{ - if (TARGET_PROTECT_AFFECTED) - { - gBattleMoveFlags |= MOVESTATUS_MISSED; - JumpIfMoveFailed(5, 0); - gBattleCommunication[6] = 1; - } - else - { - gBattlescriptCurrInstr += 5; - } -} - -bool8 JumpIfMoveAffectedByProtect(u16 move) -{ - bool8 affected = FALSE; - if (TARGET_PROTECT_AFFECTED) - { - gBattleMoveFlags |= MOVESTATUS_MISSED; - JumpIfMoveFailed(7, move); - gBattleCommunication[6] = 1; - affected = TRUE; - } - return affected; -} - -bool8 AccuracyCalcHelper(u16 move) -{ - if (gStatuses3[gBankTarget] & STATUS3_ALWAYS_HITS && gDisableStructs[gBankTarget].bankWithSureHit == gBankAttacker) - { - JumpIfMoveFailed(7, move); - return TRUE; - } - - if (!(gHitMarker & HITMARKER_IGNORE_ON_AIR) && gStatuses3[gBankTarget] & STATUS3_ON_AIR) - { - gBattleMoveFlags |= MOVESTATUS_MISSED; - JumpIfMoveFailed(7, move); - return TRUE; - } - - gHitMarker &= ~HITMARKER_IGNORE_ON_AIR; - - if (!(gHitMarker & HITMARKER_IGNORE_UNDERGROUND) && gStatuses3[gBankTarget] & STATUS3_UNDERGROUND) - { - gBattleMoveFlags |= MOVESTATUS_MISSED; - JumpIfMoveFailed(7, move); - return TRUE; - } - - gHitMarker &= ~HITMARKER_IGNORE_UNDERGROUND; - - if (!(gHitMarker & HITMARKER_IGNORE_UNDERWATER) && gStatuses3[gBankTarget] & STATUS3_UNDERWATER) - { - gBattleMoveFlags |= MOVESTATUS_MISSED; - JumpIfMoveFailed(7, move); - return TRUE; - } - - gHitMarker &= ~HITMARKER_IGNORE_UNDERWATER; - - if ((WEATHER_HAS_EFFECT && (gBattleWeather & WEATHER_RAIN_ANY) && gBattleMoves[move].effect == EFFECT_THUNDER) - || (gBattleMoves[move].effect == EFFECT_ALWAYS_HIT || gBattleMoves[move].effect == EFFECT_VITAL_THROW)) - { - JumpIfMoveFailed(7, move); - return TRUE; - } - - return FALSE; -} - -static void atk01_accuracycheck(void) -{ - u16 move = BS2ScriptRead16(gBattlescriptCurrInstr + 5); - - if (move == 0xFFFE || move == 0xFFFF) - { - if (gStatuses3[gBankTarget] & STATUS3_ALWAYS_HITS && move == 0xFFFF && gDisableStructs[gBankTarget].bankWithSureHit == gBankAttacker) - gBattlescriptCurrInstr += 7; - else if (gStatuses3[gBankTarget] & (STATUS3_ON_AIR | STATUS3_UNDERGROUND | STATUS3_UNDERWATER)) - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - else if (!JumpIfMoveAffectedByProtect(0)) - gBattlescriptCurrInstr += 7; - } - else - { - u8 type, moveAcc, holdEffect, quality; - s8 buff; - u16 calc; - - if (move == 0) - move = gCurrentMove; - - GET_MOVE_TYPE(move, type); - - if (JumpIfMoveAffectedByProtect(move)) - return; - if (AccuracyCalcHelper(move)) - return; - - if (gBattleMons[gBankTarget].status2 & STATUS2_FORESIGHT) - { - u8 acc = gBattleMons[gBankAttacker].statStages[STAT_STAGE_ACC]; - buff = acc; - } - else - { - u8 acc = gBattleMons[gBankAttacker].statStages[STAT_STAGE_ACC]; - buff = acc + 6 - gBattleMons[gBankTarget].statStages[STAT_STAGE_EVASION]; - } - - if (buff < 0) - buff = 0; - if (buff > 0xC) - buff = 0xC; - - moveAcc = gBattleMoves[move].accuracy; - // check Thunder on sunny weather - if (WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_SUN_ANY && gBattleMoves[move].effect == EFFECT_THUNDER) - moveAcc = 50; - - calc = sAccuracyStageRatios[buff].dividend * moveAcc; - calc /= sAccuracyStageRatios[buff].divisor; - - if (gBattleMons[gBankAttacker].ability == ABILITY_COMPOUND_EYES) - calc = (calc * 130) / 100; // 1.3 compound eyes boost - if (WEATHER_HAS_EFFECT && gBattleMons[gBankTarget].ability == ABILITY_SAND_VEIL && gBattleWeather & WEATHER_SANDSTORM_ANY) - calc = (calc * 80) / 100; // 1.2 sand veil loss - if (gBattleMons[gBankAttacker].ability == ABILITY_HUSTLE && type < 9) - calc = (calc * 80) / 100; // 1.2 hustle loss - - if (gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY) - { - holdEffect = gEnigmaBerries[gBankTarget].holdEffect; - quality = gEnigmaBerries[gBankTarget].holdEffectParam; - } - else - { - holdEffect = ItemId_GetHoldEffect(gBattleMons[gBankTarget].item); - quality = ItemId_GetHoldEffectParam(gBattleMons[gBankTarget].item); - } - - gStringBank = gBankTarget; - - if (holdEffect == HOLD_EFFECT_EVASION_UP) - calc = (calc * (100 - quality)) / 100; - - // final calculation - if ((Random() % 100 + 1) > calc) - { - gBattleMoveFlags |= MOVESTATUS_MISSED; - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && - (gBattleMoves[move].target == MOVE_TARGET_BOTH || gBattleMoves[move].target == MOVE_TARGET_FOES_AND_ALLY)) - gBattleCommunication[6] = 2; - else - gBattleCommunication[6] = 0; - - CheckWonderGuardAndLevitate(); - } - JumpIfMoveFailed(7, move); - } -} - -static void atk02_attackstring(void) -{ - if (gBattleExecBuffer) - return; - if (!(gHitMarker & (HITMARKER_NO_ATTACKSTRING | HITMARKER_ATTACKSTRING_PRINTED))) - { - PrepareStringBattle(4, gBankAttacker); - gHitMarker |= HITMARKER_ATTACKSTRING_PRINTED; - } - gBattlescriptCurrInstr++; - gBattleCommunication[MSG_DISPLAY] = 0; -} - -static void atk03_ppreduce(void) -{ - s32 ppToDeduct = 1; - - if (gBattleExecBuffer) - return; - - if (!gSpecialStatuses[gBankAttacker].flag20) - { - switch (gBattleMoves[gCurrentMove].target) - { - case MOVE_TARGET_FOES_AND_ALLY: - ppToDeduct += AbilityBattleEffects(ABILITYEFFECT_COUNT_ON_FIELD, gBankAttacker, ABILITY_PRESSURE, 0, 0); - break; - case MOVE_TARGET_BOTH: - case MOVE_TARGET_OPPONENTS_FIELD: - ppToDeduct += AbilityBattleEffects(ABILITYEFFECT_COUNT_OTHER_SIDE, gBankAttacker, ABILITY_PRESSURE, 0, 0); - break; - default: - if (gBankAttacker != gBankTarget && gBattleMons[gBankTarget].ability == ABILITY_PRESSURE) - ppToDeduct++; - break; - } - } - - if (!(gHitMarker & (HITMARKER_NO_PPDEDUCT | HITMARKER_NO_ATTACKSTRING)) && gBattleMons[gBankAttacker].pp[gCurrMovePos]) - { - gProtectStructs[gBankAttacker].notFirstStrike = 1; - - if (gBattleMons[gBankAttacker].pp[gCurrMovePos] > ppToDeduct) - gBattleMons[gBankAttacker].pp[gCurrMovePos] -= ppToDeduct; - else - gBattleMons[gBankAttacker].pp[gCurrMovePos] = 0; - - if (!(gBattleMons[gBankAttacker].status2 & STATUS2_TRANSFORMED) - && !((gDisableStructs[gBankAttacker].unk18_b) & gBitTable[gCurrMovePos])) - { - gActiveBank = gBankAttacker; - EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + gCurrMovePos, 0, 1, &gBattleMons[gBankAttacker].pp[gCurrMovePos]); - MarkBufferBankForExecution(gBankAttacker); - } - } - - gHitMarker &= ~(HITMARKER_NO_PPDEDUCT); - gBattlescriptCurrInstr++; -} - -static void atk04_critcalc(void) -{ - u8 holdEffect; - u16 item, critChance; - - item = gBattleMons[gBankAttacker].item; - - if (item == ITEM_ENIGMA_BERRY) - holdEffect = gEnigmaBerries[gBankAttacker].holdEffect; - else - holdEffect = ItemId_GetHoldEffect(item); - - gStringBank = gBankAttacker; - - critChance = 2 * ((gBattleMons[gBankAttacker].status2 & STATUS2_FOCUS_ENERGY) != 0) - + (gBattleMoves[gCurrentMove].effect == EFFECT_HIGH_CRITICAL) - + (gBattleMoves[gCurrentMove].effect == EFFECT_SKY_ATTACK) - + (gBattleMoves[gCurrentMove].effect == EFFECT_BLAZE_KICK) - + (gBattleMoves[gCurrentMove].effect == EFFECT_POISON_TAIL) - + (holdEffect == HOLD_EFFECT_SCOPE_LENS) - + 2 * (holdEffect == HOLD_EFFECT_LUCKY_PUNCH && gBattleMons[gBankAttacker].species == SPECIES_CHANSEY) - + 2 * (holdEffect == HOLD_EFFECT_STICK && gBattleMons[gBankAttacker].species == SPECIES_FARFETCHD); - - if (critChance > 4) - critChance = 4; - - if ((gBattleMons[gBankTarget].ability != ABILITY_BATTLE_ARMOR && gBattleMons[gBankTarget].ability != ABILITY_SHELL_ARMOR) - && !(gStatuses3[gBankAttacker] & STATUS3_CANT_SCORE_A_CRIT) - && !(gBattleTypeFlags & (BATTLE_TYPE_WALLY_TUTORIAL | BATTLE_TYPE_FIRST_BATTLE)) - && !(Random() % sCriticalHitChance[critChance])) - gCritMultiplier = 2; - else - gCritMultiplier = 1; - - gBattlescriptCurrInstr++; -} - -static void atk05_damagecalc1(void) -{ - u16 sideStatus = gSideAffecting[GET_BANK_SIDE(gBankTarget)]; - gBattleMoveDamage = CalculateBaseDamage(&gBattleMons[gBankAttacker], &gBattleMons[gBankTarget], gCurrentMove, - sideStatus, gDynamicBasePower, - gBattleStruct->dynamicMoveType, gBankAttacker, gBankTarget); - gBattleMoveDamage = gBattleMoveDamage * gCritMultiplier * gBattleScripting.dmgMultiplier; - - if (gStatuses3[gBankAttacker] & STATUS3_CHARGED_UP && gBattleMoves[gCurrentMove].type == TYPE_ELECTRIC) - gBattleMoveDamage *= 2; - if (gProtectStructs[gBankAttacker].helpingHand) - gBattleMoveDamage = gBattleMoveDamage * 15 / 10; - - gBattlescriptCurrInstr++; -} - -void AI_CalcDmg(u8 bankAtk, u8 bankDef) -{ - u16 sideStatus = gSideAffecting[GET_BANK_SIDE(bankDef)]; - gBattleMoveDamage = CalculateBaseDamage(&gBattleMons[bankAtk], &gBattleMons[bankDef], gCurrentMove, - sideStatus, gDynamicBasePower, - gBattleStruct->dynamicMoveType, bankAtk, bankDef); - gDynamicBasePower = 0; - gBattleMoveDamage = gBattleMoveDamage * gCritMultiplier * gBattleScripting.dmgMultiplier; - - if (gStatuses3[bankAtk] & STATUS3_CHARGED_UP && gBattleMoves[gCurrentMove].type == TYPE_ELECTRIC) - gBattleMoveDamage *= 2; - if (gProtectStructs[bankAtk].helpingHand) - gBattleMoveDamage = gBattleMoveDamage * 15 / 10; -} - -static void ModulateDmgByType(u8 multiplier) -{ - gBattleMoveDamage = gBattleMoveDamage * multiplier / 10; - if (gBattleMoveDamage == 0 && multiplier != 0) - gBattleMoveDamage = 1; - - switch (multiplier) - { - case TYPE_MUL_NO_EFFECT: - gBattleMoveFlags |= MOVESTATUS_NOTAFFECTED; - gBattleMoveFlags &= ~MOVESTATUS_NOTVERYEFFECTIVE; - gBattleMoveFlags &= ~MOVESTATUS_SUPEREFFECTIVE; - break; - case TYPE_MUL_NOT_EFFECTIVE: - if (gBattleMoves[gCurrentMove].power && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) - { - if (gBattleMoveFlags & MOVESTATUS_SUPEREFFECTIVE) - gBattleMoveFlags &= ~MOVESTATUS_SUPEREFFECTIVE; - else - gBattleMoveFlags |= MOVESTATUS_NOTVERYEFFECTIVE; - } - break; - case TYPE_MUL_SUPER_EFFECTIVE: - if (gBattleMoves[gCurrentMove].power && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) - { - if (gBattleMoveFlags & MOVESTATUS_NOTVERYEFFECTIVE) - gBattleMoveFlags &= ~MOVESTATUS_NOTVERYEFFECTIVE; - else - gBattleMoveFlags |= MOVESTATUS_SUPEREFFECTIVE; - } - break; - } -} - -#define TYPE_FORESIGHT 0xFE -#define TYPE_ENDTABLE 0xFF - -static void atk06_typecalc(void) -{ - s32 i = 0; - u8 moveType; - - if (gCurrentMove == MOVE_STRUGGLE) - { - gBattlescriptCurrInstr++; - return; - } - - GET_MOVE_TYPE(gCurrentMove, moveType); - - // check stab - if (gBattleMons[gBankAttacker].type1 == moveType || gBattleMons[gBankAttacker].type2 == moveType) - { - gBattleMoveDamage = gBattleMoveDamage * 15; - gBattleMoveDamage = gBattleMoveDamage / 10; - } - - if (gBattleMons[gBankTarget].ability == ABILITY_LEVITATE && moveType == TYPE_GROUND) - { - gLastUsedAbility = gBattleMons[gBankTarget].ability; - gBattleMoveFlags |= (MOVESTATUS_MISSED | MOVESTATUS_NOTAFFECTED); - gUnknown_02024250[gBankTarget] = 0; - gUnknown_02024258[gBankTarget] = 0; - gBattleCommunication[6] = moveType; - RecordAbilityBattle(gBankTarget, gLastUsedAbility); - } - else - { - while (gTypeEffectiveness[i] != TYPE_ENDTABLE) - { - if (gTypeEffectiveness[i] == TYPE_FORESIGHT) - { - if (gBattleMons[gBankTarget].status2 & STATUS2_FORESIGHT) - break; - i += 3; - continue; - } - else if (gTypeEffectiveness[i] == moveType) - { - // check type1 - if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type1) - ModulateDmgByType(gTypeEffectiveness[i + 2]); - // check type2 - if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type2 && - gBattleMons[gBankTarget].type1 != gBattleMons[gBankTarget].type2) - ModulateDmgByType(gTypeEffectiveness[i + 2]); - } - i += 3; - } - } - - if (gBattleMons[gBankTarget].ability == ABILITY_WONDER_GUARD && AttacksThisTurn(gBankAttacker, gCurrentMove) == 2 - && (!(gBattleMoveFlags & MOVESTATUS_SUPEREFFECTIVE) || ((gBattleMoveFlags & (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE)) == (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE))) - && gBattleMoves[gCurrentMove].power) - { - gLastUsedAbility = ABILITY_WONDER_GUARD; - gBattleMoveFlags |= MOVESTATUS_MISSED; - gUnknown_02024250[gBankTarget] = 0; - gUnknown_02024258[gBankTarget] = 0; - gBattleCommunication[6] = 3; - RecordAbilityBattle(gBankTarget, gLastUsedAbility); - } - if (gBattleMoveFlags & MOVESTATUS_NOTAFFECTED) - gProtectStructs[gBankAttacker].notEffective = 1; - - gBattlescriptCurrInstr++; -} - -static void CheckWonderGuardAndLevitate(void) -{ - u8 flags = 0; - s32 i = 0; - u8 moveType; - - if (gCurrentMove == MOVE_STRUGGLE || !gBattleMoves[gCurrentMove].power) - return; - - GET_MOVE_TYPE(gCurrentMove, moveType); - - if (gBattleMons[gBankTarget].ability == ABILITY_LEVITATE && moveType == TYPE_GROUND) - { - gLastUsedAbility = ABILITY_LEVITATE; - gBattleCommunication[6] = moveType; - RecordAbilityBattle(gBankTarget, ABILITY_LEVITATE); - return; - } - - while (gTypeEffectiveness[i] != TYPE_ENDTABLE) - { - if (gTypeEffectiveness[i] == TYPE_FORESIGHT) - { - if (gBattleMons[gBankTarget].status2 & STATUS2_FORESIGHT) - break; - i += 3; - continue; - } - if (gTypeEffectiveness[i] == moveType) - { - // check no effect - if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type1 && gTypeEffectiveness[i + 2] == 0) - { - gBattleMoveFlags |= MOVESTATUS_NOTAFFECTED; - gProtectStructs[gBankAttacker].notEffective = 1; - } - if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type2 && - gBattleMons[gBankTarget].type1 != gBattleMons[gBankTarget].type2 && - gTypeEffectiveness[i + 2] == TYPE_MUL_NO_EFFECT) - { - gBattleMoveFlags |= MOVESTATUS_NOTAFFECTED; - gProtectStructs[gBankAttacker].notEffective = 1; - } - - // check super effective - if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type1 && gTypeEffectiveness[i + 2] == 20) - flags |= 1; - if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type2 - && gBattleMons[gBankTarget].type1 != gBattleMons[gBankTarget].type2 - && gTypeEffectiveness[i + 2] == TYPE_MUL_SUPER_EFFECTIVE) - flags |= 1; - - // check not very effective - if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type1 && gTypeEffectiveness[i + 2] == 5) - flags |= 2; - if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type2 - && gBattleMons[gBankTarget].type1 != gBattleMons[gBankTarget].type2 - && gTypeEffectiveness[i + 2] == TYPE_MUL_NOT_EFFECTIVE) - flags |= 2; - } - i += 3; - } - - if (gBattleMons[gBankTarget].ability == ABILITY_WONDER_GUARD && AttacksThisTurn(gBankAttacker, gCurrentMove) == 2) - { - if (((flags & 2) || !(flags & 1)) && gBattleMoves[gCurrentMove].power) - { - gLastUsedAbility = ABILITY_WONDER_GUARD; - gBattleCommunication[6] = 3; - RecordAbilityBattle(gBankTarget, ABILITY_WONDER_GUARD); - } - } -} - -static void ModulateDmgByType2(u8 multiplier, u16 move, u8* flags) // same as ModulateDmgByType except different arguments -{ - gBattleMoveDamage = gBattleMoveDamage * multiplier / 10; - if (gBattleMoveDamage == 0 && multiplier != 0) - gBattleMoveDamage = 1; - - switch (multiplier) - { - case TYPE_MUL_NO_EFFECT: - *flags |= MOVESTATUS_NOTAFFECTED; - *flags &= ~MOVESTATUS_NOTVERYEFFECTIVE; - *flags &= ~MOVESTATUS_SUPEREFFECTIVE; - break; - case TYPE_MUL_NOT_EFFECTIVE: - if (gBattleMoves[move].power && !(*flags & MOVESTATUS_NOEFFECT)) - { - if (*flags & MOVESTATUS_SUPEREFFECTIVE) - *flags &= ~MOVESTATUS_SUPEREFFECTIVE; - else - *flags |= MOVESTATUS_NOTVERYEFFECTIVE; - } - break; - case TYPE_MUL_SUPER_EFFECTIVE: - if (gBattleMoves[move].power && !(*flags & MOVESTATUS_NOEFFECT)) - { - if (*flags & MOVESTATUS_NOTVERYEFFECTIVE) - *flags &= ~MOVESTATUS_NOTVERYEFFECTIVE; - else - *flags |= MOVESTATUS_SUPEREFFECTIVE; - } - break; - } -} - -u8 TypeCalc(u16 move, u8 bankAtk, u8 bankDef) -{ - s32 i = 0; - u8 flags = 0; - u8 moveType; - - if (move == MOVE_STRUGGLE) - return 0; - - moveType = gBattleMoves[move].type; - - // check stab - if (gBattleMons[bankAtk].type1 == moveType || gBattleMons[bankAtk].type2 == moveType) - { - gBattleMoveDamage = gBattleMoveDamage * 15; - gBattleMoveDamage = gBattleMoveDamage / 10; - } - - if (gBattleMons[bankDef].ability == ABILITY_LEVITATE && moveType == TYPE_GROUND) - { - flags |= (MOVESTATUS_MISSED | MOVESTATUS_NOTAFFECTED); - } - else - { - while (gTypeEffectiveness[i]!= TYPE_ENDTABLE) - { - if (gTypeEffectiveness[i] == TYPE_FORESIGHT) - { - if (gBattleMons[bankDef].status2 & STATUS2_FORESIGHT) - break; - i += 3; - continue; - } - - else if (gTypeEffectiveness[i] == moveType) - { - // check type1 - if (gTypeEffectiveness[i + 1] == gBattleMons[bankDef].type1) - ModulateDmgByType2(gTypeEffectiveness[i + 2], move, &flags); - // check type2 - if (gTypeEffectiveness[i + 1] == gBattleMons[bankDef].type2 && - gBattleMons[bankDef].type1 != gBattleMons[bankDef].type2) - ModulateDmgByType2(gTypeEffectiveness[i + 2], move, &flags); - } - i += 3; - } - } - - if (gBattleMons[bankDef].ability == ABILITY_WONDER_GUARD && !(flags & MOVESTATUS_MISSED) - && AttacksThisTurn(bankAtk, move) == 2 - && (!(flags & MOVESTATUS_SUPEREFFECTIVE) || ((flags & (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE)) == (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE))) - && gBattleMoves[move].power) - { - flags |= MOVESTATUS_MISSED; - } - return flags; -} - -u8 AI_TypeCalc(u16 move, u16 species, u8 ability) -{ - s32 i = 0; - u8 flags = 0; - u8 type1 = gBaseStats[species].type1, type2 = gBaseStats[species].type2; - u8 moveType; - - if (move == MOVE_STRUGGLE) - return 0; - - moveType = gBattleMoves[move].type; - - if (ability == ABILITY_LEVITATE && moveType == TYPE_GROUND) - { - flags = MOVESTATUS_MISSED | MOVESTATUS_NOTAFFECTED; - } - else - { - while (gTypeEffectiveness[i] != TYPE_ENDTABLE) - { - if (gTypeEffectiveness[i] == TYPE_FORESIGHT) - { - i += 3; - continue; - } - if (gTypeEffectiveness[i] == moveType) - { - // check type1 - if (gTypeEffectiveness[i + 1] == type1) - ModulateDmgByType2(gTypeEffectiveness[i + 2], move, &flags); - // check type2 - if (gTypeEffectiveness[i + 1] == type2 && type1 != type2) - ModulateDmgByType2(gTypeEffectiveness[i + 2], move, &flags); - } - i += 3; - } - } - if (ability == ABILITY_WONDER_GUARD - && (!(flags & MOVESTATUS_SUPEREFFECTIVE) || ((flags & (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE)) == (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE))) - && gBattleMoves[move].power) - flags |= MOVESTATUS_NOTAFFECTED; - return flags; -} - -// Multiplies the damage by a random factor between 85% to 100% inclusive -static inline void ApplyRandomDmgMultiplier(void) -{ - u16 rand = Random(); - u16 randPercent = 100 - (rand % 16); - - if (gBattleMoveDamage != 0) - { - gBattleMoveDamage *= randPercent; - gBattleMoveDamage /= 100; - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - } -} - -static void Unused_ApplyRandomDmgMultiplier(void) -{ - ApplyRandomDmgMultiplier(); -} - -static void atk07_dmg_adjustment(void) -{ - u8 holdEffect, quality; - - ApplyRandomDmgMultiplier(); - - if (gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY) - { - holdEffect = gEnigmaBerries[gBankTarget].holdEffect, quality = gEnigmaBerries[gBankTarget].holdEffectParam; - } - else - { - holdEffect = ItemId_GetHoldEffect(gBattleMons[gBankTarget].item); - quality = ItemId_GetHoldEffectParam(gBattleMons[gBankTarget].item); - } - - gStringBank = gBankTarget; - - if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < quality) - { - RecordItemEffectBattle(gBankTarget, holdEffect); - gSpecialStatuses[gBankTarget].focusBanded = 1; - } - if (gBattleMons[gBankTarget].status2 & STATUS2_SUBSTITUTE) - goto END; - if (gBattleMoves[gCurrentMove].effect != EFFECT_FALSE_SWIPE && !gProtectStructs[gBankTarget].endured - && !gSpecialStatuses[gBankTarget].focusBanded) - goto END; - - if (gBattleMons[gBankTarget].hp > gBattleMoveDamage) - goto END; - - gBattleMoveDamage = gBattleMons[gBankTarget].hp - 1; - - if (gProtectStructs[gBankTarget].endured) - { - gBattleMoveFlags |= MOVESTATUS_ENDURED; - } - else if (gSpecialStatuses[gBankTarget].focusBanded) - { - gBattleMoveFlags |= MOVESTATUS_HUNGON; - gLastUsedItem = gBattleMons[gBankTarget].item; - } - - END: - gBattlescriptCurrInstr++; -} - -static void atk08_dmg_adjustment2(void) // The same as 0x7 except it doesn't check for false swipe move effect. -{ - u8 holdEffect, quality; - - ApplyRandomDmgMultiplier(); - - if (gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY) - { - holdEffect = gEnigmaBerries[gBankTarget].holdEffect, quality = gEnigmaBerries[gBankTarget].holdEffectParam; - } - else - { - holdEffect = ItemId_GetHoldEffect(gBattleMons[gBankTarget].item); - quality = ItemId_GetHoldEffectParam(gBattleMons[gBankTarget].item); - } - - gStringBank = gBankTarget; - - if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < quality) - { - RecordItemEffectBattle(gBankTarget, holdEffect); - gSpecialStatuses[gBankTarget].focusBanded = 1; - } - if (gBattleMons[gBankTarget].status2 & STATUS2_SUBSTITUTE) - goto END; - if (!gProtectStructs[gBankTarget].endured && !gSpecialStatuses[gBankTarget].focusBanded) - goto END; - if (gBattleMons[gBankTarget].hp > gBattleMoveDamage) - goto END; - - gBattleMoveDamage = gBattleMons[gBankTarget].hp - 1; - - if (gProtectStructs[gBankTarget].endured) - { - gBattleMoveFlags |= MOVESTATUS_ENDURED; - } - else if (gSpecialStatuses[gBankTarget].focusBanded) - { - gBattleMoveFlags |= MOVESTATUS_HUNGON; - gLastUsedItem = gBattleMons[gBankTarget].item; - } - - END: - gBattlescriptCurrInstr++; -} - -static void atk09_attackanimation(void) -{ - if (gBattleExecBuffer) - return; - - if ((gHitMarker & HITMARKER_NO_ANIMATIONS) && (gCurrentMove != MOVE_TRANSFORM && gCurrentMove != MOVE_SUBSTITUTE)) - { - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_Pausex20; - gBattleScripting.animTurn++; - gBattleScripting.animTargetsHit++; - } - else - { - if ((gBattleMoves[gCurrentMove].target & MOVE_TARGET_BOTH - || gBattleMoves[gCurrentMove].target & MOVE_TARGET_FOES_AND_ALLY - || gBattleMoves[gCurrentMove].target & MOVE_TARGET_DEPENDS) - && gBattleScripting.animTargetsHit) - { - gBattlescriptCurrInstr++; - return; - } - if (!(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) - { - u8 multihit; - - gActiveBank = gBankAttacker; - - if (gBattleMons[gBankTarget].status2 & STATUS2_SUBSTITUTE) - multihit = gMultiHitCounter; - else if (gMultiHitCounter != 0 && gMultiHitCounter != 1) - { - if (gBattleMons[gBankTarget].hp <= gBattleMoveDamage) - multihit = 1; - else - multihit = gMultiHitCounter; - } - else - multihit = gMultiHitCounter; - - EmitMoveAnimation(0, gCurrentMove, gBattleScripting.animTurn, gBattleMovePower, gBattleMoveDamage, gBattleMons[gBankAttacker].friendship, &gDisableStructs[gBankAttacker], multihit); - gBattleScripting.animTurn += 1; - gBattleScripting.animTargetsHit += 1; - MarkBufferBankForExecution(gBankAttacker); - gBattlescriptCurrInstr++; - } - else - { - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_Pausex20; - } - } -} - -static void atk0A_waitanimation(void) -{ - if (gBattleExecBuffer == 0) - gBattlescriptCurrInstr++; -} - -static void atk0B_healthbarupdate(void) -{ - if (gBattleExecBuffer) - return; - - if (!(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) - { - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - - if (gBattleMons[gActiveBank].status2 & STATUS2_SUBSTITUTE && gDisableStructs[gActiveBank].substituteHP && !(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE)) - { - PrepareStringBattle(0x80, gActiveBank); - } - else - { - s16 healthValue; - - s32 currDmg = gBattleMoveDamage; - s32 maxPossibleDmgValue = 10000; // not present in R/S, ensures that huge damage values don't change sign - - if (currDmg <= maxPossibleDmgValue) - healthValue = currDmg; - else - healthValue = maxPossibleDmgValue; - - EmitHealthBarUpdate(0, healthValue); - MarkBufferBankForExecution(gActiveBank); - - if (GetBankSide(gActiveBank) == SIDE_PLAYER && gBattleMoveDamage > 0) - gBattleResults.unk5_0 = 1; - } - } - - gBattlescriptCurrInstr += 2; -} - -static void atk0C_datahpupdate(void) -{ - u32 moveType; - - if (gBattleExecBuffer) - return; - - if (gBattleStruct->dynamicMoveType == 0) - moveType = gBattleMoves[gCurrentMove].type; - else if (!(gBattleStruct->dynamicMoveType & 0x40)) - moveType = gBattleStruct->dynamicMoveType & 0x3F; - else - moveType = gBattleMoves[gCurrentMove].type; - - if (!(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) - { - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - if (gBattleMons[gActiveBank].status2 & STATUS2_SUBSTITUTE && gDisableStructs[gActiveBank].substituteHP && !(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE)) - { - if (gDisableStructs[gActiveBank].substituteHP >= gBattleMoveDamage) - { - if (gSpecialStatuses[gActiveBank].moveturnLostHP == 0) - gSpecialStatuses[gActiveBank].moveturnLostHP = gBattleMoveDamage; - gDisableStructs[gActiveBank].substituteHP -= gBattleMoveDamage; - gHpDealt = gBattleMoveDamage; - } - else - { - if (gSpecialStatuses[gActiveBank].moveturnLostHP == 0) - gSpecialStatuses[gActiveBank].moveturnLostHP = gDisableStructs[gActiveBank].substituteHP; - gHpDealt = gDisableStructs[gActiveBank].substituteHP; - gDisableStructs[gActiveBank].substituteHP = 0; - } - // check substitute fading - if (gDisableStructs[gActiveBank].substituteHP == 0) - { - gBattlescriptCurrInstr += 2; - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_SubstituteFade; - return; - } - } - else - { - gHitMarker &= ~(HITMARKER_IGNORE_SUBSTITUTE); - if (gBattleMoveDamage < 0) // hp goes up - { - gBattleMons[gActiveBank].hp -= gBattleMoveDamage; - if (gBattleMons[gActiveBank].hp > gBattleMons[gActiveBank].maxHP) - gBattleMons[gActiveBank].hp = gBattleMons[gActiveBank].maxHP; - - } - else // hp goes down - { - if (gHitMarker & HITMARKER_x20) - { - gHitMarker &= ~(HITMARKER_x20); - } - else - { - gTakenDmg[gActiveBank] += gBattleMoveDamage; - if (gBattlescriptCurrInstr[1] == BS_GET_TARGET) - gTakenDmgBanks[gActiveBank] = gBankAttacker; - else - gTakenDmgBanks[gActiveBank] = gBankTarget; - } - - if (gBattleMons[gActiveBank].hp > gBattleMoveDamage) - { - gBattleMons[gActiveBank].hp -= gBattleMoveDamage; - gHpDealt = gBattleMoveDamage; - } - else - { - gHpDealt = gBattleMons[gActiveBank].hp; - gBattleMons[gActiveBank].hp = 0; - } - - if (!gSpecialStatuses[gActiveBank].moveturnLostHP && !(gHitMarker & HITMARKER_x100000)) - gSpecialStatuses[gActiveBank].moveturnLostHP = gHpDealt; - - if (moveType <= 8 && !(gHitMarker & HITMARKER_x100000) && gCurrentMove != MOVE_PAIN_SPLIT) - { - gProtectStructs[gActiveBank].physicalDmg = gHpDealt; - gSpecialStatuses[gActiveBank].moveturnLostHP_physical = gHpDealt; - if (gBattlescriptCurrInstr[1] == BS_GET_TARGET) - { - gProtectStructs[gActiveBank].physicalBank = gBankAttacker; - gSpecialStatuses[gActiveBank].moveturnPhysicalBank = gBankAttacker; - } - else - { - gProtectStructs[gActiveBank].physicalBank = gBankTarget; - gSpecialStatuses[gActiveBank].moveturnPhysicalBank = gBankTarget; - } - } - else if (moveType > 8 && !(gHitMarker & HITMARKER_x100000)) - { - gProtectStructs[gActiveBank].specialDmg = gHpDealt; - gSpecialStatuses[gActiveBank].moveturnLostHP_special = gHpDealt; - if (gBattlescriptCurrInstr[1] == BS_GET_TARGET) - { - gProtectStructs[gActiveBank].specialBank = gBankAttacker; - gSpecialStatuses[gActiveBank].moveturnSpecialBank = gBankAttacker; - } - else - { - gProtectStructs[gActiveBank].specialBank = gBankTarget; - gSpecialStatuses[gActiveBank].moveturnSpecialBank = gBankTarget; - } - } - } - gHitMarker &= ~(HITMARKER_x100000); - EmitSetMonData(0, REQUEST_HP_BATTLE, 0, 2, &gBattleMons[gActiveBank].hp); - MarkBufferBankForExecution(gActiveBank); - } - } - else - { - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - if (gSpecialStatuses[gActiveBank].moveturnLostHP == 0) - gSpecialStatuses[gActiveBank].moveturnLostHP = 0xFFFF; - } - gBattlescriptCurrInstr += 2; -} - -static void atk0D_critmessage(void) -{ - if (gBattleExecBuffer == 0) - { - if (gCritMultiplier == 2 && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) - { - PrepareStringBattle(0xD9, gBankAttacker); - gBattleCommunication[MSG_DISPLAY] = 1; - } - gBattlescriptCurrInstr++; - } -} - -static void atk0E_effectiveness_sound(void) -{ - if (gBattleExecBuffer) - return; - - gActiveBank = gBankTarget; - if (!(gBattleMoveFlags & MOVESTATUS_MISSED)) - { - switch (gBattleMoveFlags & (u8)(~(MOVESTATUS_MISSED))) - { - case MOVESTATUS_SUPEREFFECTIVE: - EmitEffectivenessSound(0, SE_KOUKA_H); - MarkBufferBankForExecution(gActiveBank); - break; - case MOVESTATUS_NOTVERYEFFECTIVE: - EmitEffectivenessSound(0, SE_KOUKA_L); - MarkBufferBankForExecution(gActiveBank); - break; - case MOVESTATUS_NOTAFFECTED: - case MOVESTATUS_FAILED: - // no sound - break; - case MOVESTATUS_ENDURED: - case MOVESTATUS_ONEHITKO: - case MOVESTATUS_HUNGON: - default: - if (gBattleMoveFlags & MOVESTATUS_SUPEREFFECTIVE) - { - EmitEffectivenessSound(0, SE_KOUKA_H); - MarkBufferBankForExecution(gActiveBank); - } - else if (gBattleMoveFlags & MOVESTATUS_NOTVERYEFFECTIVE) - { - EmitEffectivenessSound(0, SE_KOUKA_L); - MarkBufferBankForExecution(gActiveBank); - } - else if (!(gBattleMoveFlags & (MOVESTATUS_NOTAFFECTED | MOVESTATUS_FAILED))) - { - EmitEffectivenessSound(0, SE_KOUKA_M); - MarkBufferBankForExecution(gActiveBank); - } - break; - } - } - gBattlescriptCurrInstr++; -} - -static void atk0F_resultmessage(void) -{ - u32 stringId = 0; - - if (gBattleExecBuffer) - return; - - if (gBattleMoveFlags & MOVESTATUS_MISSED && (!(gBattleMoveFlags & MOVESTATUS_NOTAFFECTED) || gBattleCommunication[6] > 2)) - { - stringId = gMissStringIds[gBattleCommunication[6]]; - gBattleCommunication[MSG_DISPLAY] = 1; - } - else - { - gBattleCommunication[MSG_DISPLAY] = 1; - switch (gBattleMoveFlags & (u8)(~(MOVESTATUS_MISSED))) - { - case MOVESTATUS_SUPEREFFECTIVE: - stringId = 0xDE; - break; - case MOVESTATUS_NOTVERYEFFECTIVE: - stringId = 0xDD; - break; - case MOVESTATUS_ONEHITKO: - stringId = 0xDA; - break; - case MOVESTATUS_ENDURED: - stringId = 0x99; - break; - case MOVESTATUS_FAILED: - stringId = 0xE5; - break; - case MOVESTATUS_NOTAFFECTED: - stringId = 0x1B; - break; - case MOVESTATUS_HUNGON: - gLastUsedItem = gBattleMons[gBankTarget].item; - gStringBank = gBankTarget; - gBattleMoveFlags &= ~(MOVESTATUS_ENDURED | MOVESTATUS_HUNGON); - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_HangedOnMsg; - return; - default: - if (gBattleMoveFlags & MOVESTATUS_NOTAFFECTED) - { - stringId = 0x1B; - } - else if (gBattleMoveFlags & MOVESTATUS_ONEHITKO) - { - gBattleMoveFlags &= ~(MOVESTATUS_ONEHITKO); - gBattleMoveFlags &= ~(MOVESTATUS_SUPEREFFECTIVE); - gBattleMoveFlags &= ~(MOVESTATUS_NOTVERYEFFECTIVE); - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_OneHitKOMsg; - return; - } - else if (gBattleMoveFlags & MOVESTATUS_ENDURED) - { - gBattleMoveFlags &= ~(MOVESTATUS_ENDURED | MOVESTATUS_HUNGON); - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_EnduredMsg; - return; - } - else if (gBattleMoveFlags & MOVESTATUS_HUNGON) - { - gLastUsedItem = gBattleMons[gBankTarget].item; - gStringBank = gBankTarget; - gBattleMoveFlags &= ~(MOVESTATUS_ENDURED | MOVESTATUS_HUNGON); - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_HangedOnMsg; - return; - } - else if (gBattleMoveFlags & MOVESTATUS_FAILED) - { - stringId = 0xE5; - } - else - { - gBattleCommunication[MSG_DISPLAY] = 0; - } - } - } - - if (stringId) - PrepareStringBattle(stringId, gBankAttacker); - - gBattlescriptCurrInstr++; -} - -static void atk10_printstring(void) -{ - if (gBattleExecBuffer == 0) - { - u16 var = BS2ScriptRead16(gBattlescriptCurrInstr + 1); - PrepareStringBattle(var, gBankAttacker); - gBattlescriptCurrInstr += 3; - gBattleCommunication[MSG_DISPLAY] = 1; - } -} - -static void atk11_printstring_playeronly(void) -{ - gActiveBank = gBankAttacker; - - EmitPrintStringPlayerOnly(0, BS2ScriptRead16(gBattlescriptCurrInstr + 1)); - MarkBufferBankForExecution(gActiveBank); - - gBattlescriptCurrInstr += 3; - gBattleCommunication[MSG_DISPLAY] = 1; -} - -static void atk12_waitmessage(void) -{ - if (gBattleExecBuffer == 0) - { - if (!gBattleCommunication[MSG_DISPLAY]) - { - gBattlescriptCurrInstr += 3; - } - else - { - u16 toWait = BS2ScriptRead16(gBattlescriptCurrInstr + 1); - if (++gPauseCounterBattle >= toWait) - { - gPauseCounterBattle = 0; - gBattlescriptCurrInstr += 3; - gBattleCommunication[MSG_DISPLAY] = 0; - } - } - } -} - -static void atk13_printfromtable(void) -{ - if (gBattleExecBuffer == 0) - { - const u16 *ptr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - ptr += gBattleCommunication[MULTISTRING_CHOOSER]; - - PrepareStringBattle(*ptr, gBankAttacker); - - gBattlescriptCurrInstr += 5; - gBattleCommunication[MSG_DISPLAY] = 1; - } -} - -static void atk14_printfromtable_playeronly(void) -{ - if (gBattleExecBuffer == 0) - { - const u16 *ptr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - ptr += gBattleCommunication[MULTISTRING_CHOOSER]; - - gActiveBank = gBankAttacker; - EmitPrintStringPlayerOnly(0, *ptr); - MarkBufferBankForExecution(gActiveBank); - - gBattlescriptCurrInstr += 5; - gBattleCommunication[MSG_DISPLAY] = 1; - } -} - -u8 BankGetTurnOrder(u8 bank) -{ - s32 i; - for (i = 0; i < gNoOfAllBanks; i++) - { - if (gTurnOrder[i] == bank) - break; - } - return i; -} - -#define INCREMENT_RESET_RETURN \ -{ \ - gBattlescriptCurrInstr++; \ - gBattleCommunication[MOVE_EFFECT_BYTE] = 0; \ - return; \ -} - -#define RESET_RETURN \ -{ \ - gBattleCommunication[MOVE_EFFECT_BYTE] = 0; \ - return; \ -} - -void SetMoveEffect(bool8 primary, u8 certain) -{ - bool32 statusChanged = FALSE; - u8 affectsUser = 0; // 0x40 otherwise - bool32 noSunCanFreeze = TRUE; - - if (gBattleCommunication[MOVE_EFFECT_BYTE] & MOVE_EFFECT_AFFECTS_USER) - { - gEffectBank = gBankAttacker; // bank that effects get applied on - gBattleCommunication[MOVE_EFFECT_BYTE] &= ~(MOVE_EFFECT_AFFECTS_USER); - affectsUser = MOVE_EFFECT_AFFECTS_USER; - gBattleScripting.bank = gBankTarget; // theoretically the attacker - } - else - { - gEffectBank = gBankTarget; - gBattleScripting.bank = gBankAttacker; - } - - if (gBattleMons[gEffectBank].ability == ABILITY_SHIELD_DUST && !(gHitMarker & HITMARKER_IGNORE_SAFEGUARD) - && !primary && gBattleCommunication[MOVE_EFFECT_BYTE] <= 9) - INCREMENT_RESET_RETURN - - if (gSideAffecting[GET_BANK_SIDE(gEffectBank)] & SIDE_STATUS_SAFEGUARD && !(gHitMarker & HITMARKER_IGNORE_SAFEGUARD) - && !primary && gBattleCommunication[MOVE_EFFECT_BYTE] <= 7) - INCREMENT_RESET_RETURN - - if (gBattleMons[gEffectBank].hp == 0 - && gBattleCommunication[MOVE_EFFECT_BYTE] != MOVE_EFFECT_PAYDAY - && gBattleCommunication[MOVE_EFFECT_BYTE] != MOVE_EFFECT_STEAL_ITEM) - INCREMENT_RESET_RETURN - - if (gBattleMons[gEffectBank].status2 & STATUS2_SUBSTITUTE && affectsUser != MOVE_EFFECT_AFFECTS_USER) - INCREMENT_RESET_RETURN - - if (gBattleCommunication[MOVE_EFFECT_BYTE] <= 6) // status change - { - switch (sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]) - { - case STATUS_SLEEP: - // check active uproar - if (gBattleMons[gEffectBank].ability != ABILITY_SOUNDPROOF) - { - for (gActiveBank = 0; - gActiveBank < gNoOfAllBanks && !(gBattleMons[gActiveBank].status2 & STATUS2_UPROAR); - gActiveBank++) - {} - } - else - gActiveBank = gNoOfAllBanks; - - if (gBattleMons[gEffectBank].status1) - break; - if (gActiveBank != gNoOfAllBanks) - break; - if (gBattleMons[gEffectBank].ability == ABILITY_VITAL_SPIRIT) - break; - if (gBattleMons[gEffectBank].ability == ABILITY_INSOMNIA) - break; - - CancelMultiTurnMoves(gEffectBank); - statusChanged = TRUE; - break; - case STATUS_POISON: - if (gBattleMons[gEffectBank].ability == ABILITY_IMMUNITY - && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) - { - gLastUsedAbility = ABILITY_IMMUNITY; - RecordAbilityBattle(gEffectBank, ABILITY_IMMUNITY); - - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_PSNPrevention; - - if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) - { - gBattleCommunication[MULTISTRING_CHOOSER] = 1; - gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD); - } - else - { - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - } - RESET_RETURN - } - if ((gBattleMons[gEffectBank].type1 == TYPE_POISON || gBattleMons[gEffectBank].type2 == TYPE_POISON - || gBattleMons[gEffectBank].type1 == TYPE_STEEL || gBattleMons[gEffectBank].type2 == TYPE_STEEL) - && (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) - && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) - { - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_PSNPrevention; - - gBattleCommunication[MULTISTRING_CHOOSER] = 2; - RESET_RETURN - } - if (gBattleMons[gEffectBank].type1 == TYPE_POISON) - break; - if (gBattleMons[gEffectBank].type2 == TYPE_POISON) - break; - if (gBattleMons[gEffectBank].type1 == TYPE_STEEL) - break; - if (gBattleMons[gEffectBank].type2 == TYPE_STEEL) - break; - if (gBattleMons[gEffectBank].status1) - break; - if (gBattleMons[gEffectBank].ability == ABILITY_IMMUNITY) - break; - - statusChanged = TRUE; - break; - case STATUS_BURN: - if (gBattleMons[gEffectBank].ability == ABILITY_WATER_VEIL - && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) - { - gLastUsedAbility = ABILITY_WATER_VEIL; - RecordAbilityBattle(gEffectBank, ABILITY_WATER_VEIL); - - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_BRNPrevention; - if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) - { - gBattleCommunication[MULTISTRING_CHOOSER] = 1; - gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD); - } - else - { - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - } - RESET_RETURN - } - if ((gBattleMons[gEffectBank].type1 == TYPE_FIRE - || gBattleMons[gEffectBank].type2 == TYPE_FIRE) - && (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) - && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) - { - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_BRNPrevention; - - gBattleCommunication[MULTISTRING_CHOOSER] = 2; - RESET_RETURN - } - if (gBattleMons[gEffectBank].type1 == TYPE_FIRE) - break; - if (gBattleMons[gEffectBank].type2 == TYPE_FIRE) - break; - if (gBattleMons[gEffectBank].ability == ABILITY_WATER_VEIL) - break; - if (gBattleMons[gEffectBank].status1) - break; - - statusChanged = TRUE; - break; - case STATUS_FREEZE: - if (WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_SUN_ANY) - noSunCanFreeze = FALSE; - if (gBattleMons[gEffectBank].type1 == TYPE_ICE) - break; - if (gBattleMons[gEffectBank].type2 == TYPE_ICE) - break; - if (gBattleMons[gEffectBank].status1) - break; - if (noSunCanFreeze == 0) - break; - if (gBattleMons[gEffectBank].ability == ABILITY_MAGMA_ARMOR) - break; - - CancelMultiTurnMoves(gEffectBank); - statusChanged = TRUE; - break; - case STATUS_PARALYSIS: - if (gBattleMons[gEffectBank].ability == ABILITY_LIMBER) - { - if (primary == TRUE || certain == MOVE_EFFECT_CERTAIN) - { - gLastUsedAbility = ABILITY_LIMBER; - RecordAbilityBattle(gEffectBank, ABILITY_LIMBER); - - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_PRLZPrevention; - - if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) - { - gBattleCommunication[MULTISTRING_CHOOSER] = 1; - gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD); - } - else - { - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - } - RESET_RETURN - } - else - break; - } - if (gBattleMons[gEffectBank].status1) - break; - - statusChanged = TRUE; - break; - case STATUS_TOXIC_POISON: - if (gBattleMons[gEffectBank].ability == ABILITY_IMMUNITY && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) - { - gLastUsedAbility = ABILITY_IMMUNITY; - RecordAbilityBattle(gEffectBank, ABILITY_IMMUNITY); - - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_PSNPrevention; - - if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) - { - gBattleCommunication[MULTISTRING_CHOOSER] = 1; - gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD); - } - else - { - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - } - RESET_RETURN - } - if ((gBattleMons[gEffectBank].type1 == TYPE_POISON || gBattleMons[gEffectBank].type2 == TYPE_POISON - || gBattleMons[gEffectBank].type1 == TYPE_STEEL || gBattleMons[gEffectBank].type2 == TYPE_STEEL) - && (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) - && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) - { - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_PSNPrevention; - - gBattleCommunication[MULTISTRING_CHOOSER] = 2; - RESET_RETURN - } - if (gBattleMons[gEffectBank].status1) - break; - if (gBattleMons[gEffectBank].type1 != TYPE_POISON - && gBattleMons[gEffectBank].type2 != TYPE_POISON - && gBattleMons[gEffectBank].type1 != TYPE_STEEL - && gBattleMons[gEffectBank].type2 != TYPE_STEEL) - { - if (gBattleMons[gEffectBank].ability == ABILITY_IMMUNITY) - break; - - // It's redundant, because at this point we know the status1 value is 0. - gBattleMons[gEffectBank].status1 &= ~(STATUS_TOXIC_POISON); - gBattleMons[gEffectBank].status1 &= ~(STATUS_POISON); - statusChanged = TRUE; - break; - } - else - { - gBattleMoveFlags |= MOVESTATUS_NOTAFFECTED; - } - break; - } - if (statusChanged == TRUE) - { - BattleScriptPush(gBattlescriptCurrInstr + 1); - - if (sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]] == STATUS_SLEEP) - gBattleMons[gEffectBank].status1 |= ((Random() & 3) + 2); - else - gBattleMons[gEffectBank].status1 |= sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]; - - gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; - - gActiveBank = gEffectBank; - EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gEffectBank].status1); - MarkBufferBankForExecution(gActiveBank); - - if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) - { - gBattleCommunication[MULTISTRING_CHOOSER] = 1; - gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD); - } - else - { - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - } - - // for synchronize - - if (gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_POISON - || gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_TOXIC - || gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_PARALYSIS - || gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_BURN) - { - u8* synchronizeEffect = &gBattleStruct->synchronizeMoveEffect; - *synchronizeEffect = gBattleCommunication[MOVE_EFFECT_BYTE]; - gHitMarker |= HITMARKER_SYNCHRONISE_EFFECT; - } - return; - } - else if (statusChanged == FALSE) - { - gBattleCommunication[MOVE_EFFECT_BYTE] = 0; - gBattlescriptCurrInstr++; - return; - } - return; - } - else - { - if (gBattleMons[gEffectBank].status2 & sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]) - { - gBattlescriptCurrInstr++; - } - else - { - u8 side; - switch (gBattleCommunication[MOVE_EFFECT_BYTE]) - { - case MOVE_EFFECT_CONFUSION: - if (gBattleMons[gEffectBank].ability == ABILITY_OWN_TEMPO - || gBattleMons[gEffectBank].status2 & STATUS2_CONFUSION) - { - gBattlescriptCurrInstr++; - } - else - { - gBattleMons[gEffectBank].status2 |= (((Random()) % 0x4)) + 2; - - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; - } - break; - case MOVE_EFFECT_FLINCH: - if (gBattleMons[gEffectBank].ability == ABILITY_INNER_FOCUS) - { - if (primary == TRUE || certain == MOVE_EFFECT_CERTAIN) - { - gLastUsedAbility = ABILITY_INNER_FOCUS; - RecordAbilityBattle(gEffectBank, ABILITY_INNER_FOCUS); - gBattlescriptCurrInstr = BattleScript_FlinchPrevention; - } - else - { - gBattlescriptCurrInstr++; - } - } - else - { - if (BankGetTurnOrder(gEffectBank) > gCurrentMoveTurn) - gBattleMons[gEffectBank].status2 |= sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]; - gBattlescriptCurrInstr++; - } - break; - case MOVE_EFFECT_UPROAR: - if (!(gBattleMons[gEffectBank].status2 & STATUS2_UPROAR)) - { - - gBattleMons[gEffectBank].status2 |= STATUS2_MULTIPLETURNS; - gLockedMoves[gEffectBank] = gCurrentMove; - gBattleMons[gEffectBank].status2 |= ((Random() & 3) + 2) << 4; - - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; - } - else - { - gBattlescriptCurrInstr++; - } - break; - case MOVE_EFFECT_PAYDAY: - if (GET_BANK_SIDE(gBankAttacker) == SIDE_PLAYER) - { - u16 PayDay = gPaydayMoney; - gPaydayMoney += (gBattleMons[gBankAttacker].level * 5); - if (PayDay > gPaydayMoney) - gPaydayMoney = 0xFFFF; - } - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; - break; - case MOVE_EFFECT_TRI_ATTACK: - if (gBattleMons[gEffectBank].status1) - { - gBattlescriptCurrInstr++; - } - else - { - gBattleCommunication[MOVE_EFFECT_BYTE] = Random() % 3 + 3; - SetMoveEffect(FALSE, 0); - } - break; - case MOVE_EFFECT_CHARGING: - gBattleMons[gEffectBank].status2 |= STATUS2_MULTIPLETURNS; - gLockedMoves[gEffectBank] = gCurrentMove; - gProtectStructs[gEffectBank].chargingTurn = 1; - gBattlescriptCurrInstr++; - break; - case MOVE_EFFECT_WRAP: - if (gBattleMons[gEffectBank].status2 & STATUS2_WRAPPED) - { - gBattlescriptCurrInstr++; - } - else - { - gBattleMons[gEffectBank].status2 |= ((Random() & 3) + 3) << 0xD; - - *(gBattleStruct->wrappedMove + gEffectBank * 2 + 0) = gCurrentMove; - *(gBattleStruct->wrappedMove + gEffectBank * 2 + 1) = gCurrentMove >> 8; - *(gBattleStruct->wrappedBy + gEffectBank) = gBankAttacker; - - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; - - for (gBattleCommunication[MULTISTRING_CHOOSER] = 0; ; gBattleCommunication[MULTISTRING_CHOOSER]++) - { - if (gBattleCommunication[MULTISTRING_CHOOSER] > 4) - break; - if (gTrappingMoves[gBattleCommunication[MULTISTRING_CHOOSER]] == gCurrentMove) - break; - } - } - break; - case MOVE_EFFECT_RECOIL_25: // 25% recoil - gBattleMoveDamage = (gHpDealt) / 4; - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; - break; - case MOVE_EFFECT_ATK_PLUS_1: - case MOVE_EFFECT_DEF_PLUS_1: - case MOVE_EFFECT_SPD_PLUS_1: - case MOVE_EFFECT_SP_ATK_PLUS_1: - case MOVE_EFFECT_SP_DEF_PLUS_1: - case MOVE_EFFECT_ACC_PLUS_1: - case MOVE_EFFECT_EVS_PLUS_1: - if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(1), - gBattleCommunication[MOVE_EFFECT_BYTE] - MOVE_EFFECT_ATK_PLUS_1 + 1, - affectsUser, 0)) - { - gBattlescriptCurrInstr++; - } - else - { - gBattleScripting.animArg1 = gBattleCommunication[MOVE_EFFECT_BYTE] & ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); - gBattleScripting.animArg2 = 0; - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_StatUp; - } - break; - case MOVE_EFFECT_ATK_MINUS_1: - case MOVE_EFFECT_DEF_MINUS_1: - case MOVE_EFFECT_SPD_MINUS_1: - case MOVE_EFFECT_SP_ATK_MINUS_1: - case MOVE_EFFECT_SP_DEF_MINUS_1: - case MOVE_EFFECT_ACC_MINUS_1: - case MOVE_EFFECT_EVS_MINUS_1: - if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(1) | STAT_BUFF_NEGATIVE, - gBattleCommunication[MOVE_EFFECT_BYTE] - MOVE_EFFECT_ATK_MINUS_1 + 1, - affectsUser, 0)) - { - gBattlescriptCurrInstr++; - } - else - { - gBattleScripting.animArg1 = gBattleCommunication[MOVE_EFFECT_BYTE] & ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); - gBattleScripting.animArg2 = 0; - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_StatDown; - } - break; - case MOVE_EFFECT_ATK_PLUS_2: - case MOVE_EFFECT_DEF_PLUS_2: - case MOVE_EFFECT_SPD_PLUS_2: - case MOVE_EFFECT_SP_ATK_PLUS_2: - case MOVE_EFFECT_SP_DEF_PLUS_2: - case MOVE_EFFECT_ACC_PLUS_2: - case MOVE_EFFECT_EVS_PLUS_2: - if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(2), - gBattleCommunication[MOVE_EFFECT_BYTE] - MOVE_EFFECT_ATK_PLUS_2 + 1, - affectsUser, 0)) - { - gBattlescriptCurrInstr++; - } - else - { - gBattleScripting.animArg1 = gBattleCommunication[MOVE_EFFECT_BYTE] & ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); - gBattleScripting.animArg2 = 0; - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_StatUp; - } - break; - case MOVE_EFFECT_ATK_MINUS_2: - case MOVE_EFFECT_DEF_MINUS_2: - case MOVE_EFFECT_SPD_MINUS_2: - case MOVE_EFFECT_SP_ATK_MINUS_2: - case MOVE_EFFECT_SP_DEF_MINUS_2: - case MOVE_EFFECT_ACC_MINUS_2: - case MOVE_EFFECT_EVS_MINUS_2: - if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(2) | STAT_BUFF_NEGATIVE, - gBattleCommunication[MOVE_EFFECT_BYTE] - MOVE_EFFECT_ATK_MINUS_2 + 1, - affectsUser, 0)) - { - gBattlescriptCurrInstr++; - } - else - { - gBattleScripting.animArg1 = gBattleCommunication[MOVE_EFFECT_BYTE] & ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); - gBattleScripting.animArg2 = 0; - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_StatDown; - } - break; - case MOVE_EFFECT_RECHARGE: - gBattleMons[gEffectBank].status2 |= STATUS2_RECHARGE; - gDisableStructs[gEffectBank].rechargeCounter = 2; - gLockedMoves[gEffectBank] = gCurrentMove; - gBattlescriptCurrInstr++; - break; - case MOVE_EFFECT_RAGE: - gBattleMons[gBankAttacker].status2 |= STATUS2_RAGE; - gBattlescriptCurrInstr++; - break; - case MOVE_EFFECT_STEAL_ITEM: - { - if (gBattleTypeFlags & BATTLE_TYPE_x4000000) - { - gBattlescriptCurrInstr++; - break; - } - - side = GetBankSide(gBankAttacker); - if (GetBankSide(gBankAttacker) == SIDE_OPPONENT - && !(gBattleTypeFlags & - (BATTLE_TYPE_EREADER_TRAINER - | BATTLE_TYPE_FRONTIER - | BATTLE_TYPE_LINK - | BATTLE_TYPE_x2000000 - | BATTLE_TYPE_SECRET_BASE))) - { - gBattlescriptCurrInstr++; - } - else if (!(gBattleTypeFlags & - (BATTLE_TYPE_EREADER_TRAINER - | BATTLE_TYPE_FRONTIER - | BATTLE_TYPE_LINK - | BATTLE_TYPE_x2000000 - | BATTLE_TYPE_SECRET_BASE)) - && (gWishFutureKnock.knockedOffPokes[side] & gBitTable[gBattlePartyID[gBankAttacker]])) - { - gBattlescriptCurrInstr++; - } - else if (gBattleMons[gBankTarget].item - && gBattleMons[gBankTarget].ability == ABILITY_STICKY_HOLD) - { - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_NoItemSteal; - - gLastUsedAbility = gBattleMons[gBankTarget].ability; - RecordAbilityBattle(gBankTarget, gLastUsedAbility); - } - else if (gBattleMons[gBankAttacker].item != 0 - || gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY - || IS_ITEM_MAIL(gBattleMons[gBankTarget].item) - || gBattleMons[gBankTarget].item == 0) - { - gBattlescriptCurrInstr++; - } - else - { - u16* changedItem = &gBattleStruct->changedItems[gBankAttacker]; - gLastUsedItem = *changedItem = gBattleMons[gBankTarget].item; - gBattleMons[gBankTarget].item = 0; - - gActiveBank = gBankAttacker; - EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gLastUsedItem); - MarkBufferBankForExecution(gBankAttacker); - - gActiveBank = gBankTarget; - EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gBankTarget].item); - MarkBufferBankForExecution(gBankTarget); - - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_ItemSteal; - - *(u8*)((u8*)(&gBattleStruct->choicedMove[gBankTarget]) + 0) = 0; - *(u8*)((u8*)(&gBattleStruct->choicedMove[gBankTarget]) + 1) = 0; - } - - } - break; - case MOVE_EFFECT_PREVENT_ESCAPE: - gBattleMons[gBankTarget].status2 |= STATUS2_ESCAPE_PREVENTION; - gDisableStructs[gBankTarget].bankPreventingEscape = gBankAttacker; - gBattlescriptCurrInstr++; - break; - case MOVE_EFFECT_NIGHTMARE: - gBattleMons[gBankTarget].status2 |= STATUS2_NIGHTMARE; - gBattlescriptCurrInstr++; - break; - case MOVE_EFFECT_ALL_STATS_UP: - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_AllStatsUp; - break; - case MOVE_EFFECT_RAPIDSPIN: - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_RapidSpinAway; - break; - case MOVE_EFFECT_REMOVE_PARALYSIS: // Smelling salts - if (!(gBattleMons[gBankTarget].status1 & STATUS_PARALYSIS)) - { - gBattlescriptCurrInstr++; - } - else - { - gBattleMons[gBankTarget].status1 &= ~(STATUS_PARALYSIS); - - gActiveBank = gBankTarget; - EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); - MarkBufferBankForExecution(gActiveBank); - - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_TargetPRLZHeal; - } - break; - case MOVE_EFFECT_ATK_DEF_DOWN: // SuperPower - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_AtkDefDown; - break; - case MOVE_EFFECT_RECOIL_33_PARALYSIS: // Volt Tackle - gBattleMoveDamage = gHpDealt / 3; - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; - break; - case MOVE_EFFECT_THRASH: - if (gBattleMons[gEffectBank].status2 & STATUS2_LOCK_CONFUSE) - { - gBattlescriptCurrInstr++; - } - else - { - gBattleMons[gEffectBank].status2 |= STATUS2_MULTIPLETURNS; - gLockedMoves[gEffectBank] = gCurrentMove; - gBattleMons[gEffectBank].status2 |= (((Random() & 1) + 2) << 0xA); - } - break; - case MOVE_EFFECT_KNOCK_OFF: - if (gBattleMons[gEffectBank].ability == ABILITY_STICKY_HOLD) - { - if (gBattleMons[gEffectBank].item == 0) - { - gBattlescriptCurrInstr++; - } - else - { - gLastUsedAbility = ABILITY_STICKY_HOLD; - gBattlescriptCurrInstr = BattleScript_StickyHoldActivates; - RecordAbilityBattle(gEffectBank, ABILITY_STICKY_HOLD); - } - break; - } - if (gBattleMons[gEffectBank].item) - { - side = GetBankSide(gEffectBank); - - gLastUsedItem = gBattleMons[gEffectBank].item; - gBattleMons[gEffectBank].item = 0; - gWishFutureKnock.knockedOffPokes[side] |= gBitTable[gBattlePartyID[gEffectBank]]; - - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_KnockedOff; - - *(u8*)((u8*)(&gBattleStruct->choicedMove[gEffectBank]) + 0) = 0; - *(u8*)((u8*)(&gBattleStruct->choicedMove[gEffectBank]) + 1) = 0; - } - else - { - gBattlescriptCurrInstr++; - } - break; - case MOVE_EFFECT_SP_ATK_TWO_DOWN: // Overheat - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_SAtkDown2; - break; - } - } - } - - gBattleCommunication[MOVE_EFFECT_BYTE] = 0; -} - -static void atk15_seteffectwithchance(void) -{ - u32 percentChance; - - if (gBattleMons[gBankAttacker].ability == ABILITY_SERENE_GRACE) - percentChance = gBattleMoves[gCurrentMove].secondaryEffectChance * 2; - else - percentChance = gBattleMoves[gCurrentMove].secondaryEffectChance; - - if (gBattleCommunication[MOVE_EFFECT_BYTE] & MOVE_EFFECT_CERTAIN - && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) - { - gBattleCommunication[MOVE_EFFECT_BYTE] &= ~(MOVE_EFFECT_CERTAIN); - SetMoveEffect(0, MOVE_EFFECT_CERTAIN); - } - else if (Random() % 100 < percentChance - && gBattleCommunication[MOVE_EFFECT_BYTE] - && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) - { - if (percentChance >= 100) - SetMoveEffect(0, MOVE_EFFECT_CERTAIN); - else - SetMoveEffect(0, 0); - } - else - { - gBattlescriptCurrInstr++; - } - - gBattleCommunication[MOVE_EFFECT_BYTE] = 0; - gBattleScripting.field_16 = 0; -} - -static void atk16_seteffectprimary(void) -{ - SetMoveEffect(TRUE, 0); -} - -static void atk17_seteffectsecondary(void) -{ - SetMoveEffect(FALSE, 0); -} - -static void atk18_status_effect_clear(void) -{ - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - - if (gBattleCommunication[MOVE_EFFECT_BYTE] <= MOVE_EFFECT_TOXIC) - gBattleMons[gActiveBank].status1 &= (~sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]); - else - gBattleMons[gActiveBank].status2 &= (~sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]); - - gBattleCommunication[MOVE_EFFECT_BYTE] = 0; - gBattlescriptCurrInstr += 2; - gBattleScripting.field_16 = 0; -} - -static void atk19_faint_pokemon(void) -{ - const u8 *BS_ptr; - - if (gBattlescriptCurrInstr[2] != 0) - { - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - if (gHitMarker & HITMARKER_FAINTED(gActiveBank)) - { - BS_ptr = BSScriptReadPtr(gBattlescriptCurrInstr + 3); - - BattleScriptPop(); - gBattlescriptCurrInstr = BS_ptr; - gSideAffecting[GetBankSide(gActiveBank)] &= ~(SIDE_STATUS_SPIKES_DAMAGED); - } - else - { - gBattlescriptCurrInstr += 7; - } - } - else - { - u8 bank; - - if (gBattlescriptCurrInstr[1] == BS_GET_ATTACKER) - { - gActiveBank = gBankAttacker; - bank = gBankTarget; - BS_ptr = BattleScript_FaintAttacker; - } - else - { - gActiveBank = gBankTarget; - bank = gBankAttacker; - BS_ptr = BattleScript_FaintTarget; - } - if (!(gAbsentBankFlags & gBitTable[gActiveBank]) - && gBattleMons[gActiveBank].hp == 0) - { - gHitMarker |= HITMARKER_FAINTED(gActiveBank); - BattleScriptPush(gBattlescriptCurrInstr + 7); - gBattlescriptCurrInstr = BS_ptr; - if (GetBankSide(gActiveBank) == SIDE_PLAYER) - { - gHitMarker |= HITMARKER_x400000; - if (gBattleResults.playerFaintCounter < 0xFF) - gBattleResults.playerFaintCounter++; - AdjustFriendshipOnBattleFaint(gActiveBank); - } - else - { - if (gBattleResults.opponentFaintCounter < 0xFF) - gBattleResults.opponentFaintCounter++; - gBattleResults.lastOpponentSpecies = GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES, NULL); - } - if ((gHitMarker & HITMARKER_DESTINYBOND) && gBattleMons[gBankAttacker].hp != 0) - { - gHitMarker &= ~(HITMARKER_DESTINYBOND); - BattleScriptPush(gBattlescriptCurrInstr); - gBattleMoveDamage = gBattleMons[bank].hp; - gBattlescriptCurrInstr = BattleScript_DestinyBondTakesLife; - } - if ((gStatuses3[gBankTarget] & STATUS3_GRUDGE) - && !(gHitMarker & HITMARKER_GRUDGE) - && GetBankSide(gBankAttacker) != GetBankSide(gBankTarget) - && gBattleMons[gBankAttacker].hp != 0 - && gCurrentMove != MOVE_STRUGGLE) - { - u8 moveIndex = *(gBattleStruct->chosenMovesIds + gBankAttacker); - - gBattleMons[gBankAttacker].pp[moveIndex] = 0; - BattleScriptPush(gBattlescriptCurrInstr); - gBattlescriptCurrInstr = BattleScript_GrudgeTakesPp; - gActiveBank = gBankAttacker; - EmitSetMonData(0, moveIndex + REQUEST_PPMOVE1_BATTLE, 0, 1, &gBattleMons[gActiveBank].pp[moveIndex]); - MarkBufferBankForExecution(gActiveBank); - - PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleMons[gBankAttacker].moves[moveIndex]) - } - } - else - { - gBattlescriptCurrInstr += 7; - } - } -} - -static void atk1A_faint_animation(void) -{ - if (gBattleExecBuffer == 0) - { - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - EmitFaintAnimation(0); - MarkBufferBankForExecution(gActiveBank); - gBattlescriptCurrInstr += 2; - } -} - -static void atk1B_faint_effects_clear(void) -{ - if (gBattleExecBuffer == 0) - { - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - - if (!(gBattleTypeFlags & BATTLE_TYPE_ARENA) || gBattleMons[gActiveBank].hp == 0) - { - gBattleMons[gActiveBank].status1 = 0; - EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 0x4, &gBattleMons[gActiveBank].status1); - MarkBufferBankForExecution(gActiveBank); - } - - UndoEffectsAfterFainting(); // Effects like attractions, trapping, etc. - gBattlescriptCurrInstr += 2; - } -} - -static void atk1C_jumpifstatus(void) -{ - u8 bank = GetBattleBank(gBattlescriptCurrInstr[1]); - u32 flags = BS2ScriptRead32(gBattlescriptCurrInstr + 2); - const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 6); - - if (gBattleMons[bank].status1 & flags && gBattleMons[bank].hp) - gBattlescriptCurrInstr = jumpPtr; - else - gBattlescriptCurrInstr += 10; -} - -static void atk1D_jumpifstatus2(void) -{ - u8 bank = GetBattleBank(gBattlescriptCurrInstr[1]); - u32 flags = BS2ScriptRead32(gBattlescriptCurrInstr + 2); - const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 6); - - if (gBattleMons[bank].status2 & flags && gBattleMons[bank].hp) - gBattlescriptCurrInstr = jumpPtr; - else - gBattlescriptCurrInstr += 10; -} - -static void atk1E_jumpifability(void) -{ - u8 bank; - u8 ability = gBattlescriptCurrInstr[2]; - const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 3); - - if (gBattlescriptCurrInstr[1] == BS_GET_ATTACKER_SIDE) - { - bank = AbilityBattleEffects(ABILITYEFFECT_CHECK_BANK_SIDE, gBankAttacker, ability, 0, 0); - if (bank) - { - gLastUsedAbility = ability; - gBattlescriptCurrInstr = jumpPtr; - RecordAbilityBattle(bank - 1, gLastUsedAbility); - gBattleScripting.field_15 = bank - 1; - } - else - gBattlescriptCurrInstr += 7; - } - else if (gBattlescriptCurrInstr[1] == BS_GET_NOT_ATTACKER_SIDE) - { - bank = AbilityBattleEffects(ABILITYEFFECT_CHECK_OTHER_SIDE, gBankAttacker, ability, 0, 0); - if (bank) - { - gLastUsedAbility = ability; - gBattlescriptCurrInstr = jumpPtr; - RecordAbilityBattle(bank - 1, gLastUsedAbility); - gBattleScripting.field_15 = bank - 1; - } - else - gBattlescriptCurrInstr += 7; - } - else - { - bank = GetBattleBank(gBattlescriptCurrInstr[1]); - if (gBattleMons[bank].ability == ability) - { - gLastUsedAbility = ability; - gBattlescriptCurrInstr = jumpPtr; - RecordAbilityBattle(bank, gLastUsedAbility); - gBattleScripting.field_15 = bank; - } - else - gBattlescriptCurrInstr += 7; - } -} - -static void atk1F_jumpifsideaffecting(void) -{ - u8 side; - u16 flags; - const u8* jumpPtr; - - if (gBattlescriptCurrInstr[1] == BS_GET_ATTACKER) - side = GET_BANK_SIDE(gBankAttacker); - else - side = GET_BANK_SIDE(gBankTarget); - - flags = BS2ScriptRead16(gBattlescriptCurrInstr + 2); - jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 4); - - if (gSideAffecting[side] & flags) - gBattlescriptCurrInstr = jumpPtr; - else - gBattlescriptCurrInstr += 8; -} - -static void atk20_jumpifstat(void) -{ - u8 ret = 0; - u8 bank = GetBattleBank(gBattlescriptCurrInstr[1]); - u8 value = gBattleMons[bank].statStages[gBattlescriptCurrInstr[3]]; - - switch (gBattlescriptCurrInstr[2]) - { - case CMP_EQUAL: - if (value == gBattlescriptCurrInstr[4]) - ret++; - break; - case CMP_NOT_EQUAL: - if (value != gBattlescriptCurrInstr[4]) - ret++; - break; - case CMP_GREATER_THAN: - if (value > gBattlescriptCurrInstr[4]) - ret++; - break; - case CMP_LESS_THAN: - if (value < gBattlescriptCurrInstr[4]) - ret++; - break; - case CMP_COMMON_BITS: - if (value & gBattlescriptCurrInstr[4]) - ret++; - break; - case CMP_NO_COMMON_BITS: - if (!(value & gBattlescriptCurrInstr[4])) - ret++; - break; - } - - if (ret) - gBattlescriptCurrInstr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5); - else - gBattlescriptCurrInstr += 9; -} - -static void atk21_jumpifstatus3(void) -{ - u32 flags; - const u8* jumpPtr; - - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - flags = BS2ScriptRead32(gBattlescriptCurrInstr + 2); - jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 7); - - if (gBattlescriptCurrInstr[6]) - { - if ((gStatuses3[gActiveBank] & flags) != 0) - gBattlescriptCurrInstr += 11; - else - gBattlescriptCurrInstr = jumpPtr; - } - else - { - if ((gStatuses3[gActiveBank] & flags) != 0) - gBattlescriptCurrInstr = jumpPtr; - else - gBattlescriptCurrInstr += 11; - } -} - -static void atk22_jumpiftype(void) -{ - u8 bank = GetBattleBank(gBattlescriptCurrInstr[1]); - u8 type = gBattlescriptCurrInstr[2]; - const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 3); - - if (gBattleMons[bank].type1 == type || gBattleMons[bank].type2 == type) - gBattlescriptCurrInstr = jumpPtr; - else - gBattlescriptCurrInstr += 7; -} - -static void atk23_getexp(void) -{ - u16 item; - s32 i; // also used as stringId - u8 holdEffect; - s32 sentIn; - - s32 viaExpShare = 0; - u16* exp = &gBattleStruct->expValue; - - gBank1 = GetBattleBank(gBattlescriptCurrInstr[1]); - sentIn = gSentPokesToOpponent[(gBank1 & 2) >> 1]; - - switch (gBattleScripting.atk23_state) - { - case 0: // check if should receive exp at all - if (GetBankSide(gBank1) != SIDE_OPPONENT || (gBattleTypeFlags & - (BATTLE_TYPE_LINK - | BATTLE_TYPE_x2000000 - | BATTLE_TYPE_x4000000 - | BATTLE_TYPE_FRONTIER - | BATTLE_TYPE_SAFARI - | BATTLE_TYPE_BATTLE_TOWER - | BATTLE_TYPE_EREADER_TRAINER))) - { - gBattleScripting.atk23_state = 6; // goto last case - } - else - { - gBattleScripting.atk23_state++; - gBattleStruct->field_DF |= gBitTable[gBattlePartyID[gBank1]]; - } - break; - case 1: // calculate experience points to redistribute - { - u16 calculatedExp; - s32 viaSentIn; - - for (viaSentIn = 0, i = 0; i < 6; i++) - { - if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) == SPECIES_NONE || GetMonData(&gPlayerParty[i], MON_DATA_HP) == 0) - continue; - if (gBitTable[i] & sentIn) - viaSentIn++; - - item = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM); - - if (item == ITEM_ENIGMA_BERRY) - holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect; - else - holdEffect = ItemId_GetHoldEffect(item); - - if (holdEffect == HOLD_EFFECT_EXP_SHARE) - viaExpShare++; - } - - calculatedExp = gBaseStats[gBattleMons[gBank1].species].expYield * gBattleMons[gBank1].level / 7; - - if (viaExpShare) // at least one mon is getting exp via exp share - { - *exp = calculatedExp / 2 / viaSentIn; - if (*exp == 0) - *exp = 1; - - gExpShareExp = calculatedExp / 2 / viaExpShare; - if (gExpShareExp == 0) - gExpShareExp = 1; - } - else - { - *exp = calculatedExp / viaSentIn; - if (*exp == 0) - *exp = 1; - gExpShareExp = 0; - } - - gBattleScripting.atk23_state++; - gBattleStruct->expGetterId = 0; - gBattleStruct->sentInPokes = sentIn; - } - // fall through - case 2: // set exp value to the poke in expgetter_id and print message - if (gBattleExecBuffer == 0) - { - item = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_HELD_ITEM); - - if (item == ITEM_ENIGMA_BERRY) - holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect; - else - holdEffect = ItemId_GetHoldEffect(item); - - if (holdEffect != HOLD_EFFECT_EXP_SHARE && !(gBattleStruct->sentInPokes & 1)) - { - *(&gBattleStruct->sentInPokes) >>= 1; - gBattleScripting.atk23_state = 5; - gBattleMoveDamage = 0; // used for exp - } - else if (GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL) == MAX_MON_LEVEL) - { - *(&gBattleStruct->sentInPokes) >>= 1; - gBattleScripting.atk23_state = 5; - gBattleMoveDamage = 0; // used for exp - } - else - { - // music change in wild battle after fainting a poke - if (!(gBattleTypeFlags & BATTLE_TYPE_TRAINER) && gBattleMons[0].hp && !gBattleStruct->wildVictorySong) - { - BattleMusicStop(); - PlayBGM(0x161); - gBattleStruct->wildVictorySong++; - } - - if (GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_HP)) - { - if (gBattleStruct->sentInPokes & 1) - gBattleMoveDamage = *exp; - else - gBattleMoveDamage = 0; - - if (holdEffect == HOLD_EFFECT_EXP_SHARE) - gBattleMoveDamage += gExpShareExp; - if (holdEffect == HOLD_EFFECT_LUCKY_EGG) - gBattleMoveDamage = (gBattleMoveDamage * 150) / 100; - if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) - gBattleMoveDamage = (gBattleMoveDamage * 150) / 100; - - if (IsTradedMon(&gPlayerParty[gBattleStruct->expGetterId])) - { - // check if the pokemon doesn't belong to the player - if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gBattleStruct->expGetterId >= 3) - { - i = 0x149; - } - else - { - gBattleMoveDamage = (gBattleMoveDamage * 150) / 100; - i = 0x14A; - } - } - else - { - i = 0x149; - } - - // get exp getter bank - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) - { - if (!(gBattlePartyID[2] != gBattleStruct->expGetterId) && !(gAbsentBankFlags & gBitTable[2])) - gBattleStruct->expGetterBank = 2; - else - { - if (!(gAbsentBankFlags & gBitTable[0])) - gBattleStruct->expGetterBank = 0; - else - gBattleStruct->expGetterBank = 2; - } - } - else - gBattleStruct->expGetterBank = 0; - - PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBattleStruct->expGetterBank, gBattleStruct->expGetterId) - - // buffer 'gained' or 'gained a boosted' - PREPARE_STRING_BUFFER(gBattleTextBuff2, i) - - PREPARE_WORD_NUMBER_BUFFER(gBattleTextBuff3, 5, gBattleMoveDamage) - - PrepareStringBattle(0xD, gBattleStruct->expGetterBank); - MonGainEVs(&gPlayerParty[gBattleStruct->expGetterId], gBattleMons[gBank1].species); - } - gBattleStruct->sentInPokes >>= 1; - gBattleScripting.atk23_state++; - } - } - break; - case 3: // Set stats and give exp - if (gBattleExecBuffer == 0) - { - gBattleBufferB[gBattleStruct->expGetterBank][0] = 0; - if (GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_HP) && GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL) != MAX_MON_LEVEL) - { - BATTLE_LVLUP_STATS->hp = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_MAX_HP); - BATTLE_LVLUP_STATS->atk = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_ATK); - BATTLE_LVLUP_STATS->def = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_DEF); - BATTLE_LVLUP_STATS->spd = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPD); - BATTLE_LVLUP_STATS->spAtk = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPATK); - BATTLE_LVLUP_STATS->spDef = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPDEF); - - gActiveBank = gBattleStruct->expGetterBank; - EmitExpUpdate(0, gBattleStruct->expGetterId, gBattleMoveDamage); - MarkBufferBankForExecution(gActiveBank); - } - gBattleScripting.atk23_state++; - } - break; - case 4: // lvl up if necessary - if (gBattleExecBuffer == 0) - { - gActiveBank = gBattleStruct->expGetterBank; - if (gBattleBufferB[gActiveBank][0] == 0x21 && gBattleBufferB[gActiveBank][1] == 0xB) - { - if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && gBattlePartyID[gActiveBank] == gBattleStruct->expGetterId) - sub_805E990(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank); - - PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gActiveBank, gBattleStruct->expGetterId) - - PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff2, 3, GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL)) - - BattleScriptPushCursor(); - gLeveledUpInBattle |= gBitTable[gBattleStruct->expGetterId]; - gBattlescriptCurrInstr = BattleScript_LevelUp; - gBattleMoveDamage = (gBattleBufferB[gActiveBank][2] | (gBattleBufferB[gActiveBank][3] << 8)); - AdjustFriendship(&gPlayerParty[gBattleStruct->expGetterId], 0); - - // update battle mon structure after level up - if (gBattlePartyID[0] == gBattleStruct->expGetterId && gBattleMons[0].hp) - { - gBattleMons[0].level = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL); - gBattleMons[0].hp = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_HP); - gBattleMons[0].maxHP = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_MAX_HP); - gBattleMons[0].attack = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_ATK); - gBattleMons[0].defense = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_DEF); - // Why is this duplicated? - gBattleMons[0].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPD); - gBattleMons[0].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPD); - - gBattleMons[0].spAttack = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPATK); - gBattleMons[0].spDefense = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPDEF); - } - // What is else if? - if (gBattlePartyID[2] == gBattleStruct->expGetterId && gBattleMons[2].hp && (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) - { - gBattleMons[2].level = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL); - gBattleMons[2].hp = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_HP); - gBattleMons[2].maxHP = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_MAX_HP); - gBattleMons[2].attack = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_ATK); - gBattleMons[2].defense = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_DEF); - // Duplicated again, but this time there's no Sp Defense - gBattleMons[2].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPD); - gBattleMons[2].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPD); - - gBattleMons[2].spAttack = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPATK); - } - gBattleScripting.atk23_state = 5; - } - else - { - gBattleMoveDamage = 0; - gBattleScripting.atk23_state = 5; - } - } - break; - case 5: // looper increment - if (gBattleMoveDamage) // there is exp to give, goto case 3 that gives exp - gBattleScripting.atk23_state = 3; - else - { - gBattleStruct->expGetterId++; - if (gBattleStruct->expGetterId <= 5) - gBattleScripting.atk23_state = 2; // loop again - else - gBattleScripting.atk23_state = 6; // we're done - } - break; - case 6: // increment instruction - if (gBattleExecBuffer == 0) - { - // not sure why gf clears the item and ability here - gBattleMons[gBank1].item = 0; - gBattleMons[gBank1].ability = 0; - gBattlescriptCurrInstr += 2; - } - break; - } -} - -#ifdef NONMATCHING -static void atk24(void) -{ - u16 HP_count = 0; - s32 i; - - if (gBattleExecBuffer) - return; - - if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gPartnerTrainerId == STEVEN_PARTNER_ID) - { - for (i = 0; i < 3; i++) - { - if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) && !GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG)) - HP_count += GetMonData(&gPlayerParty[i], MON_DATA_HP); - } - } - else - { - for (i = 0; i < 6; i++) - { - if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) && !GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG) - && (!(gBattleTypeFlags & BATTLE_TYPE_ARENA) || !(gBattleStruct->field_2A0 & gBitTable[i]))) - { - HP_count += GetMonData(&gPlayerParty[i], MON_DATA_HP); - } - } - } - - if (HP_count == 0) - gBattleOutcome |= BATTLE_LOST; - - for (HP_count = 0, i = 0; i < 6; i++) - { - if (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES) && !GetMonData(&gEnemyParty[i], MON_DATA_IS_EGG) - && (!(gBattleTypeFlags & BATTLE_TYPE_ARENA) || !(gBattleStruct->field_2A1 & gBitTable[i]))) - { - HP_count += GetMonData(&gEnemyParty[i], MON_DATA_HP); - } - } - - if (HP_count == 0) - gBattleOutcome |= BATTLE_WON; - - if (gBattleOutcome == 0 && (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000))) - { - s32 foundPlayer; - s32 foundOpponent; - - // Impossible to decompile loops. - for (foundPlayer = 0, i = 0; i < gNoOfAllBanks; i += 2) - { - if (HITMARKER_UNK(i) & gHitMarker && !gSpecialStatuses[i].flag40) - foundPlayer++; - } - - for (foundOpponent = 0, i = 1; i < gNoOfAllBanks; i += 2) - { - if (HITMARKER_UNK(i) & gHitMarker && !gSpecialStatuses[i].flag40) - foundOpponent++; - } - - if (gBattleTypeFlags & BATTLE_TYPE_MULTI) - { - if (foundOpponent + foundPlayer > 1) - gBattlescriptCurrInstr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); - else - gBattlescriptCurrInstr += 5; - } - else - { - if (foundOpponent != 0 && foundPlayer != 0) - gBattlescriptCurrInstr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); - else - gBattlescriptCurrInstr += 5; - } - } - else - { - gBattlescriptCurrInstr += 5; - } -} -#else -__attribute__((naked)) -static void atk24(void) -{ - asm("\n\ - .syntax unified\n\ - push {r4-r7,lr}\n\ - mov r7, r8\n\ - push {r7}\n\ - movs r6, 0\n\ - ldr r0, =gBattleExecBuffer\n\ - ldr r0, [r0]\n\ - cmp r0, 0\n\ - beq _0804ACE2\n\ - b _0804AF22\n\ - _0804ACE2:\n\ - ldr r0, =gBattleTypeFlags\n\ - ldr r0, [r0]\n\ - movs r1, 0x80\n\ - lsls r1, 15\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _0804AD48\n\ - ldr r0, =gPartnerTrainerId\n\ - ldrh r1, [r0]\n\ - ldr r0, =0x00000c03\n\ - cmp r1, r0\n\ - bne _0804AD48\n\ - movs r5, 0\n\ - _0804ACFC:\n\ - movs r0, 0x64\n\ - adds r1, r5, 0\n\ - muls r1, r0\n\ - ldr r0, =gPlayerParty\n\ - adds r4, r1, r0\n\ - adds r0, r4, 0\n\ - movs r1, 0xB\n\ - bl GetMonData\n\ - cmp r0, 0\n\ - beq _0804AD2C\n\ - adds r0, r4, 0\n\ - movs r1, 0x2D\n\ - bl GetMonData\n\ - cmp r0, 0\n\ - bne _0804AD2C\n\ - adds r0, r4, 0\n\ - movs r1, 0x39\n\ - bl GetMonData\n\ - adds r0, r6, r0\n\ - lsls r0, 16\n\ - lsrs r6, r0, 16\n\ - _0804AD2C:\n\ - adds r5, 0x1\n\ - cmp r5, 0x2\n\ - ble _0804ACFC\n\ - b _0804ADA8\n\ - .pool\n\ - _0804AD48:\n\ - movs r5, 0\n\ - _0804AD4A:\n\ - movs r0, 0x64\n\ - adds r1, r5, 0\n\ - muls r1, r0\n\ - ldr r0, =gPlayerParty\n\ - adds r4, r1, r0\n\ - adds r0, r4, 0\n\ - movs r1, 0xB\n\ - bl GetMonData\n\ - cmp r0, 0\n\ - beq _0804ADA2\n\ - adds r0, r4, 0\n\ - movs r1, 0x2D\n\ - bl GetMonData\n\ - cmp r0, 0\n\ - bne _0804ADA2\n\ - ldr r0, =gBattleTypeFlags\n\ - ldr r0, [r0]\n\ - movs r1, 0x80\n\ - lsls r1, 11\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _0804AD94\n\ - ldr r0, =gBattleStruct\n\ - ldr r0, [r0]\n\ - movs r1, 0xA8\n\ - lsls r1, 2\n\ - adds r0, r1\n\ - ldrb r1, [r0]\n\ - ldr r2, =gBitTable\n\ - lsls r0, r5, 2\n\ - adds r0, r2\n\ - ldr r0, [r0]\n\ - ands r1, r0\n\ - cmp r1, 0\n\ - bne _0804ADA2\n\ - _0804AD94:\n\ - adds r0, r4, 0\n\ - movs r1, 0x39\n\ - bl GetMonData\n\ - adds r0, r6, r0\n\ - lsls r0, 16\n\ - lsrs r6, r0, 16\n\ - _0804ADA2:\n\ - adds r5, 0x1\n\ - cmp r5, 0x5\n\ - ble _0804AD4A\n\ - _0804ADA8:\n\ - cmp r6, 0\n\ - bne _0804ADB6\n\ - ldr r0, =gBattleOutcome\n\ - ldrb r1, [r0]\n\ - movs r2, 0x2\n\ - orrs r1, r2\n\ - strb r1, [r0]\n\ - _0804ADB6:\n\ - movs r6, 0\n\ - movs r5, 0\n\ - _0804ADBA:\n\ - movs r0, 0x64\n\ - adds r1, r5, 0\n\ - muls r1, r0\n\ - ldr r0, =gEnemyParty\n\ - adds r4, r1, r0\n\ - adds r0, r4, 0\n\ - movs r1, 0xB\n\ - bl GetMonData\n\ - cmp r0, 0\n\ - beq _0804AE10\n\ - adds r0, r4, 0\n\ - movs r1, 0x2D\n\ - bl GetMonData\n\ - cmp r0, 0\n\ - bne _0804AE10\n\ - ldr r0, =gBattleTypeFlags\n\ - ldr r0, [r0]\n\ - movs r1, 0x80\n\ - lsls r1, 11\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _0804AE02\n\ - ldr r0, =gBattleStruct\n\ - ldr r0, [r0]\n\ - ldr r1, =0x000002a1\n\ - adds r0, r1\n\ - ldrb r1, [r0]\n\ - ldr r2, =gBitTable\n\ - lsls r0, r5, 2\n\ - adds r0, r2\n\ - ldr r0, [r0]\n\ - ands r1, r0\n\ - cmp r1, 0\n\ - bne _0804AE10\n\ - _0804AE02:\n\ - adds r0, r4, 0\n\ - movs r1, 0x39\n\ - bl GetMonData\n\ - adds r0, r6, r0\n\ - lsls r0, 16\n\ - lsrs r6, r0, 16\n\ - _0804AE10:\n\ - adds r5, 0x1\n\ - cmp r5, 0x5\n\ - ble _0804ADBA\n\ - ldr r2, =gBattleOutcome\n\ - cmp r6, 0\n\ - bne _0804AE24\n\ - ldrb r0, [r2]\n\ - movs r1, 0x1\n\ - orrs r0, r1\n\ - strb r0, [r2]\n\ - _0804AE24:\n\ - ldrb r0, [r2]\n\ - cmp r0, 0\n\ - bne _0804AF1A\n\ - ldr r0, =gBattleTypeFlags\n\ - ldr r1, [r0]\n\ - ldr r2, =0x02000002\n\ - ands r1, r2\n\ - mov r8, r0\n\ - cmp r1, 0\n\ - beq _0804AF1A\n\ - movs r3, 0\n\ - movs r5, 0\n\ - ldr r0, =gNoOfAllBanks\n\ - ldrb r1, [r0]\n\ - mov r12, r0\n\ - ldr r7, =gBattlescriptCurrInstr\n\ - cmp r3, r1\n\ - bge _0804AE70\n\ - ldr r0, =gHitMarker\n\ - movs r6, 0x80\n\ - lsls r6, 21\n\ - ldr r4, [r0]\n\ - adds r2, r1, 0\n\ - ldr r1, =gSpecialStatuses\n\ - _0804AE54:\n\ - adds r0, r6, 0\n\ - lsls r0, r5\n\ - ands r0, r4\n\ - cmp r0, 0\n\ - beq _0804AE68\n\ - ldrb r0, [r1]\n\ - lsls r0, 25\n\ - cmp r0, 0\n\ - blt _0804AE68\n\ - adds r3, 0x1\n\ - _0804AE68:\n\ - adds r1, 0x28\n\ - adds r5, 0x2\n\ - cmp r5, r2\n\ - blt _0804AE54\n\ - _0804AE70:\n\ - movs r2, 0\n\ - movs r5, 0x1\n\ - mov r4, r12\n\ - ldrb r1, [r4]\n\ - cmp r5, r1\n\ - bge _0804AEAA\n\ - ldr r0, =gHitMarker\n\ - movs r4, 0x80\n\ - lsls r4, 21\n\ - mov r12, r4\n\ - ldr r6, [r0]\n\ - ldr r0, =gSpecialStatuses\n\ - adds r4, r1, 0\n\ - adds r1, r0, 0\n\ - adds r1, 0x14\n\ - _0804AE8E:\n\ - mov r0, r12\n\ - lsls r0, r5\n\ - ands r0, r6\n\ - cmp r0, 0\n\ - beq _0804AEA2\n\ - ldrb r0, [r1]\n\ - lsls r0, 25\n\ - cmp r0, 0\n\ - blt _0804AEA2\n\ - adds r2, 0x1\n\ - _0804AEA2:\n\ - adds r1, 0x28\n\ - adds r5, 0x2\n\ - cmp r5, r4\n\ - blt _0804AE8E\n\ - _0804AEAA:\n\ - mov r1, r8\n\ - ldr r0, [r1]\n\ - movs r1, 0x40\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _0804AEF0\n\ - adds r0, r2, r3\n\ - cmp r0, 0x1\n\ - bgt _0804AEF8\n\ - b _0804AF12\n\ - .pool\n\ - _0804AEF0:\n\ - cmp r2, 0\n\ - beq _0804AF12\n\ - cmp r3, 0\n\ - beq _0804AF12\n\ - _0804AEF8:\n\ - ldr r2, [r7]\n\ - ldrb r1, [r2, 0x1]\n\ - ldrb r0, [r2, 0x2]\n\ - lsls r0, 8\n\ - adds r1, r0\n\ - ldrb r0, [r2, 0x3]\n\ - lsls r0, 16\n\ - adds r1, r0\n\ - ldrb r0, [r2, 0x4]\n\ - lsls r0, 24\n\ - adds r1, r0\n\ - str r1, [r7]\n\ - b _0804AF22\n\ - _0804AF12:\n\ - ldr r0, [r7]\n\ - adds r0, 0x5\n\ - str r0, [r7]\n\ - b _0804AF22\n\ - _0804AF1A:\n\ - ldr r1, =gBattlescriptCurrInstr\n\ - ldr r0, [r1]\n\ - adds r0, 0x5\n\ - str r0, [r1]\n\ - _0804AF22:\n\ - pop {r3}\n\ - mov r8, r3\n\ - pop {r4-r7}\n\ - pop {r0}\n\ - bx r0\n\ - .pool\n\ - .syntax divided"); -} - -#endif // NONMATCHING - -static void MoveValuesCleanUp(void) -{ - gBattleMoveFlags = 0; - gBattleScripting.dmgMultiplier = 1; - gCritMultiplier = 1; - gBattleCommunication[MOVE_EFFECT_BYTE] = 0; - gBattleCommunication[6] = 0; - gHitMarker &= ~(HITMARKER_DESTINYBOND); - gHitMarker &= ~(HITMARKER_SYNCHRONISE_EFFECT); -} - -static void atk25_move_values_cleanup(void) -{ - MoveValuesCleanUp(); - gBattlescriptCurrInstr += 1; -} - -static void atk26_set_multihit(void) -{ - gMultiHitCounter = gBattlescriptCurrInstr[1]; - gBattlescriptCurrInstr += 2; -} - -static void atk27_decrement_multihit(void) -{ - if (--gMultiHitCounter == 0) - gBattlescriptCurrInstr += 5; - else - gBattlescriptCurrInstr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); -} - -static void atk28_goto(void) -{ - gBattlescriptCurrInstr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); -} - -static void atk29_jumpifbyte(void) -{ - u8 caseID = gBattlescriptCurrInstr[1]; - const u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 2); - u8 value = gBattlescriptCurrInstr[6]; - const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 7); - - gBattlescriptCurrInstr += 11; - - switch (caseID) - { - case CMP_EQUAL: - if (*memByte == value) - gBattlescriptCurrInstr = jumpPtr; - break; - case CMP_NOT_EQUAL: - if (*memByte != value) - gBattlescriptCurrInstr = jumpPtr; - break; - case CMP_GREATER_THAN: - if (*memByte > value) - gBattlescriptCurrInstr = jumpPtr; - break; - case CMP_LESS_THAN: - if (*memByte < value) - gBattlescriptCurrInstr = jumpPtr; - break; - case CMP_COMMON_BITS: - if (*memByte & value) - gBattlescriptCurrInstr = jumpPtr; - break; - case CMP_NO_COMMON_BITS: - if (!(*memByte & value)) - gBattlescriptCurrInstr = jumpPtr; - break; - } -} - -static void atk2A_jumpifhalfword(void) -{ - u8 caseID = gBattlescriptCurrInstr[1]; - const u16* memHword = BS2ScriptReadPtr(gBattlescriptCurrInstr + 2); - u16 value = BS2ScriptRead16(gBattlescriptCurrInstr + 6); - const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 8); - - gBattlescriptCurrInstr += 12; - - switch (caseID) - { - case CMP_EQUAL: - if (*memHword == value) - gBattlescriptCurrInstr = jumpPtr; - break; - case CMP_NOT_EQUAL: - if (*memHword != value) - gBattlescriptCurrInstr = jumpPtr; - break; - case CMP_GREATER_THAN: - if (*memHword > value) - gBattlescriptCurrInstr = jumpPtr; - break; - case CMP_LESS_THAN: - if (*memHword < value) - gBattlescriptCurrInstr = jumpPtr; - break; - case CMP_COMMON_BITS: - if (*memHword & value) - gBattlescriptCurrInstr = jumpPtr; - break; - case CMP_NO_COMMON_BITS: - if (!(*memHword & value)) - gBattlescriptCurrInstr = jumpPtr; - break; - } -} - -static void atk2B_jumpifword(void) -{ - u8 caseID = gBattlescriptCurrInstr[1]; - const u32* memWord = BS2ScriptReadPtr(gBattlescriptCurrInstr + 2); - u32 value = BSScriptRead32(gBattlescriptCurrInstr + 6); - const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 10); - - gBattlescriptCurrInstr += 14; - - switch (caseID) - { - case CMP_EQUAL: - if (*memWord == value) - gBattlescriptCurrInstr = jumpPtr; - break; - case CMP_NOT_EQUAL: - if (*memWord != value) - gBattlescriptCurrInstr = jumpPtr; - break; - case CMP_GREATER_THAN: - if (*memWord > value) - gBattlescriptCurrInstr = jumpPtr; - break; - case CMP_LESS_THAN: - if (*memWord < value) - gBattlescriptCurrInstr = jumpPtr; - break; - case CMP_COMMON_BITS: - if (*memWord & value) - gBattlescriptCurrInstr = jumpPtr; - break; - case CMP_NO_COMMON_BITS: - if (!(*memWord & value)) - gBattlescriptCurrInstr = jumpPtr; - break; - } -} - -static void atk2C_jumpifarrayequal(void) -{ - const u8* mem1 = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); - const u8* mem2 = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5); - u32 size = gBattlescriptCurrInstr[9]; - const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 10); - - u8 i; - for (i = 0; i < size; i++) - { - if (*mem1 != *mem2) - { - gBattlescriptCurrInstr += 14; - break; - } - mem1++, mem2++; - } - - if (i == size) - gBattlescriptCurrInstr = jumpPtr; -} - -static void atk2D_jumpifarraynotequal(void) -{ - u8 equalBytes = 0; - const u8* mem1 = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); - const u8* mem2 = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5); - u32 size = gBattlescriptCurrInstr[9]; - const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 10); - - u8 i; - for (i = 0; i < size; i++) - { - if (*mem1 == *mem2) - { - equalBytes++; - } - mem1++, mem2++; - } - - if (equalBytes != size) - gBattlescriptCurrInstr = jumpPtr; - else - gBattlescriptCurrInstr += 14; -} - -static void atk2E_setbyte(void) -{ - u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); - *memByte = gBattlescriptCurrInstr[5]; - - gBattlescriptCurrInstr += 6; -} - -static void atk2F_addbyte(void) -{ - u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); - *memByte += gBattlescriptCurrInstr[5]; - gBattlescriptCurrInstr += 6; -} - -static void atk30_subbyte(void) -{ - u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); - *memByte -= gBattlescriptCurrInstr[5]; - gBattlescriptCurrInstr += 6; -} - -static void atk31_copyarray(void) -{ - u8* dest = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); - const u8* src = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5); - s32 size = gBattlescriptCurrInstr[9]; - - s32 i; - for (i = 0; i < size; i++) - { - dest[i] = src[i]; - } - - gBattlescriptCurrInstr += 10; -} - -static void atk32_copyarray_withindex(void) -{ - u8* dest = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); - const u8* src = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5); - const u8* index = BS2ScriptReadPtr(gBattlescriptCurrInstr + 9); - s32 size = gBattlescriptCurrInstr[13]; - - s32 i; - for (i = 0; i < size; i++) - { - dest[i] = src[i + *index]; - } - - gBattlescriptCurrInstr += 14; -} - -static void atk33_orbyte(void) -{ - u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); - *memByte |= gBattlescriptCurrInstr[5]; - gBattlescriptCurrInstr += 6; -} - -static void atk34_orhalfword(void) -{ - u16* memHword = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); - u16 val = BS2ScriptRead16(gBattlescriptCurrInstr + 5); - - *memHword |= val; - gBattlescriptCurrInstr += 7; -} - -static void atk35_orword(void) -{ - u32* memWord = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); - u32 val = BS2ScriptRead32(gBattlescriptCurrInstr + 5); - - *memWord |= val; - gBattlescriptCurrInstr += 9; -} - -static void atk36_bicbyte(void) -{ - u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); - *memByte &= ~(gBattlescriptCurrInstr[5]); - gBattlescriptCurrInstr += 6; -} - -static void atk37_bichalfword(void) -{ - u16* memHword = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); - u16 val = BS2ScriptRead16(gBattlescriptCurrInstr + 5); - - *memHword &= ~val; - gBattlescriptCurrInstr += 7; -} - -static void atk38_bicword(void) -{ - u32* memWord = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); - u32 val = BS2ScriptRead32(gBattlescriptCurrInstr + 5); - - *memWord &= ~val; - gBattlescriptCurrInstr += 9; -} - -static void atk39_pause(void) -{ - if (gBattleExecBuffer == 0) - { - u16 value = BS2ScriptRead16(gBattlescriptCurrInstr + 1); - if (++gPauseCounterBattle >= value) - { - gPauseCounterBattle = 0; - gBattlescriptCurrInstr += 3; - } - } -} - -static void atk3A_waitstate(void) -{ - if (gBattleExecBuffer == 0) - gBattlescriptCurrInstr++; -} - -static void atk3B_healthbar_update(void) -{ - if (gBattlescriptCurrInstr[1] == BS_GET_TARGET) - gActiveBank = gBankTarget; - else - gActiveBank = gBankAttacker; - - EmitHealthBarUpdate(0, gBattleMoveDamage); - MarkBufferBankForExecution(gActiveBank); - gBattlescriptCurrInstr += 2; -} - -static void atk3C_return(void) -{ - BattleScriptPop(); -} - -static void atk3D_end(void) -{ - if (gBattleTypeFlags & BATTLE_TYPE_ARENA) - sub_81A5718(gBankAttacker); - - gBattleMoveFlags = 0; - gActiveBank = 0; - gFightStateTracker = 0xB; -} - -static void atk3E_end2(void) -{ - gActiveBank = 0; - gFightStateTracker = 0xB; -} - -static void atk3F_end3(void) // pops the main function stack -{ - BattleScriptPop(); - if (BATTLE_CALLBACKS_STACK->size) - BATTLE_CALLBACKS_STACK->size--; - gBattleMainFunc = BATTLE_CALLBACKS_STACK->function[BATTLE_CALLBACKS_STACK->size]; -} - -static void atk41_call(void) -{ - BattleScriptPush(gBattlescriptCurrInstr + 5); - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); -} - -static void atk42_jumpiftype2(void) -{ - u8 bank = GetBattleBank(gBattlescriptCurrInstr[1]); - - if (gBattlescriptCurrInstr[2] == gBattleMons[bank].type1 || gBattlescriptCurrInstr[2] == gBattleMons[bank].type2) - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 3); - else - gBattlescriptCurrInstr += 7; -} - -static void atk43_jumpifabilitypresent(void) -{ - if (AbilityBattleEffects(ABILITYEFFECT_CHECK_ON_FIELD, 0, gBattlescriptCurrInstr[1], 0, 0)) - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); - else - gBattlescriptCurrInstr += 6; -} - -static void atk44(void) -{ - *(gBankAttacker + gBattleStruct->field_54) = 1; -} - -static void atk45_playanimation(void) -{ - const u16* argumentPtr; - - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - argumentPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 3); - - if (gBattlescriptCurrInstr[2] == B_ANIM_STATS_CHANGE - || gBattlescriptCurrInstr[2] == B_ANIM_SNATCH_MOVE - || gBattlescriptCurrInstr[2] == B_ANIM_SUBSTITUTE_FADE) - { - EmitBattleAnimation(0, gBattlescriptCurrInstr[2], *argumentPtr); - MarkBufferBankForExecution(gActiveBank); - gBattlescriptCurrInstr += 7; - } - else if (gHitMarker & HITMARKER_NO_ANIMATIONS) - { - BattleScriptPush(gBattlescriptCurrInstr + 7); - gBattlescriptCurrInstr = BattleScript_Pausex20; - } - else if (gBattlescriptCurrInstr[2] == B_ANIM_RAIN_CONTINUES - || gBattlescriptCurrInstr[2] == B_ANIM_SUN_CONTINUES - || gBattlescriptCurrInstr[2] == B_ANIM_SANDSTORM_CONTINUES - || gBattlescriptCurrInstr[2] == B_ANIM_HAIL_CONTINUES) - { - EmitBattleAnimation(0, gBattlescriptCurrInstr[2], *argumentPtr); - MarkBufferBankForExecution(gActiveBank); - gBattlescriptCurrInstr += 7; - } - else if (gStatuses3[gActiveBank] & STATUS3_SEMI_INVULNERABLE) - { - gBattlescriptCurrInstr += 7; - } - else - { - EmitBattleAnimation(0, gBattlescriptCurrInstr[2], *argumentPtr); - MarkBufferBankForExecution(gActiveBank); - gBattlescriptCurrInstr += 7; - } -} - -static void atk46_playanimation2(void) // animation Id is stored in the first pointer -{ - const u16* argumentPtr; - const u8* animationIdPtr; - - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - animationIdPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 2); - argumentPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 6); - - if (*animationIdPtr == B_ANIM_STATS_CHANGE - || *animationIdPtr == B_ANIM_SNATCH_MOVE - || *animationIdPtr == B_ANIM_SUBSTITUTE_FADE) - { - EmitBattleAnimation(0, *animationIdPtr, *argumentPtr); - MarkBufferBankForExecution(gActiveBank); - gBattlescriptCurrInstr += 10; - } - else if (gHitMarker & HITMARKER_NO_ANIMATIONS) - { - gBattlescriptCurrInstr += 10; - } - else if (*animationIdPtr == B_ANIM_RAIN_CONTINUES - || *animationIdPtr == B_ANIM_SUN_CONTINUES - || *animationIdPtr == B_ANIM_SANDSTORM_CONTINUES - || *animationIdPtr == B_ANIM_HAIL_CONTINUES) - { - EmitBattleAnimation(0, *animationIdPtr, *argumentPtr); - MarkBufferBankForExecution(gActiveBank); - gBattlescriptCurrInstr += 10; - } - else if (gStatuses3[gActiveBank] & STATUS3_SEMI_INVULNERABLE) - { - gBattlescriptCurrInstr += 10; - } - else - { - EmitBattleAnimation(0, *animationIdPtr, *argumentPtr); - MarkBufferBankForExecution(gActiveBank); - gBattlescriptCurrInstr += 10; - } -} - -static void atk47_setgraphicalstatchangevalues(void) -{ - u8 value = 0; - switch (gBattleScripting.statChanger & 0xF0) - { - case 0x10: // +1 - value = 0xF; - break; - case 0x20: // +2 - value = 0x27; - break; - case 0x90: // -1 - value = 0x16; - break; - case 0xA0: // -2 - value = 0x2E; - break; - } - gBattleScripting.animArg1 = (gBattleScripting.statChanger & 0xF) + value - 1; - gBattleScripting.animArg2 = 0; - gBattlescriptCurrInstr++; -} - -#ifdef NONMATCHING -static void atk48_playstatchangeanimation(void) -{ - u32 currStat = 0; - s16 statAnimId = 0; - s16 checkingStatAnimId = 0; - s32 changeableStats = 0; - u32 statsToCheck = 0; - - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - statsToCheck = gBattlescriptCurrInstr[2]; - - if (gBattlescriptCurrInstr[3] & ATK48_STAT_NEGATIVE) // goes down - { - checkingStatAnimId = (gBattlescriptCurrInstr[3] & ATK48_STAT_BY_TWO) ? 0x2D : 0x15; - while (statsToCheck != 0) - { - if (statsToCheck & 1) - { - if (!(gBattlescriptCurrInstr[3] & ATK48_LOWER_FAIL_CHECK)) - { - if (gBattleMons[gActiveBank].statStages[currStat] > 0) - { - statAnimId = checkingStatAnimId; - changeableStats++; - } - } - else if (!gSideTimers[GET_BANK_SIDE(gActiveBank)].mistTimer - && gBattleMons[gActiveBank].ability != ABILITY_CLEAR_BODY - && gBattleMons[gActiveBank].ability != ABILITY_WHITE_SMOKE - && !(gBattleMons[gActiveBank].ability == ABILITY_KEEN_EYE && currStat == STAT_STAGE_ACC) - && !(gBattleMons[gActiveBank].ability == ABILITY_HYPER_CUTTER && currStat == STAT_STAGE_ATK)) - { - if (gBattleMons[gActiveBank].statStages[currStat] > 0) - { - statAnimId = checkingStatAnimId; - changeableStats++; - } - } - } - statsToCheck >>= 1, checkingStatAnimId++, currStat++; - } - - if (changeableStats > 1) // more than one stat, so the color is gray - { - if (gBattlescriptCurrInstr[3] & ATK48_STAT_BY_TWO) - statAnimId = 0x3A; - else - statAnimId = 0x39; - } - } - else // goes up - { - checkingStatAnimId = (gBattlescriptCurrInstr[3] & ATK48_STAT_BY_TWO) ? 0x26 : 0xE; - while (statsToCheck != 0) - { - if (statsToCheck & 1 && gBattleMons[gActiveBank].statStages[currStat] < 0xC) - { - statAnimId = checkingStatAnimId; - changeableStats++; - } - statsToCheck >>= 1, checkingStatAnimId += 1, currStat++; - } - - if (changeableStats > 1) // more than one stat, so the color is gray - { - if (gBattlescriptCurrInstr[3] & ATK48_STAT_BY_TWO) - statAnimId = 0x38; - else - statAnimId = 0x37; - } - } - - if (gBattlescriptCurrInstr[3] & ATK48_BIT_x4 && changeableStats < 2) - { - gBattlescriptCurrInstr += 4; - } - else if (changeableStats != 0 && gBattleScripting.field_1B == 0) - { - EmitBattleAnimation(0, B_ANIM_STATS_CHANGE, statAnimId); - MarkBufferBankForExecution(gActiveBank); - if (gBattlescriptCurrInstr[3] & ATK48_BIT_x4 && changeableStats > 1) - gBattleScripting.field_1B = 1; - gBattlescriptCurrInstr += 4; - } - else - { - gBattlescriptCurrInstr += 4; - } -} -#else -__attribute__((naked)) -static void atk48_playstatchangeanimation(void) -{ - asm("\n\ - .syntax unified\n\ - push {r4-r7,lr}\n\ - mov r7, r10\n\ - mov r6, r9\n\ - mov r5, r8\n\ - push {r5-r7}\n\ - sub sp, 0x4\n\ - movs r7, 0\n\ - movs r0, 0\n\ - mov r8, r0\n\ - movs r3, 0\n\ - ldr r5, =gBattlescriptCurrInstr\n\ - ldr r0, [r5]\n\ - ldrb r0, [r0, 0x1]\n\ - str r3, [sp]\n\ - bl GetBattleBank\n\ - ldr r2, =gActiveBank\n\ - strb r0, [r2]\n\ - ldr r0, [r5]\n\ - ldrb r4, [r0, 0x2]\n\ - ldrb r1, [r0, 0x3]\n\ - movs r0, 0x1\n\ - ands r0, r1\n\ - ldr r3, [sp]\n\ - cmp r0, 0\n\ - beq _0804BAEC\n\ - movs r0, 0x2\n\ - ands r0, r1\n\ - movs r1, 0x15\n\ - cmp r0, 0\n\ - beq _0804BA18\n\ - movs r1, 0x2D\n\ -_0804BA18:\n\ - cmp r4, 0\n\ - beq _0804BAC0\n\ - movs r0, 0x1\n\ - mov r10, r0\n\ - ldr r0, =gBattleMons + 0x18\n\ - mov r9, r0\n\ - lsls r5, r1, 16\n\ -_0804BA26:\n\ - adds r0, r4, 0\n\ - mov r1, r10\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _0804BAB2\n\ - ldr r0, =gBattlescriptCurrInstr\n\ - ldr r0, [r0]\n\ - ldrb r1, [r0, 0x3]\n\ - movs r0, 0x8\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _0804BA58\n\ - ldr r0, =gActiveBank\n\ - ldrb r1, [r0]\n\ - movs r0, 0x58\n\ - muls r0, r1\n\ - adds r0, r7, r0\n\ - b _0804BAA0\n\ - .pool\n\ -_0804BA58:\n\ - ldr r6, =gActiveBank\n\ - ldrb r0, [r6]\n\ - str r3, [sp]\n\ - bl GetBankIdentity\n\ - mov r1, r10\n\ - ands r1, r0\n\ - lsls r0, r1, 1\n\ - adds r0, r1\n\ - lsls r0, 2\n\ - ldr r1, =gSideTimers\n\ - adds r0, r1\n\ - ldrb r0, [r0, 0x4]\n\ - ldr r3, [sp]\n\ - cmp r0, 0\n\ - bne _0804BAB2\n\ - ldr r0, =gBattleMons\n\ - ldrb r2, [r6]\n\ - movs r1, 0x58\n\ - muls r2, r1\n\ - adds r0, r2, r0\n\ - adds r0, 0x20\n\ - ldrb r0, [r0]\n\ - cmp r0, 0x1D\n\ - beq _0804BAB2\n\ - cmp r0, 0x49\n\ - beq _0804BAB2\n\ - cmp r0, 0x33\n\ - bne _0804BA96\n\ - cmp r7, 0x6\n\ - beq _0804BAB2\n\ -_0804BA96:\n\ - cmp r0, 0x34\n\ - bne _0804BA9E\n\ - cmp r7, 0x1\n\ - beq _0804BAB2\n\ -_0804BA9E:\n\ - adds r0, r7, r2\n\ -_0804BAA0:\n\ - add r0, r9\n\ - ldrb r0, [r0]\n\ - lsls r0, 24\n\ - asrs r0, 24\n\ - cmp r0, 0\n\ - ble _0804BAB2\n\ - lsrs r0, r5, 16\n\ - mov r8, r0\n\ - adds r3, 0x1\n\ -_0804BAB2:\n\ - lsrs r4, 1\n\ - movs r1, 0x80\n\ - lsls r1, 9\n\ - adds r5, r1\n\ - adds r7, 0x1\n\ - cmp r4, 0\n\ - bne _0804BA26\n\ -_0804BAC0:\n\ - ldr r0, =gBattlescriptCurrInstr\n\ - mov r9, r0\n\ - cmp r3, 0x1\n\ - ble _0804BB4E\n\ - ldr r0, [r0]\n\ - ldrb r1, [r0, 0x3]\n\ - movs r0, 0x2\n\ - ands r0, r1\n\ - movs r1, 0x39\n\ - mov r8, r1\n\ - cmp r0, 0\n\ - beq _0804BB4E\n\ - movs r0, 0x3A\n\ - b _0804BB4C\n\ - .pool\n\ -_0804BAEC:\n\ - movs r0, 0x2\n\ - ands r0, r1\n\ - movs r1, 0xE\n\ - cmp r0, 0\n\ - beq _0804BAF8\n\ - movs r1, 0x26\n\ -_0804BAF8:\n\ - mov r9, r5\n\ - cmp r4, 0\n\ - beq _0804BB34\n\ - ldr r6, =gBattleMons + 0x18\n\ - adds r5, r2, 0\n\ - lsls r2, r1, 16\n\ -_0804BB04:\n\ - movs r0, 0x1\n\ - ands r0, r4\n\ - cmp r0, 0\n\ - beq _0804BB26\n\ - ldrb r1, [r5]\n\ - movs r0, 0x58\n\ - muls r0, r1\n\ - adds r0, r7, r0\n\ - adds r0, r6\n\ - ldrb r0, [r0]\n\ - lsls r0, 24\n\ - asrs r0, 24\n\ - cmp r0, 0xB\n\ - bgt _0804BB26\n\ - lsrs r1, r2, 16\n\ - mov r8, r1\n\ - adds r3, 0x1\n\ -_0804BB26:\n\ - lsrs r4, 1\n\ - movs r0, 0x80\n\ - lsls r0, 9\n\ - adds r2, r0\n\ - adds r7, 0x1\n\ - cmp r4, 0\n\ - bne _0804BB04\n\ -_0804BB34:\n\ - cmp r3, 0x1\n\ - ble _0804BB4E\n\ - mov r1, r9\n\ - ldr r0, [r1]\n\ - ldrb r1, [r0, 0x3]\n\ - movs r0, 0x2\n\ - ands r0, r1\n\ - movs r1, 0x37\n\ - mov r8, r1\n\ - cmp r0, 0\n\ - beq _0804BB4E\n\ - movs r0, 0x38\n\ -_0804BB4C:\n\ - mov r8, r0\n\ -_0804BB4E:\n\ - mov r1, r9\n\ - ldr r2, [r1]\n\ - ldrb r1, [r2, 0x3]\n\ - movs r0, 0x4\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _0804BB6C\n\ - cmp r3, 0x1\n\ - bgt _0804BB6C\n\ - adds r0, r2, 0x4\n\ - mov r1, r9\n\ - b _0804BBBA\n\ - .pool\n\ -_0804BB6C:\n\ - cmp r3, 0\n\ - beq _0804BBB4\n\ - ldr r4, =gBattleScripting\n\ - ldrb r0, [r4, 0x1B]\n\ - cmp r0, 0\n\ - bne _0804BBB4\n\ - movs r0, 0\n\ - movs r1, 0x1\n\ - mov r2, r8\n\ - str r3, [sp]\n\ - bl EmitBattleAnimation\n\ - ldr r0, =gActiveBank\n\ - ldrb r0, [r0]\n\ - bl MarkBufferBankForExecution\n\ - ldr r0, =gBattlescriptCurrInstr\n\ - ldr r0, [r0]\n\ - ldrb r1, [r0, 0x3]\n\ - movs r0, 0x4\n\ - ands r0, r1\n\ - ldr r3, [sp]\n\ - cmp r0, 0\n\ - beq _0804BBA4\n\ - cmp r3, 0x1\n\ - ble _0804BBA4\n\ - movs r0, 0x1\n\ - strb r0, [r4, 0x1B]\n\ -_0804BBA4:\n\ - ldr r1, =gBattlescriptCurrInstr\n\ - b _0804BBB6\n\ - .pool\n\ -_0804BBB4:\n\ - mov r1, r9\n\ -_0804BBB6:\n\ - ldr r0, [r1]\n\ - adds r0, 0x4\n\ -_0804BBBA:\n\ - str r0, [r1]\n\ - add sp, 0x4\n\ - pop {r3-r5}\n\ - mov r8, r3\n\ - mov r9, r4\n\ - mov r10, r5\n\ - pop {r4-r7}\n\ - pop {r0}\n\ - bx r0\n\ - .syntax divided"); -} -#endif // NONMATCHING - -#define ATK49_LAST_CASE 17 - -static void atk49_moveend(void) -{ - s32 i; - bool32 effect; - u8 moveType; - u8 holdEffectAtk; - u16 *choicedMoveAtk; - u8 arg1, arg2; - u16 lastMove; - - effect = FALSE; - - if (gLastUsedMove == 0xFFFF) - lastMove = 0; - else - lastMove = gLastUsedMove; - - arg1 = gBattlescriptCurrInstr[1]; - arg2 = gBattlescriptCurrInstr[2]; - - if (gBattleMons[gBankAttacker].item == ITEM_ENIGMA_BERRY) - holdEffectAtk = gEnigmaBerries[gBankAttacker].holdEffect; - else - holdEffectAtk = ItemId_GetHoldEffect(gBattleMons[gBankAttacker].item); - - choicedMoveAtk = &gBattleStruct->choicedMove[gBankAttacker]; - - GET_MOVE_TYPE(gCurrentMove, moveType); - - do - { - switch (gBattleScripting.atk49_state) - { - case 0: // rage check - if (gBattleMons[gBankTarget].status2 & STATUS2_RAGE - && gBattleMons[gBankTarget].hp != 0 && gBankAttacker != gBankTarget - && GetBankSide(gBankAttacker) != GetBankSide(gBankTarget) - && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT) && TARGET_TURN_DAMAGED - && gBattleMoves[gCurrentMove].power && gBattleMons[gBankTarget].statStages[STAT_STAGE_ATK] <= 0xB) - { - gBattleMons[gBankTarget].statStages[STAT_STAGE_ATK]++; - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_RageIsBuilding; - effect = TRUE; - } - gBattleScripting.atk49_state++; - break; - case 1: // defrosting check - if (gBattleMons[gBankTarget].status1 & STATUS_FREEZE - && gBattleMons[gBankTarget].hp != 0 && gBankAttacker != gBankTarget - && gSpecialStatuses[gBankTarget].moveturnLostHP_special - && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT) && moveType == TYPE_FIRE) - { - gBattleMons[gBankTarget].status1 &= ~(STATUS_FREEZE); - gActiveBank = gBankTarget; - EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gBankTarget].status1); - MarkBufferBankForExecution(gActiveBank); - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_DefrostedViaFireMove; - effect = TRUE; - } - gBattleScripting.atk49_state++; - break; - case 2: // target synchronize - if (AbilityBattleEffects(ABILITYEFFECT_SYNCHRONIZE, gBankTarget, 0, 0, 0)) - effect = TRUE; - gBattleScripting.atk49_state++; - break; - case 3: // contact abilities - if (AbilityBattleEffects(ABILITYEFFECT_CONTACT, gBankTarget, 0, 0, 0)) - effect = TRUE; - gBattleScripting.atk49_state++; - break; - case 4: // status immunities - if (AbilityBattleEffects(ABILITYEFFECT_IMMUNITY, 0, 0, 0, 0)) - effect = TRUE; // it loops through all banks, so we increment after its done with all banks - else - gBattleScripting.atk49_state++; - break; - case 5: // attacker synchronize - if (AbilityBattleEffects(ABILITYEFFECT_ATK_SYNCHRONIZE, gBankAttacker, 0, 0, 0)) - effect = TRUE; - gBattleScripting.atk49_state++; - break; - case 6: // update choice band move - if (!(gHitMarker & HITMARKER_OBEYS) || holdEffectAtk != HOLD_EFFECT_CHOICE_BAND - || gLastUsedMove == MOVE_STRUGGLE || (*choicedMoveAtk != 0 && *choicedMoveAtk != 0xFFFF)) - goto LOOP; - if (gLastUsedMove == MOVE_BATON_PASS && !(gBattleMoveFlags & MOVESTATUS_FAILED)) - { - gBattleScripting.atk49_state++; - break; - } - *choicedMoveAtk = gLastUsedMove; - LOOP: - { - for (i = 0; i < 4; i++) - { - if (gBattleMons[gBankAttacker].moves[i] == *choicedMoveAtk) - break; - } - if (i == 4) - *choicedMoveAtk = 0; - - gBattleScripting.atk49_state++; - } - break; - case 7: // changed held items - for (i = 0; i < gNoOfAllBanks; i++) - { - u16* changedItem = &gBattleStruct->changedItems[i]; - if (*changedItem != 0) - { - gBattleMons[i].item = *changedItem; - *changedItem = 0; - } - } - gBattleScripting.atk49_state++; - break; - case 11: // item effects for all banks - if (ItemBattleEffects(3, 0, FALSE)) - effect = TRUE; - else - gBattleScripting.atk49_state++; - break; - case 12: // king's rock and shell bell - if (ItemBattleEffects(4, 0, FALSE)) - effect = TRUE; - gBattleScripting.atk49_state++; - break; - case 8: // make attacker sprite invisible - if (gStatuses3[gBankAttacker] & (STATUS3_SEMI_INVULNERABLE) - && gHitMarker & HITMARKER_NO_ANIMATIONS) - { - gActiveBank = gBankAttacker; - EmitSpriteInvisibility(0, TRUE); - MarkBufferBankForExecution(gActiveBank); - gBattleScripting.atk49_state++; - return; - } - gBattleScripting.atk49_state++; - break; - case 9: // make attacker sprite visible - if (gBattleMoveFlags & MOVESTATUS_NOEFFECT - || !(gStatuses3[gBankAttacker] & (STATUS3_SEMI_INVULNERABLE)) - || HasMoveFailed(gBankAttacker)) - { - gActiveBank = gBankAttacker; - EmitSpriteInvisibility(0, FALSE); - MarkBufferBankForExecution(gActiveBank); - gStatuses3[gBankAttacker] &= ~(STATUS3_SEMI_INVULNERABLE); - gSpecialStatuses[gBankAttacker].restoredBankSprite = 1; - gBattleScripting.atk49_state++; - return; - } - gBattleScripting.atk49_state++; - break; - case 10: // make target sprite visible - if (!gSpecialStatuses[gBankTarget].restoredBankSprite && gBankTarget < gNoOfAllBanks - && !(gStatuses3[gBankTarget] & STATUS3_SEMI_INVULNERABLE)) - { - gActiveBank = gBankTarget; - EmitSpriteInvisibility(0, FALSE); - MarkBufferBankForExecution(gActiveBank); - gStatuses3[gBankTarget] &= ~(STATUS3_SEMI_INVULNERABLE); - gBattleScripting.atk49_state++; - return; - } - gBattleScripting.atk49_state++; - break; - case 13: // update substitute - for (i = 0; i < gNoOfAllBanks; i++) - { - if (gDisableStructs[i].substituteHP == 0) - gBattleMons[i].status2 &= ~(STATUS2_SUBSTITUTE); - } - gBattleScripting.atk49_state++; - break; - case 14: // This case looks interesting, although I am not certain what it does. Probably fine tunes edge cases. - if (gHitMarker & HITMARKER_PURSUIT_TRAP) - { - gActiveBank = gBankAttacker; - gBankAttacker = gBankTarget; - gBankTarget = gActiveBank; - gHitMarker &= ~(HITMARKER_PURSUIT_TRAP); - } - if (gHitMarker & HITMARKER_ATTACKSTRING_PRINTED) - { - gUnknownMovesUsedByBanks[gBankAttacker] = gLastUsedMove; - } - if (!(gAbsentBankFlags & gBitTable[gBankAttacker]) - && !(gBattleStruct->field_91 & gBitTable[gBankAttacker]) - && gBattleMoves[lastMove].effect != EFFECT_BATON_PASS) - { - if (gHitMarker & HITMARKER_OBEYS) - { - gLastUsedMovesByBanks[gBankAttacker] = gLastUsedMove; - gUnknown_02024260[gBankAttacker] = gCurrentMove; - } - else - { - gLastUsedMovesByBanks[gBankAttacker] = 0xFFFF; - gUnknown_02024260[gBankAttacker] = 0xFFFF; - } - - if (!(gHitMarker & HITMARKER_FAINTED(gBankTarget))) - gUnknown_02024270[gBankTarget] = gBankAttacker; - - if (gHitMarker & HITMARKER_OBEYS && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) - { - if (gLastUsedMove == 0xFFFF) - { - gUnknown_02024250[gBankTarget] = gLastUsedMove; - } - else - { - gUnknown_02024250[gBankTarget] = gCurrentMove; - GET_MOVE_TYPE(gCurrentMove, gUnknown_02024258[gBankTarget]); - } - } - else - { - gUnknown_02024250[gBankTarget] = 0xFFFF; - } - } - gBattleScripting.atk49_state++; - break; - case 15: // mirror move - if (!(gAbsentBankFlags & gBitTable[gBankAttacker]) && !(gBattleStruct->field_91 & gBitTable[gBankAttacker]) - && gBattleMoves[lastMove].flags & FLAG_MIRROR_MOVE_AFFECTED && gHitMarker & HITMARKER_OBEYS - && gBankAttacker != gBankTarget && !(gHitMarker & HITMARKER_FAINTED(gBankTarget)) - && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) - { - u8 target, attacker; - - *(gBattleStruct->mirrorMoves + gBankTarget * 2 + 0) = gLastUsedMove; - *(gBattleStruct->mirrorMoves + gBankTarget * 2 + 1) = gLastUsedMove >> 8; - - target = gBankTarget; - attacker = gBankAttacker; - *(attacker * 2 + target * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = gLastUsedMove; - - target = gBankTarget; - attacker = gBankAttacker; - *(attacker * 2 + target * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) = gLastUsedMove >> 8; - } - gBattleScripting.atk49_state++; - break; - case 16: // - if (!(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) && gBattleTypeFlags & BATTLE_TYPE_DOUBLE - && !gProtectStructs[gBankAttacker].chargingTurn && gBattleMoves[gCurrentMove].target == MOVE_TARGET_BOTH - && !(gHitMarker & HITMARKER_NO_ATTACKSTRING)) - { - u8 bank = GetBankByIdentity(GetBankIdentity(gBankTarget) ^ BIT_MON); - if (gBattleMons[bank].hp != 0) - { - gBankTarget = bank; - gHitMarker |= HITMARKER_NO_ATTACKSTRING; - gBattleScripting.atk49_state = 0; - MoveValuesCleanUp(); - BattleScriptPush(gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]); - gBattlescriptCurrInstr = gUnknown_082DB87D; - return; - } - else - { - gHitMarker |= HITMARKER_NO_ATTACKSTRING; - } - } - gBattleScripting.atk49_state++; - break; - case ATK49_LAST_CASE: - break; - } - - if (arg1 == 1 && effect == FALSE) - gBattleScripting.atk49_state = ATK49_LAST_CASE; - if (arg1 == 2 && arg2 == gBattleScripting.atk49_state) - gBattleScripting.atk49_state = ATK49_LAST_CASE; - - } while (gBattleScripting.atk49_state != ATK49_LAST_CASE && effect == FALSE); - - if (gBattleScripting.atk49_state == ATK49_LAST_CASE && effect == FALSE) - gBattlescriptCurrInstr += 3; -} - -static void atk4A_typecalc2(void) -{ - u8 flags = 0; - s32 i = 0; - u8 moveType = gBattleMoves[gCurrentMove].type; - - if (gBattleMons[gBankTarget].ability == ABILITY_LEVITATE && moveType == TYPE_GROUND) - { - gLastUsedAbility = gBattleMons[gBankTarget].ability; - gBattleMoveFlags |= (MOVESTATUS_MISSED | MOVESTATUS_NOTAFFECTED); - gUnknown_02024250[gBankTarget] = 0; - gBattleCommunication[6] = moveType; - RecordAbilityBattle(gBankTarget, gLastUsedAbility); - } - else - { - while (gTypeEffectiveness[i]!= TYPE_ENDTABLE) - { - if (gTypeEffectiveness[i] == TYPE_FORESIGHT) - { - if (gBattleMons[gBankTarget].status2 & STATUS2_FORESIGHT) - { - break; - } - else - { - i += 3; - continue; - } - } - - if (gTypeEffectiveness[i] == moveType) - { - // check type1 - if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type1) - { - if (gTypeEffectiveness[i + 2] == 0) - { - gBattleMoveFlags |= MOVESTATUS_NOTAFFECTED; - break; - } - if (gTypeEffectiveness[i + 2] == 5) - { - flags |= MOVESTATUS_NOTVERYEFFECTIVE; - } - if (gTypeEffectiveness[i + 2] == 20) - { - flags |= MOVESTATUS_SUPEREFFECTIVE; - } - } - // check type2 - if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type2) - { - if (gBattleMons[gBankTarget].type1 != gBattleMons[gBankTarget].type2 - && gTypeEffectiveness[i + 2] == 0) - { - gBattleMoveFlags |= MOVESTATUS_NOTAFFECTED; - break; - } - if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type2 - && gBattleMons[gBankTarget].type1 != gBattleMons[gBankTarget].type2 - && gTypeEffectiveness[i + 2] == 5) - { - flags |= MOVESTATUS_NOTVERYEFFECTIVE; - } - if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type2 - && gBattleMons[gBankTarget].type1 != gBattleMons[gBankTarget].type2 - && gTypeEffectiveness[i + 2] == 20) - { - flags |= MOVESTATUS_SUPEREFFECTIVE; - } - } - } - i += 3; - } - } - - if (gBattleMons[gBankTarget].ability == ABILITY_WONDER_GUARD - && !(flags & MOVESTATUS_NOEFFECT) - && AttacksThisTurn(gBankAttacker, gCurrentMove) == 2 - && (!(flags & MOVESTATUS_SUPEREFFECTIVE) || ((flags & (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE)) == (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE))) - && gBattleMoves[gCurrentMove].power) - { - gLastUsedAbility = ABILITY_WONDER_GUARD; - gBattleMoveFlags |= MOVESTATUS_MISSED; - gUnknown_02024250[gBankTarget] = 0; - gBattleCommunication[6] = 3; - RecordAbilityBattle(gBankTarget, gLastUsedAbility); - } - if (gBattleMoveFlags & MOVESTATUS_NOTAFFECTED) - gProtectStructs[gBankAttacker].notEffective = 1; - - gBattlescriptCurrInstr++; -} - -static void atk4B_return_atk_to_ball(void) -{ - gActiveBank = gBankAttacker; - if (!(gHitMarker & HITMARKER_FAINTED(gActiveBank))) - { - EmitReturnPokeToBall(0, 0); - MarkBufferBankForExecution(gActiveBank); - } - gBattlescriptCurrInstr++; -} - -static void atk4C_copy_poke_data(void) -{ - if (gBattleExecBuffer) - return; - - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - - gBattlePartyID[gActiveBank] = *(gBattleStruct->field_5C + gActiveBank); - - EmitGetMonData(0, 0, gBitTable[gBattlePartyID[gActiveBank]]); - MarkBufferBankForExecution(gActiveBank); - - gBattlescriptCurrInstr += 2; -} - -static void atk4D_switch_data_update(void) -{ - struct BattlePokemon oldData; - s32 i; - u8 *monData; - - if (gBattleExecBuffer) - return; - - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - oldData = gBattleMons[gActiveBank]; - monData = (u8*)(&gBattleMons[gActiveBank]); - - for (i = 0; i < sizeof(struct BattlePokemon); i++) - { - monData[i] = gBattleBufferB[gActiveBank][4 + i]; - } - - gBattleMons[gActiveBank].type1 = gBaseStats[gBattleMons[gActiveBank].species].type1; - gBattleMons[gActiveBank].type2 = gBaseStats[gBattleMons[gActiveBank].species].type2; - gBattleMons[gActiveBank].ability = GetAbilityBySpecies(gBattleMons[gActiveBank].species, gBattleMons[gActiveBank].altAbility); - - // check knocked off item - i = GetBankSide(gActiveBank); - if (gWishFutureKnock.knockedOffPokes[i] & gBitTable[gBattlePartyID[gActiveBank]]) - { - gBattleMons[gActiveBank].item = 0; - } - - if (gBattleMoves[gCurrentMove].effect == EFFECT_BATON_PASS) - { - for (i = 0; i < 8; i++) - { - gBattleMons[gActiveBank].statStages[i] = oldData.statStages[i]; - } - gBattleMons[gActiveBank].status2 = oldData.status2; - } - - SwitchInClearStructs(); - - if (gBattleTypeFlags & BATTLE_TYPE_PALACE && gBattleMons[gActiveBank].maxHP / 2 >= gBattleMons[gActiveBank].hp - && gBattleMons[gActiveBank].hp != 0 && !(gBattleMons[gActiveBank].status1 & STATUS_SLEEP)) - { - gBattleStruct->field_92 |= gBitTable[gActiveBank]; - } - - gBattleScripting.bank = gActiveBank; - gBattleTextBuff1[0] = PLACEHOLDER_BEGIN; - gBattleTextBuff1[1] = 7; - gBattleTextBuff1[2] = gActiveBank; - gBattleTextBuff1[3] = gBattlePartyID[gActiveBank]; - gBattleTextBuff1[4] = EOS; - - gBattlescriptCurrInstr += 2; -} - -static void atk4E_switchin_anim(void) -{ - if (gBattleExecBuffer) - return; - - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - - if (GetBankSide(gActiveBank) == SIDE_OPPONENT - && !(gBattleTypeFlags & (BATTLE_TYPE_LINK - | BATTLE_TYPE_EREADER_TRAINER - | BATTLE_TYPE_x2000000 - | BATTLE_TYPE_x4000000 - | BATTLE_TYPE_FRONTIER))) - HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gActiveBank].species), FLAG_SET_SEEN, gBattleMons[gActiveBank].personality); - - gAbsentBankFlags &= ~(gBitTable[gActiveBank]); - - EmitSwitchInAnim(0, gBattlePartyID[gActiveBank], gBattlescriptCurrInstr[2]); - MarkBufferBankForExecution(gActiveBank); - - gBattlescriptCurrInstr += 3; - - if (gBattleTypeFlags & BATTLE_TYPE_ARENA) - sub_81A56B4(); -} - -static void atk4F_jump_if_cannot_switch(void) -{ - s32 val = 0; - s32 compareVar = 0; - struct Pokemon *party = NULL; - s32 r7 = 0; - - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1] & ~(ATK4F_DONT_CHECK_STATUSES)); - - if (!(gBattlescriptCurrInstr[1] & ATK4F_DONT_CHECK_STATUSES) - && ((gBattleMons[gActiveBank].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION)) - || (gStatuses3[gActiveBank] & STATUS3_ROOTED))) - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); - } - else if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) - { - #ifndef NONMATCHING - asm("":::"r5"); - #endif // NONMATCHING - if (GetBankSide(gActiveBank) == SIDE_OPPONENT) - party = gEnemyParty; - else - party = gPlayerParty; - - val = 0; - if (2 & gActiveBank) - val = 3; - - for (compareVar = val + 3; val < compareVar; val++) - { - if (GetMonData(&party[val], MON_DATA_SPECIES) != SPECIES_NONE - && !GetMonData(&party[val], MON_DATA_IS_EGG) - && GetMonData(&party[val], MON_DATA_HP) != 0 - && gBattlePartyID[gActiveBank] != val) - break; - } - - if (val == compareVar) - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); - else - gBattlescriptCurrInstr += 6; - } - else if (gBattleTypeFlags & BATTLE_TYPE_MULTI) - { - if (gBattleTypeFlags & BATTLE_TYPE_x800000) - { - if (GetBankSide(gActiveBank) == SIDE_PLAYER) - { - party = gPlayerParty; - - val = 0; - if (sub_806D82C(sub_806D864(gActiveBank)) == TRUE) - val = 3; - } - else - { - party = gEnemyParty; - - if (gActiveBank == 1) - val = 0; - else - val = 3; - } - } - else - { - if (GetBankSide(gActiveBank) == SIDE_OPPONENT) - party = gEnemyParty; - else - party = gPlayerParty; - - - val = 0; - if (sub_806D82C(sub_806D864(gActiveBank)) == TRUE) - val = 3; - } - - for (compareVar = val + 3; val < compareVar; val++) - { - if (GetMonData(&party[val], MON_DATA_SPECIES) != SPECIES_NONE - && !GetMonData(&party[val], MON_DATA_IS_EGG) - && GetMonData(&party[val], MON_DATA_HP) != 0 - && gBattlePartyID[gActiveBank] != val) - break; - } - - if (val == compareVar) - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); - else - gBattlescriptCurrInstr += 6; - } - else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS && GetBankSide(gActiveBank) == SIDE_OPPONENT) - { - party = gEnemyParty; - - val = 0; - if (gActiveBank == 3) - val = 3; - - for (compareVar = val + 3; val < compareVar; val++) - { - if (GetMonData(&party[val], MON_DATA_SPECIES) != SPECIES_NONE - && !GetMonData(&party[val], MON_DATA_IS_EGG) - && GetMonData(&party[val], MON_DATA_HP) != 0 - && gBattlePartyID[gActiveBank] != val) - break; - } - - if (val == compareVar) - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); - else - gBattlescriptCurrInstr += 6; - } - else - { - if (GetBankSide(gActiveBank) == SIDE_OPPONENT) - { - r7 = GetBankByIdentity(1); - - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) - compareVar = GetBankByIdentity(3); - else - compareVar = r7; - - party = gEnemyParty; - } - else - { - r7 = GetBankByIdentity(0); - - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) - compareVar = GetBankByIdentity(2); - else - compareVar = r7; - - party = gPlayerParty; - } - for (val = 0; val < 6; val++) - { - if (GetMonData(&party[val], MON_DATA_HP) != 0 - && GetMonData(&party[val], MON_DATA_SPECIES) != SPECIES_NONE - && !GetMonData(&party[val], MON_DATA_IS_EGG) - && val != gBattlePartyID[r7] && val != gBattlePartyID[compareVar]) - break; - } - - if (val == 6) - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); - else - gBattlescriptCurrInstr += 6; - } -} - -static void sub_804CF10(u8 arg0) -{ - *(gBattleStruct->field_58 + gActiveBank) = gBattlePartyID[gActiveBank]; - *(gBattleStruct->field_5C + gActiveBank) = 6; - gBattleStruct->field_93 &= ~(gBitTable[gActiveBank]); - - EmitChoosePokemon(0, 1, arg0, 0, gBattleStruct->field_60[gActiveBank]); - MarkBufferBankForExecution(gActiveBank); -} - -static void atk50_openpartyscreen(void) -{ - u32 flags; - u8 hitmarkerFaintBits; - u8 bank; - const u8 *jumpPtr; - - bank = 0; - flags = 0; - jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); - - if (gBattlescriptCurrInstr[1] == 5) - { - if ((gBattleTypeFlags & (BATTLE_TYPE_DOUBLE | BATTLE_TYPE_MULTI)) != BATTLE_TYPE_DOUBLE) - { - for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++) - { - if (gHitMarker & HITMARKER_FAINTED(gActiveBank)) - { - if (sub_80423F4(gActiveBank, 6, 6)) - { - gAbsentBankFlags |= gBitTable[gActiveBank]; - gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); - EmitLinkStandbyMsg(0, 2, 0); - MarkBufferBankForExecution(gActiveBank); - } - else if (!gSpecialStatuses[gActiveBank].flag40) - { - sub_804CF10(6); - gSpecialStatuses[gActiveBank].flag40 = 1; - } - } - else - { - EmitLinkStandbyMsg(0, 2, 0); - MarkBufferBankForExecution(gActiveBank); - } - } - } - else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) - { - u8 flag40_0, flag40_1, flag40_2, flag40_3; - - hitmarkerFaintBits = gHitMarker >> 0x1C; - - if (gBitTable[0] & hitmarkerFaintBits) - { - gActiveBank = 0; - if (sub_80423F4(0, 6, 6)) - { - gAbsentBankFlags |= gBitTable[gActiveBank]; - gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); - Emit_x2A(0); - MarkBufferBankForExecution(gActiveBank); - } - else if (!gSpecialStatuses[gActiveBank].flag40) - { - sub_804CF10(gBattleStruct->field_5C[2]); - gSpecialStatuses[gActiveBank].flag40 = 1; - } - else - { - EmitLinkStandbyMsg(0, 2, 0); - MarkBufferBankForExecution(gActiveBank); - flags |= 1; - } - } - if (gBitTable[2] & hitmarkerFaintBits && !(gBitTable[0] & hitmarkerFaintBits)) - { - gActiveBank = 2; - if (sub_80423F4(2, 6, 6)) - { - gAbsentBankFlags |= gBitTable[gActiveBank]; - gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); - Emit_x2A(0); - MarkBufferBankForExecution(gActiveBank); - } - else if (!gSpecialStatuses[gActiveBank].flag40) - { - sub_804CF10(gBattleStruct->field_5C[0]); - gSpecialStatuses[gActiveBank].flag40 = 1; - } - else if (!(flags & 1)) - { - EmitLinkStandbyMsg(0, 2, 0); - MarkBufferBankForExecution(gActiveBank); - } - } - if (gBitTable[1] & hitmarkerFaintBits) - { - gActiveBank = 1; - if (sub_80423F4(1, 6, 6)) - { - gAbsentBankFlags |= gBitTable[gActiveBank]; - gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); - Emit_x2A(0); - MarkBufferBankForExecution(gActiveBank); - } - else if (!gSpecialStatuses[gActiveBank].flag40) - { - sub_804CF10(gBattleStruct->field_5C[3]); - gSpecialStatuses[gActiveBank].flag40 = 1; - } - else - { - EmitLinkStandbyMsg(0, 2, 0); - MarkBufferBankForExecution(gActiveBank); - flags |= 2; - } - } - if (gBitTable[3] & hitmarkerFaintBits && !(gBitTable[1] & hitmarkerFaintBits)) - { - gActiveBank = 3; - if (sub_80423F4(3, 6, 6)) - { - gAbsentBankFlags |= gBitTable[gActiveBank]; - gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); - Emit_x2A(0); - MarkBufferBankForExecution(gActiveBank); - } - else if (!gSpecialStatuses[gActiveBank].flag40) - { - sub_804CF10(gBattleStruct->field_5C[1]); - gSpecialStatuses[gActiveBank].flag40 = 1; - } - else if (!(flags & 2)) - { - EmitLinkStandbyMsg(0, 2, 0); - MarkBufferBankForExecution(gActiveBank); - } - } - - flag40_0 = gSpecialStatuses[0].flag40; - if (!flag40_0) - { - flag40_2 = gSpecialStatuses[2].flag40; - if (!flag40_2 && hitmarkerFaintBits != 0) - { - if (gAbsentBankFlags & gBitTable[0]) - gActiveBank = 2; - else - gActiveBank = 0; - - EmitLinkStandbyMsg(0, 2, 0); - MarkBufferBankForExecution(gActiveBank); - } - - } - flag40_1 = gSpecialStatuses[1].flag40; - if (!flag40_1) - { - flag40_3 = gSpecialStatuses[3].flag40; - if (!flag40_3 && hitmarkerFaintBits != 0) - { - if (gAbsentBankFlags & gBitTable[1]) - gActiveBank = 3; - else - gActiveBank = 1; - - EmitLinkStandbyMsg(0, 2, 0); - MarkBufferBankForExecution(gActiveBank); - } - } - } - gBattlescriptCurrInstr += 6; - } - else if (gBattlescriptCurrInstr[1] == 6) - { - if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI)) - { - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) - { - hitmarkerFaintBits = gHitMarker >> 0x1C; - if (gBitTable[2] & hitmarkerFaintBits && gBitTable[0] & hitmarkerFaintBits) - { - gActiveBank = 2; - if (sub_80423F4(2, gBattleBufferB[0][1], 6)) - { - gAbsentBankFlags |= gBitTable[gActiveBank]; - gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); - Emit_x2A(0); - MarkBufferBankForExecution(gActiveBank); - } - else if (!gSpecialStatuses[gActiveBank].flag40) - { - sub_804CF10(gBattleStruct->field_5C[0]); - gSpecialStatuses[gActiveBank].flag40 = 1; - } - } - if (gBitTable[3] & hitmarkerFaintBits && hitmarkerFaintBits & gBitTable[1]) - { - gActiveBank = 3; - if (sub_80423F4(3, gBattleBufferB[1][1], 6)) - { - gAbsentBankFlags |= gBitTable[gActiveBank]; - gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); - Emit_x2A(0); - MarkBufferBankForExecution(gActiveBank); - } - else if (!gSpecialStatuses[gActiveBank].flag40) - { - sub_804CF10(gBattleStruct->field_5C[1]); - gSpecialStatuses[gActiveBank].flag40 = 1; - } - } - gBattlescriptCurrInstr += 6; - } - else - { - gBattlescriptCurrInstr += 6; - } - } - else - { - gBattlescriptCurrInstr += 6; - } - - hitmarkerFaintBits = gHitMarker >> 0x1C; - - gBank1 = 0; - while (1) - { - if (gBitTable[gBank1] & hitmarkerFaintBits) - break; - if (gBank1 >= gNoOfAllBanks) - break; - gBank1++; - } - - if (gBank1 == gNoOfAllBanks) - gBattlescriptCurrInstr = jumpPtr; - } - else - { - if (gBattlescriptCurrInstr[1] & 0x80) - hitmarkerFaintBits = 0; // used here as the caseId for the EmitChoose function - else - hitmarkerFaintBits = 1; - - bank = GetBattleBank(gBattlescriptCurrInstr[1] & ~(0x80)); - if (gSpecialStatuses[bank].flag40) - { - gBattlescriptCurrInstr += 6; - } - else if (sub_80423F4(bank, 6, 6)) - { - gActiveBank = bank; - gAbsentBankFlags |= gBitTable[gActiveBank]; - gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); - gBattlescriptCurrInstr = jumpPtr; - } - else - { - gActiveBank = bank; - *(gBattleStruct->field_58 + gActiveBank) = gBattlePartyID[gActiveBank]; - *(gBattleStruct->field_5C + gActiveBank) = 6; - gBattleStruct->field_93 &= ~(gBitTable[gActiveBank]); - - EmitChoosePokemon(0, hitmarkerFaintBits, *(gBattleStruct->field_5C + (gActiveBank ^ 2)), 0, gBattleStruct->field_60[gActiveBank]); - MarkBufferBankForExecution(gActiveBank); - - gBattlescriptCurrInstr += 6; - - if (GetBankIdentity(gActiveBank) == 0 && gBattleResults.playerSwitchesCounter < 0xFF) - gBattleResults.playerSwitchesCounter++; - - if (gBattleTypeFlags & BATTLE_TYPE_MULTI) - { - for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++) - { - if (gActiveBank != bank) - { - EmitLinkStandbyMsg(0, 2, 0); - MarkBufferBankForExecution(gActiveBank); - } - } - } - else - { - gActiveBank = GetBankByIdentity(GetBankIdentity(bank) ^ BIT_SIDE); - if (gAbsentBankFlags & gBitTable[gActiveBank]) - gActiveBank ^= BIT_MON; - - EmitLinkStandbyMsg(0, 2, 0); - MarkBufferBankForExecution(gActiveBank); - } - } - } -} - -static void atk51_switch_handle_order(void) -{ - s32 i; - if (gBattleExecBuffer) - return; - - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - - switch (gBattlescriptCurrInstr[2]) - { - case 0: - for (i = 0; i < gNoOfAllBanks; i++) - { - if (gBattleBufferB[i][0] == 0x22) - { - *(gBattleStruct->field_5C + i) = gBattleBufferB[i][1]; - if (!(gBattleStruct->field_93 & gBitTable[i])) - { - RecordedBattle_SetBankAction(i, gBattleBufferB[i][1]); - gBattleStruct->field_93 |= gBitTable[i]; - } - } - } - break; - case 1: - if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI)) - sub_803BDA0(gActiveBank); - break; - case 2: - if (!(gBattleStruct->field_93 & gBitTable[gActiveBank])) - { - RecordedBattle_SetBankAction(gActiveBank, gBattleBufferB[gActiveBank][1]); - gBattleStruct->field_93 |= gBitTable[gActiveBank]; - } - // fall through - case 3: - gBattleCommunication[0] = gBattleBufferB[gActiveBank][1]; - *(gBattleStruct->field_5C + gActiveBank) = gBattleBufferB[gActiveBank][1]; - - if ((gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_LINK)) == (BATTLE_TYPE_MULTI | BATTLE_TYPE_LINK)) - { - *(gActiveBank * 3 + (u8*)(gBattleStruct->field_60) + 0) &= 0xF; - *(gActiveBank * 3 + (u8*)(gBattleStruct->field_60) + 0) |= (gBattleBufferB[gActiveBank][2] & 0xF0); - *(gActiveBank * 3 + (u8*)(gBattleStruct->field_60) + 1) = gBattleBufferB[gActiveBank][3]; - - *((gActiveBank ^ 2) * 3 + (u8*)(gBattleStruct->field_60) + 0) &= (0xF0); - *((gActiveBank ^ 2) * 3 + (u8*)(gBattleStruct->field_60) + 0) |= (gBattleBufferB[gActiveBank][2] & 0xF0) >> 4; - *((gActiveBank ^ 2) * 3 + (u8*)(gBattleStruct->field_60) + 2) = gBattleBufferB[gActiveBank][3]; - } - else if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) - { - sub_80571DC(gActiveBank, *(gBattleStruct->field_5C + gActiveBank)); - } - else - { - sub_803BDA0(gActiveBank); - } - - PREPARE_SPECIES_BUFFER(gBattleTextBuff1, gBattleMons[gBankAttacker].species) - PREPARE_MON_NICK_BUFFER(gBattleTextBuff2, gActiveBank, gBattleBufferB[gActiveBank][1]) - - break; - } - - gBattlescriptCurrInstr += 3; -} - -static void atk52_switch_in_effects(void) -{ - s32 i; - - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - sub_803FA70(gActiveBank); - - gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); - gSpecialStatuses[gActiveBank].flag40 = 0; - - if (!(gSideAffecting[GetBankSide(gActiveBank)] & SIDE_STATUS_SPIKES_DAMAGED) - && (gSideAffecting[GetBankSide(gActiveBank)] & SIDE_STATUS_SPIKES) - && gBattleMons[gActiveBank].type1 != TYPE_FLYING - && gBattleMons[gActiveBank].type2 != TYPE_FLYING - && gBattleMons[gActiveBank].ability != ABILITY_LEVITATE) - { - u8 spikesDmg; - - gSideAffecting[GetBankSide(gActiveBank)] |= SIDE_STATUS_SPIKES_DAMAGED; - - gBattleMons[gActiveBank].status2 &= ~(STATUS2_DESTINY_BOND); - gHitMarker &= ~(HITMARKER_DESTINYBOND); - - spikesDmg = (5 - gSideTimers[GetBankSide(gActiveBank)].spikesAmount) * 2; - gBattleMoveDamage = gBattleMons[gActiveBank].maxHP / (spikesDmg); - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - - gBattleScripting.bank = gActiveBank; - BattleScriptPushCursor(); - - if (gBattlescriptCurrInstr[1] == 0) - gBattlescriptCurrInstr = gUnknown_082DAE90; - else if (gBattlescriptCurrInstr[1] == 1) - gBattlescriptCurrInstr = gUnknown_082DAE59; - else - gBattlescriptCurrInstr = gUnknown_082DAEC7; - } - else - { - if (gBattleMons[gActiveBank].ability == ABILITY_TRUANT && !gDisableStructs[gActiveBank].truantUnknownBit) - gDisableStructs[gActiveBank].truantCounter = 1; - - gDisableStructs[gActiveBank].truantUnknownBit = 0; - - if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, gActiveBank, 0, 0, 0) == 0 && - ItemBattleEffects(0, gActiveBank, 0) == 0) - { - gSideAffecting[GetBankSide(gActiveBank)] &= ~(SIDE_STATUS_SPIKES_DAMAGED); - - for (i = 0; i < gNoOfAllBanks; i++) - { - if (gTurnOrder[i] == gActiveBank) - gUnknown_0202407A[i] = 0xC; - } - - for (i = 0; i < gNoOfAllBanks; i++) - { - u16* hpOnSwitchout = &gBattleStruct->hpOnSwitchout[GetBankSide(i)]; - *hpOnSwitchout = gBattleMons[i].hp; - } - - if (gBattlescriptCurrInstr[1] == 5) - { - u32 hitmarkerFaintBits = gHitMarker >> 0x1C; - - gBank1++; - while (1) - { - if (hitmarkerFaintBits & gBitTable[gBank1] && !(gAbsentBankFlags & gBitTable[gBank1])) - break; - if (gBank1 >= gNoOfAllBanks) - break; - gBank1++; - } - } - gBattlescriptCurrInstr += 2; - } - } -} - -static void atk53_trainer_slide(void) -{ - gActiveBank = GetBankByIdentity(gBattlescriptCurrInstr[1]); - EmitTrainerSlide(0); - MarkBufferBankForExecution(gActiveBank); - - gBattlescriptCurrInstr += 2; -} - -static void atk54_effectiveness_sound(void) -{ - gActiveBank = gBankAttacker; - EmitEffectivenessSound(0, BS2ScriptRead16(gBattlescriptCurrInstr + 1)); - MarkBufferBankForExecution(gActiveBank); - - gBattlescriptCurrInstr += 3; -} - -static void atk55_play_sound(void) -{ - gActiveBank = gBankAttacker; - EmitPlaySound(0, BS2ScriptRead16(gBattlescriptCurrInstr + 1), 0); - MarkBufferBankForExecution(gActiveBank); - - gBattlescriptCurrInstr += 3; -} - -static void atk56_fainting_cry(void) -{ - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - EmitFaintingCry(0); - MarkBufferBankForExecution(gActiveBank); - - gBattlescriptCurrInstr += 2; -} - -static void atk57(void) -{ - gActiveBank = GetBankByIdentity(0); - Emit_x37(0, gBattleOutcome); - MarkBufferBankForExecution(gActiveBank); - - gBattlescriptCurrInstr += 1; -} - -static void atk58_return_to_ball(void) -{ - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - EmitReturnPokeToBall(0, 1); - MarkBufferBankForExecution(gActiveBank); - - gBattlescriptCurrInstr += 2; -} - -static void atk59_learnmove_inbattle(void) -{ - const u8* jumpPtr1 = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - const u8* jumpPtr2 = BSScriptReadPtr(gBattlescriptCurrInstr + 5); - - u16 ret = MonTryLearningNewMove(&gPlayerParty[gBattleStruct->expGetterId], gBattlescriptCurrInstr[9]); - while (ret == 0xFFFE) - ret = MonTryLearningNewMove(&gPlayerParty[gBattleStruct->expGetterId], 0); - - if (ret == 0) - { - gBattlescriptCurrInstr = jumpPtr2; - } - else if (ret == 0xFFFF) - { - gBattlescriptCurrInstr += 10; - } - else - { - gActiveBank = GetBankByIdentity(0); - - if (gBattlePartyID[gActiveBank] == gBattleStruct->expGetterId - && !(gBattleMons[gActiveBank].status2 & STATUS2_TRANSFORMED)) - { - GiveMoveToBattleMon(&gBattleMons[gActiveBank], ret); - } - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) - { - gActiveBank = GetBankByIdentity(2); - if (gBattlePartyID[gActiveBank] == gBattleStruct->expGetterId - && !(gBattleMons[gActiveBank].status2 & STATUS2_TRANSFORMED)) - { - GiveMoveToBattleMon(&gBattleMons[gActiveBank], ret); - } - } - - gBattlescriptCurrInstr = jumpPtr1; - } -} - -static void atk5A_yesnoboxlearnmove(void) -{ - gActiveBank = 0; - - switch (gBattleScripting.learnMoveState) - { - case 0: - sub_8056A3C(0x18, 8, 0x1D, 0xD, 0); - sub_814F9EC(gText_BattleYesNoChoice, 0xC); - gBattleScripting.learnMoveState++; - gBattleCommunication[CURSOR_POSITION] = 0; - BattleCreateCursorAt(0); - break; - case 1: - if (gMain.newKeys & DPAD_UP && gBattleCommunication[CURSOR_POSITION] != 0) - { - PlaySE(SE_SELECT); - BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); - gBattleCommunication[CURSOR_POSITION] = 0; - BattleCreateCursorAt(0); - } - if (gMain.newKeys & DPAD_DOWN && gBattleCommunication[CURSOR_POSITION] == 0) - { - PlaySE(SE_SELECT); - BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); - gBattleCommunication[CURSOR_POSITION] = 1; - BattleCreateCursorAt(1); - } - if (gMain.newKeys & A_BUTTON) - { - PlaySE(SE_SELECT); - if (gBattleCommunication[1] == 0) - { - sub_8056A3C(0x18, 0x8, 0x1D, 0xD, 1); - BeginNormalPaletteFade(-1, 0, 0, 0x10, 0); - gBattleScripting.learnMoveState++; - } - else - { - gBattleScripting.learnMoveState = 5; - } - } - else if (gMain.newKeys & B_BUTTON) - { - PlaySE(SE_SELECT); - gBattleScripting.learnMoveState = 5; - } - break; - case 2: - if (!gPaletteFade.active) - { - FreeAllWindowBuffers(); - sub_81BFA38(gPlayerParty, gBattleStruct->expGetterId, gPlayerPartyCount - 1, ReshowBattleScreenAfterMenu, gMoveToLearn); - gBattleScripting.learnMoveState++; - } - break; - case 3: - if (!gPaletteFade.active && gMain.callback2 == BattleMainCB2) - { - gBattleScripting.learnMoveState++; - } - break; - case 4: - if (!gPaletteFade.active && gMain.callback2 == BattleMainCB2) - { - u8 movePosition = sub_81C1B94(); - if (movePosition == 4) - { - gBattleScripting.learnMoveState = 5; - } - else - { - u16 moveId = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_MOVE1 + movePosition); - if (IsHMMove2(moveId)) - { - PrepareStringBattle(0x13F, gActiveBank); - gBattleScripting.learnMoveState = 6; - } - else - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - - PREPARE_MOVE_BUFFER(gBattleTextBuff2, moveId) - - RemoveMonPPBonus(&gPlayerParty[gBattleStruct->expGetterId], movePosition); - SetMonMoveSlot(&gPlayerParty[gBattleStruct->expGetterId], gMoveToLearn, movePosition); - - if (gBattlePartyID[0] == gBattleStruct->expGetterId - && !(gBattleMons[0].status2 & STATUS2_TRANSFORMED) - && !(gDisableStructs[0].unk18_b & gBitTable[movePosition])) - { - RemoveBattleMonPPBonus(&gBattleMons[0], movePosition); - SetBattleMonMoveSlot(&gBattleMons[0], gMoveToLearn, movePosition); - } - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE - && gBattlePartyID[2] == gBattleStruct->expGetterId - && !(gBattleMons[2].status2 & STATUS2_TRANSFORMED) - && !(gDisableStructs[2].unk18_b & gBitTable[movePosition])) - { - RemoveBattleMonPPBonus(&gBattleMons[2], movePosition); - SetBattleMonMoveSlot(&gBattleMons[2], gMoveToLearn, movePosition); - } - } - } - } - break; - case 5: - sub_8056A3C(0x18, 8, 0x1D, 0xD, 1); - gBattlescriptCurrInstr += 5; - break; - case 6: - if (gBattleExecBuffer == 0) - { - gBattleScripting.learnMoveState = 2; - } - break; - } -} - -static void atk5B_yesnoboxstoplearningmove(void) -{ - switch (gBattleScripting.learnMoveState) - { - case 0: - sub_8056A3C(0x18, 8, 0x1D, 0xD, 0); - sub_814F9EC(gText_BattleYesNoChoice, 0xC); - gBattleScripting.learnMoveState++; - gBattleCommunication[CURSOR_POSITION] = 0; - BattleCreateCursorAt(0); - break; - case 1: - if (gMain.newKeys & DPAD_UP && gBattleCommunication[CURSOR_POSITION] != 0) - { - PlaySE(SE_SELECT); - BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); - gBattleCommunication[CURSOR_POSITION] = 0; - BattleCreateCursorAt(0); - } - if (gMain.newKeys & DPAD_DOWN && gBattleCommunication[CURSOR_POSITION] == 0) - { - PlaySE(SE_SELECT); - BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); - gBattleCommunication[CURSOR_POSITION] = 1; - BattleCreateCursorAt(1); - } - if (gMain.newKeys & A_BUTTON) - { - PlaySE(SE_SELECT); - - if (gBattleCommunication[1] != 0) - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - else - gBattlescriptCurrInstr += 5; - - sub_8056A3C(0x18, 0x8, 0x1D, 0xD, 1); - } - else if (gMain.newKeys & B_BUTTON) - { - PlaySE(SE_SELECT); - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - sub_8056A3C(0x18, 0x8, 0x1D, 0xD, 1); - } - break; - } -} - -static void atk5C_hitanimation(void) -{ - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - - if (gBattleMoveFlags & MOVESTATUS_NOEFFECT) - { - gBattlescriptCurrInstr += 2; - } - else if (!(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE) || !(gBattleMons[gActiveBank].status2 & STATUS2_SUBSTITUTE) || gDisableStructs[gActiveBank].substituteHP == 0) - { - EmitHitAnimation(0); - MarkBufferBankForExecution(gActiveBank); - gBattlescriptCurrInstr += 2; - } - else - { - gBattlescriptCurrInstr += 2; - } -} - -static u32 GetTrainerMoneyToGive(u16 trainerId) -{ - u32 i = 0; - u32 lastMonLevel = 0; - u32 moneyReward = 0; - - if (trainerId == SECRET_BASE_OPPONENT) - { - moneyReward = 20 * gBattleResources->secretBase->partyLevels[0] * gBattleStruct->moneyMultiplier; - } - else - { - switch (gTrainers[trainerId].partyFlags) - { - case 0: - { - const struct TrainerMonNoItemDefaultMoves *party = gTrainers[trainerId].party.NoItemDefaultMoves; - lastMonLevel = party[gTrainers[trainerId].partySize - 1].lvl; - } - break; - case PARTY_FLAG_CUSTOM_MOVES: - { - const struct TrainerMonNoItemCustomMoves *party = gTrainers[trainerId].party.NoItemCustomMoves; - lastMonLevel = party[gTrainers[trainerId].partySize - 1].lvl; - } - break; - case PARTY_FLAG_HAS_ITEM: - { - const struct TrainerMonItemDefaultMoves *party = gTrainers[trainerId].party.ItemDefaultMoves; - lastMonLevel = party[gTrainers[trainerId].partySize - 1].lvl; - } - break; - case PARTY_FLAG_CUSTOM_MOVES | PARTY_FLAG_HAS_ITEM: - { - const struct TrainerMonItemCustomMoves *party = gTrainers[trainerId].party.ItemCustomMoves; - lastMonLevel = party[gTrainers[trainerId].partySize - 1].lvl; - } - break; - } - - for (; gTrainerMoneyTable[i].classId != 0xFF; i++) - { - if (gTrainerMoneyTable[i].classId == gTrainers[trainerId].trainerClass) - break; - } - - if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) - moneyReward = 4 * lastMonLevel * gBattleStruct->moneyMultiplier * gTrainerMoneyTable[i].value; - else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) - moneyReward = 4 * lastMonLevel * gBattleStruct->moneyMultiplier * 2 * gTrainerMoneyTable[i].value; - else - moneyReward = 4 * lastMonLevel * gBattleStruct->moneyMultiplier * gTrainerMoneyTable[i].value; - } - - return moneyReward; -} - -static void atk5D_getmoneyreward(void) -{ - u32 moneyReward = GetTrainerMoneyToGive(gTrainerBattleOpponent_A); - if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) - moneyReward += GetTrainerMoneyToGive(gTrainerBattleOpponent_B); - - AddMoney(&gSaveBlock1Ptr->money, moneyReward); - - PREPARE_WORD_NUMBER_BUFFER(gBattleTextBuff1, 5, moneyReward) - - gBattlescriptCurrInstr++; -} - -static void atk5E_8025A70(void) -{ - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - - switch (gBattleCommunication[0]) - { - case 0: - EmitGetMonData(0, REQUEST_ALL_BATTLE, 0); - MarkBufferBankForExecution(gActiveBank); - gBattleCommunication[0]++; - break; - case 1: - if (gBattleExecBuffer == 0) - { - s32 i; - struct BattlePokemon* bufferPoke = (struct BattlePokemon*) &gBattleBufferB[gActiveBank][4]; - for (i = 0; i < 4; i++) - { - gBattleMons[gActiveBank].moves[i] = bufferPoke->moves[i]; - gBattleMons[gActiveBank].pp[i] = bufferPoke->pp[i]; - } - gBattlescriptCurrInstr += 2; - } - break; - } -} - -static void atk5F_8025B24(void) -{ - gActiveBank = gBankAttacker; - gBankAttacker = gBankTarget; - gBankTarget = gActiveBank; - - if (gHitMarker & HITMARKER_PURSUIT_TRAP) - gHitMarker &= ~(HITMARKER_PURSUIT_TRAP); - else - gHitMarker |= HITMARKER_PURSUIT_TRAP; - - gBattlescriptCurrInstr++; -} - -static void atk60_increment_gamestat(void) -{ - if (GetBankSide(gBankAttacker) == SIDE_PLAYER) - IncrementGameStat(gBattlescriptCurrInstr[1]); - - gBattlescriptCurrInstr += 2; -} - -static void atk61_8025BA4(void) -{ - s32 i; - struct Pokemon* party; - struct HpAndStatus hpStatuses[6]; - - if (gBattleExecBuffer) - return; - - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - - if (GetBankSide(gActiveBank) == SIDE_PLAYER) - party = gPlayerParty; - else - party = gEnemyParty; - - for (i = 0; i < 6; i++) - { - if (GetMonData(&party[i], MON_DATA_SPECIES2) == SPECIES_NONE - || GetMonData(&party[i], MON_DATA_SPECIES2) == SPECIES_EGG) - { - hpStatuses[i].hp = 0xFFFF; - hpStatuses[i].status = 0; - } - else - { - hpStatuses[i].hp = GetMonData(&party[i], MON_DATA_HP); - hpStatuses[i].status = GetMonData(&party[i], MON_DATA_STATUS); - } - } - - EmitCmd48(0, hpStatuses, 1); - MarkBufferBankForExecution(gActiveBank); - - gBattlescriptCurrInstr += 2; -} - -static void atk62_08025C6C(void) -{ - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - EmitCmd49(0); - MarkBufferBankForExecution(gActiveBank); - - gBattlescriptCurrInstr += 2; -} - -static void atk63_jumptorandomattack(void) -{ - if (gBattlescriptCurrInstr[1] != 0) - gCurrentMove = gRandomMove; - else - gLastUsedMove = gCurrentMove = gRandomMove; - - gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]; -} - -static void atk64_statusanimation(void) -{ - if (gBattleExecBuffer == 0) - { - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - if (!(gStatuses3[gActiveBank] & STATUS3_SEMI_INVULNERABLE) - && gDisableStructs[gActiveBank].substituteHP == 0 - && !(gHitMarker & HITMARKER_NO_ANIMATIONS)) - { - EmitStatusAnimation(0, FALSE, gBattleMons[gActiveBank].status1); - MarkBufferBankForExecution(gActiveBank); - } - gBattlescriptCurrInstr += 2; - } -} - -static void atk65_status2animation(void) -{ - u32 wantedToAnimate; - - if (gBattleExecBuffer == 0) - { - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - wantedToAnimate = BSScriptRead32(gBattlescriptCurrInstr + 2); - if (!(gStatuses3[gActiveBank] & STATUS3_SEMI_INVULNERABLE) - && gDisableStructs[gActiveBank].substituteHP == 0 - && !(gHitMarker & HITMARKER_NO_ANIMATIONS)) - { - EmitStatusAnimation(0, TRUE, gBattleMons[gActiveBank].status2 & wantedToAnimate); - MarkBufferBankForExecution(gActiveBank); - } - gBattlescriptCurrInstr += 6; - } -} - -static void atk66_chosenstatusanimation(void) -{ - u32 wantedStatus; - - if (gBattleExecBuffer == 0) - { - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - wantedStatus = BSScriptRead32(gBattlescriptCurrInstr + 3); - if (!(gStatuses3[gActiveBank] & STATUS3_SEMI_INVULNERABLE) - && gDisableStructs[gActiveBank].substituteHP == 0 - && !(gHitMarker & HITMARKER_NO_ANIMATIONS)) - { - EmitStatusAnimation(0, gBattlescriptCurrInstr[2], wantedStatus); - MarkBufferBankForExecution(gActiveBank); - } - gBattlescriptCurrInstr += 7; - } -} - -static void atk67_yesnobox(void) -{ - switch (gBattleCommunication[0]) - { - case 0: - sub_8056A3C(0x18, 8, 0x1D, 0xD, 0); - sub_814F9EC(gText_BattleYesNoChoice, 0xC); - gBattleCommunication[0]++; - gBattleCommunication[CURSOR_POSITION] = 0; - BattleCreateCursorAt(0); - break; - case 1: - if (gMain.newKeys & DPAD_UP && gBattleCommunication[CURSOR_POSITION] != 0) - { - PlaySE(SE_SELECT); - BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); - gBattleCommunication[CURSOR_POSITION] = 0; - BattleCreateCursorAt(0); - } - if (gMain.newKeys & DPAD_DOWN && gBattleCommunication[CURSOR_POSITION] == 0) - { - PlaySE(SE_SELECT); - BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); - gBattleCommunication[CURSOR_POSITION] = 1; - BattleCreateCursorAt(1); - } - if (gMain.newKeys & B_BUTTON) - { - gBattleCommunication[CURSOR_POSITION] = 1; - PlaySE(SE_SELECT); - sub_8056A3C(0x18, 8, 0x1D, 0xD, 1); - gBattlescriptCurrInstr++; - } - else if (gMain.newKeys & A_BUTTON) - { - PlaySE(SE_SELECT); - sub_8056A3C(0x18, 8, 0x1D, 0xD, 1); - gBattlescriptCurrInstr++; - } - break; - } -} - -static void atk68_80246A0(void) -{ - s32 i; - - for (i = 0; i < gNoOfAllBanks; i++) - gUnknown_0202407A[i] = 0xC; - - gBattlescriptCurrInstr++; -} - -static void atk69_dmg_adjustment3(void) // The same as 0x7, except there's no random damage multiplier. -{ - u8 holdEffect, quality; - - if (gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY) - { - holdEffect = gEnigmaBerries[gBankTarget].holdEffect, quality = gEnigmaBerries[gBankTarget].holdEffectParam; - } - else - { - holdEffect = ItemId_GetHoldEffect(gBattleMons[gBankTarget].item); - quality = ItemId_GetHoldEffectParam(gBattleMons[gBankTarget].item); - } - - gStringBank = gBankTarget; - - if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < quality) - { - RecordItemEffectBattle(gBankTarget, holdEffect); - gSpecialStatuses[gBankTarget].focusBanded = 1; - } - if (gBattleMons[gBankTarget].status2 & STATUS2_SUBSTITUTE) - goto END; - if (gBattleMoves[gCurrentMove].effect != EFFECT_FALSE_SWIPE && !gProtectStructs[gBankTarget].endured - && !gSpecialStatuses[gBankTarget].focusBanded) - goto END; - - if (gBattleMons[gBankTarget].hp > gBattleMoveDamage) - goto END; - - gBattleMoveDamage = gBattleMons[gBankTarget].hp - 1; - - if (gProtectStructs[gBankTarget].endured) - { - gBattleMoveFlags |= MOVESTATUS_ENDURED; - } - else if (gSpecialStatuses[gBankTarget].focusBanded) - { - gBattleMoveFlags |= MOVESTATUS_HUNGON; - gLastUsedItem = gBattleMons[gBankTarget].item; - } - - END: - gBattlescriptCurrInstr++; -} - -static void atk6A_removeitem(void) -{ - u16* usedHeldItem; - - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - - usedHeldItem = &gBattleStruct->usedHeldItems[gActiveBank]; - *usedHeldItem = gBattleMons[gActiveBank].item; - gBattleMons[gActiveBank].item = 0; - - EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gActiveBank].item); - MarkBufferBankForExecution(gActiveBank); - - gBattlescriptCurrInstr += 2; -} - -static void atk6B_atknameinbuff1(void) -{ - PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, gBankAttacker, gBattlePartyID[gBankAttacker]) - - gBattlescriptCurrInstr++; -} - -static void atk6C_draw_lvlupbox(void) -{ - if (gBattleScripting.atk6C_state == 0) - { - if (IsMonGettingExpSentOut()) - gBattleScripting.atk6C_state = 3; - else - gBattleScripting.atk6C_state = 1; - } - - switch (gBattleScripting.atk6C_state) - { - case 1: - gBattle_BG2_Y = 0x60; - SetBgAttribute(2, BG_CTRL_ATTR_MOSAIC, 0); - ShowBg(2); - sub_804F17C(); - gBattleScripting.atk6C_state = 2; - break; - case 2: - if (!sub_804F1CC()) - gBattleScripting.atk6C_state = 3; - break; - case 3: - gBattle_BG1_X = 0; - gBattle_BG1_Y = 0x100; - SetBgAttribute(0, BG_CTRL_ATTR_MOSAIC, 1); - SetBgAttribute(1, BG_CTRL_ATTR_MOSAIC, 0); - ShowBg(0); - ShowBg(1); - sub_8056A3C(0x12, 7, 0x1D, 0x13, 0x80); - gBattleScripting.atk6C_state = 4; - break; - case 4: - sub_804F100(); - PutWindowTilemap(13); - CopyWindowToVram(13, 3); - gBattleScripting.atk6C_state++; - break; - case 5: - case 7: - if (!IsDma3ManagerBusyWithBgCopy()) - { - gBattle_BG1_Y = 0; - gBattleScripting.atk6C_state++; - } - break; - case 6: - if (gMain.newKeys != 0) - { - PlaySE(SE_SELECT); - sub_804F144(); - CopyWindowToVram(13, 2); - gBattleScripting.atk6C_state++; - } - break; - case 8: - if (gMain.newKeys != 0) - { - PlaySE(SE_SELECT); - sub_8056A3C(0x12, 7, 0x1D, 0x13, 0x81); - gBattleScripting.atk6C_state++; - } - break; - case 9: - if (!sub_804F344()) - { - ClearWindowTilemap(14); - CopyWindowToVram(14, 1); - - ClearWindowTilemap(13); - CopyWindowToVram(13, 1); - - SetBgAttribute(2, BG_CTRL_ATTR_MOSAIC, 2); - ShowBg(2); - - gBattleScripting.atk6C_state = 10; - } - break; - case 10: - if (!IsDma3ManagerBusyWithBgCopy()) - { - SetBgAttribute(0, BG_CTRL_ATTR_MOSAIC, 0); - SetBgAttribute(1, BG_CTRL_ATTR_MOSAIC, 1); - ShowBg(0); - ShowBg(1); - gBattlescriptCurrInstr++; - } - break; - } -} - -static void sub_804F100(void) -{ - struct StatsArray currentStats; - - sub_81D388C(&gPlayerParty[gBattleStruct->expGetterId], ¤tStats); - sub_81D3640(0xD, gBattleResources->statsBeforeLvlUp, ¤tStats, 0xE, 0xD, 0xF); -} - -static void sub_804F144(void) -{ - struct StatsArray currentStats; - - sub_81D388C(&gPlayerParty[gBattleStruct->expGetterId], ¤tStats); - sub_81D3784(0xD, ¤tStats, 0xE, 0xD, 0xF); -} - -static void sub_804F17C(void) -{ - gBattle_BG2_Y = 0; - gBattle_BG2_X = 0x1A0; - - LoadPalette(sUnknown_0831C2C8, 0x60, 0x20); - CopyToWindowPixelBuffer(14, sUnknown_0831C2E8, 0, 0); - PutWindowTilemap(14); - CopyWindowToVram(14, 3); - - PutMonIconOnLvlUpBox(); -} - -static bool8 sub_804F1CC(void) -{ - if (IsDma3ManagerBusyWithBgCopy()) - return TRUE; - - if (gBattle_BG2_X == 0x200) - return FALSE; - - if (gBattle_BG2_X == 0x1A0) - PutLevelAndGenderOnLvlUpBox(); - - gBattle_BG2_X += 8; - if (gBattle_BG2_X >= 0x200) - gBattle_BG2_X = 0x200; - - return (gBattle_BG2_X != 0x200); -} - -static void PutLevelAndGenderOnLvlUpBox(void) -{ - u16 monLevel; - u8 monGender; - struct TextSubPrinter subPrinter; - u8 *txtPtr; - u32 var; - - monLevel = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL); - monGender = GetMonGender(&gPlayerParty[gBattleStruct->expGetterId]); - GetMonNickname(&gPlayerParty[gBattleStruct->expGetterId], gStringVar4); - - subPrinter.current_text_offset = gStringVar4; - subPrinter.windowId = 14; - subPrinter.fontId = 0; - subPrinter.x = 32; - subPrinter.y = 0; - subPrinter.currentX = 32; - subPrinter.currentY = 0; - subPrinter.letterSpacing = 0; - subPrinter.lineSpacing = 0; - subPrinter.fontColor_l = TEXT_COLOR_TRANSPARENT; - subPrinter.fontColor_h = TEXT_COLOR_WHITE; - subPrinter.bgColor = TEXT_COLOR_TRANSPARENT; - subPrinter.shadowColor = TEXT_COLOR_DARK_GREY; - - AddTextPrinter(&subPrinter, 0xFF, NULL); - - txtPtr = gStringVar4; - gStringVar4[0] = CHAR_SPECIAL_F9; - txtPtr++; - txtPtr[0] = 5; - txtPtr++; - - var = (u32)(txtPtr); - txtPtr = ConvertIntToDecimalStringN(txtPtr, monLevel, STR_CONV_MODE_LEFT_ALIGN, 3); - var = (u32)(txtPtr) - var; - txtPtr = StringFill(txtPtr, 0x77, 4 - var); - - if (monGender != MON_GENDERLESS) - { - if (monGender == MON_MALE) - { - txtPtr = WriteColorChangeControlCode(txtPtr, 0, 0xC); - txtPtr = WriteColorChangeControlCode(txtPtr, 1, 0xD); - *(txtPtr++) = CHAR_MALE; - } - else - { - txtPtr = WriteColorChangeControlCode(txtPtr, 0, 0xE); - txtPtr = WriteColorChangeControlCode(txtPtr, 1, 0xF); - *(txtPtr++) = CHAR_FEMALE; - } - *(txtPtr++) = EOS; - } - - subPrinter.y = 10; - subPrinter.currentY = 10; - AddTextPrinter(&subPrinter, 0xFF, NULL); - - CopyWindowToVram(14, 2); -} - -static bool8 sub_804F344(void) -{ - if (gBattle_BG2_X == 0x1A0) - return FALSE; - - if (gBattle_BG2_X - 16 < 0x1A0) - gBattle_BG2_X = 0x1A0; - else - gBattle_BG2_X -= 16; - - return (gBattle_BG2_X != 0x1A0); -} - -#define sDestroy data0 -#define sSavedLvlUpBoxXPosition data1 - -static void PutMonIconOnLvlUpBox(void) -{ - u8 spriteId; - const u16* iconPal; - struct SpriteSheet iconSheet; - struct SpritePalette iconPalSheet; - - u16 species = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPECIES); - u32 personality = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_PERSONALITY); - - const u8* iconPtr = GetMonIconPtr(species, personality, 1); - iconSheet.data = iconPtr; - iconSheet.size = 0x200; - iconSheet.tag = MON_ICON_LVLUP_BOX_TAG; - - iconPal = GetValidMonIconPalettePtr(species); - iconPalSheet.data = iconPal; - iconPalSheet.tag = MON_ICON_LVLUP_BOX_TAG; - - LoadSpriteSheet(&iconSheet); - LoadSpritePalette(&iconPalSheet); - - spriteId = CreateSprite(&sSpriteTemplate_MonIconOnLvlUpBox, 256, 10, 0); - gSprites[spriteId].sDestroy = FALSE; - gSprites[spriteId].sSavedLvlUpBoxXPosition = gBattle_BG2_X; -} - -static void SpriteCB_MonIconOnLvlUpBox(struct Sprite* sprite) -{ - sprite->pos2.x = sprite->sSavedLvlUpBoxXPosition - gBattle_BG2_X; - - if (sprite->pos2.x != 0) - { - sprite->sDestroy = TRUE; - } - else if (sprite->sDestroy) - { - DestroySprite(sprite); - FreeSpriteTilesByTag(MON_ICON_LVLUP_BOX_TAG); - FreeSpritePaletteByTag(MON_ICON_LVLUP_BOX_TAG); - } -} - -#undef sDestroy -#undef sSavedLvlUpBoxXPosition - -static bool32 IsMonGettingExpSentOut(void) -{ - if (gBattlePartyID[0] == gBattleStruct->expGetterId) - return TRUE; - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && gBattlePartyID[2] == gBattleStruct->expGetterId) - return TRUE; - - return FALSE; -} - -static void atk6D_reset_sentpokes_value(void) -{ - ResetSentPokesToOpponentValue(); - gBattlescriptCurrInstr++; -} - -static void atk6E_set_atk_to_player0(void) -{ - gBankAttacker = GetBankByIdentity(0); - gBattlescriptCurrInstr++; -} - -static void atk6F_set_visible(void) -{ - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - EmitSpriteInvisibility(0, FALSE); - MarkBufferBankForExecution(gActiveBank); - - gBattlescriptCurrInstr += 2; -} - -static void atk70_record_last_used_ability(void) -{ - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - RecordAbilityBattle(gActiveBank, gLastUsedAbility); - gBattlescriptCurrInstr += 1; // UB: Should be + 2, one byte for command and one byte for bank argument. -} - -void BufferMoveToLearnIntoBattleTextBuff2(void) -{ - PREPARE_MOVE_BUFFER(gBattleTextBuff2, gMoveToLearn); -} - -static void atk71_buffer_move_to_learn(void) -{ - BufferMoveToLearnIntoBattleTextBuff2(); - gBattlescriptCurrInstr++; -} - -static void atk72_jump_if_can_run_frombattle(void) -{ - if (CanRunFromBattle(gBank1)) - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - else - gBattlescriptCurrInstr += 5; -} - -static void atk73_hp_thresholds(void) -{ - u8 opposingBank; - s32 result; - - if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) - { - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - opposingBank = gActiveBank ^ BIT_SIDE; - - result = gBattleMons[opposingBank].hp * 100 / gBattleMons[opposingBank].maxHP; - if (result == 0) - result = 1; - - if (result > 69 || !gBattleMons[opposingBank].hp) - gBattleStruct->hpScale = 0; - else if (result > 39) - gBattleStruct->hpScale = 1; - else if (result > 9) - gBattleStruct->hpScale = 2; - else - gBattleStruct->hpScale = 3; - } - - gBattlescriptCurrInstr += 2; -} - -static void atk74_hp_thresholds2(void) -{ - u8 opposingBank; - s32 result; - u8 hpSwitchout; - - if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) - { - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - opposingBank = gActiveBank ^ BIT_SIDE; - hpSwitchout = *(gBattleStruct->hpOnSwitchout + GetBankSide(opposingBank)); - result = (hpSwitchout - gBattleMons[opposingBank].hp) * 100 / hpSwitchout; - - if (gBattleMons[opposingBank].hp >= hpSwitchout) - gBattleStruct->hpScale = 0; - else if (result <= 29) - gBattleStruct->hpScale = 1; - else if (result <= 69) - gBattleStruct->hpScale = 2; - else - gBattleStruct->hpScale = 3; - } - - gBattlescriptCurrInstr += 2; -} - -static void atk75_item_effect_on_opponent(void) -{ - gBankInMenu = gBankAttacker; - ExecuteTableBasedItemEffect(&gEnemyParty[gBattlePartyID[gBankAttacker]], gLastUsedItem, gBattlePartyID[gBankAttacker], 0, 1); - - gBattlescriptCurrInstr += 1; -} - -static void atk76_various(void) -{ - u8 side; - s32 i; - - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - - switch (gBattlescriptCurrInstr[2]) - { - case VARIOUS_CANCEL_MULTI_TURN_MOVES: - CancelMultiTurnMoves(gActiveBank); - break; - case VARIOUS_SET_MAGIC_COAT_TARGET: - gBankAttacker = gBankTarget; - side = GetBankSide(gBankAttacker) ^ 1; - if (gSideTimers[side].followmeTimer != 0 && gBattleMons[gSideTimers[side].followmeTarget].hp != 0) - gBankTarget = gSideTimers[side].followmeTarget; - else - gBankTarget = gActiveBank; - break; - case 2: - gBattleCommunication[0] = IsRunningFromBattleImpossible(); - break; - case VARIOUS_GET_MOVE_TARGET: - gBankTarget = GetMoveTarget(gCurrentMove, 0); - break; - case 4: - if (gHitMarker & HITMARKER_FAINTED(gActiveBank)) - gBattleCommunication[0] = 1; - else - gBattleCommunication[0] = 0; - break; - case VARIOUS_RESET_INTIMIDATE_TRACE_BITS: - gSpecialStatuses[gActiveBank].intimidatedPoke = 0; - gSpecialStatuses[gActiveBank].traced = 0; - break; - case VARIOUS_UPDATE_CHOICE_MOVE_ON_LVL_UP: - if (gBattlePartyID[0] == gBattleStruct->expGetterId || gBattlePartyID[2] == gBattleStruct->expGetterId) - { - u16 *choicedMove; - - if (gBattlePartyID[0] == gBattleStruct->expGetterId) - gActiveBank = 0; - else - gActiveBank = 2; - - choicedMove = &gBattleStruct->choicedMove[gActiveBank]; - - for (i = 0; i < 4; i++) - { - if (gBattleMons[gActiveBank].moves[i] == *choicedMove) - break; - } - if (i == 4) - *choicedMove = 0; - } - break; - case 7: - if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_DOUBLE)) - && gBattleTypeFlags & BATTLE_TYPE_TRAINER - && gBattleMons[0].hp != 0 - && gBattleMons[1].hp != 0) - { - gHitMarker &= ~(HITMARKER_x400000); - } - break; - case 8: - gBattleCommunication[0] = 0; - gBattleScripting.bank = gActiveBank = gBattleCommunication[1]; - if (!(gBattleStruct->field_92 & gBitTable[gActiveBank]) - && gBattleMons[gActiveBank].maxHP / 2 >= gBattleMons[gActiveBank].hp - && gBattleMons[gActiveBank].hp != 0 - && !(gBattleMons[gActiveBank].status1 & STATUS_SLEEP)) - { - gBattleStruct->field_92 |= gBitTable[gActiveBank]; - gBattleCommunication[0] = 1; - gBattleCommunication[MULTISTRING_CHOOSER] = sUnknown_0831C4F8[GetNatureFromPersonality(gBattleMons[gActiveBank].personality)]; - } - break; - case 9: - i = sub_81A5258(gBattleCommunication); - if (i == 0) - return; - - gBattleCommunication[1] = i; - break; - case 10: - gBattleMons[1].hp = 0; - gHitMarker |= HITMARKER_FAINTED(1); - gBattleStruct->field_2A1 |= gBitTable[gBattlePartyID[1]]; - gDisableStructs[1].truantUnknownBit = 1; - break; - case 11: - gBattleMons[0].hp = 0; - gHitMarker |= HITMARKER_FAINTED(0); - gHitMarker |= HITMARKER_x400000; - gBattleStruct->field_2A0 |= gBitTable[gBattlePartyID[0]]; - gDisableStructs[0].truantUnknownBit = 1; - break; - case 12: - gBattleMons[0].hp = 0; - gBattleMons[1].hp = 0; - gHitMarker |= HITMARKER_FAINTED(0); - gHitMarker |= HITMARKER_FAINTED(1); - gHitMarker |= HITMARKER_x400000; - gBattleStruct->field_2A0 |= gBitTable[gBattlePartyID[0]]; - gBattleStruct->field_2A1 |= gBitTable[gBattlePartyID[1]]; - gDisableStructs[0].truantUnknownBit = 1; - gDisableStructs[1].truantUnknownBit = 1; - break; - case 13: - EmitCmd13(0); - MarkBufferBankForExecution(gActiveBank); - break; - case 14: - sub_81A5BF8(); - break; - case 15: - sub_81A5D44(); - break; - case 16: - BattleStringExpandPlaceholdersToDisplayedString(gRefereeStringsTable[gBattlescriptCurrInstr[1]]); - sub_814F9EC(gDisplayedStringBattle, 0x16); - break; - case 17: - if (IsTextPrinterActive(0x16)) - return; - break; - case VARIOUS_WAIT_CRY: - if (!IsCryFinished()) - return; - break; - case VARIOUS_RETURN_OPPONENT_MON1: - gActiveBank = 1; - if (gBattleMons[gActiveBank].hp != 0) - { - EmitReturnPokeToBall(0, 0); - MarkBufferBankForExecution(gActiveBank); - } - break; - case VARIOUS_RETURN_OPPONENT_MON2: - if (gNoOfAllBanks > 3) - { - gActiveBank = 3; - if (gBattleMons[gActiveBank].hp != 0) - { - EmitReturnPokeToBall(0, 0); - MarkBufferBankForExecution(gActiveBank); - } - } - break; - case 21: - m4aMPlayVolumeControl(&gMPlay_BGM, 0xFFFF, 0x55); - break; - case 22: - m4aMPlayVolumeControl(&gMPlay_BGM, 0xFFFF, 0x100); - break; - case 23: - gBattleStruct->field_2A2 |= gBitTable[gActiveBank]; - break; - case 24: - if (sub_805725C(gActiveBank)) - return; - break; - case VARIOUS_SET_TELEPORT_OUTCOME: - if (GetBankSide(gActiveBank) == SIDE_PLAYER) - gBattleOutcome = BATTLE_PLAYER_TELEPORTED; - else - gBattleOutcome = BATTLE_OPPONENT_TELEPORTED; - break; - case VARIOUS_PLAY_TRAINER_DEFEATED_MUSIC: - EmitPlaySound(0, 0x19C, 1); - MarkBufferBankForExecution(gActiveBank); - break; - } - - gBattlescriptCurrInstr += 3; -} - -static void atk77_set_protect_like(void) // protect and endure -{ - bool8 notLastTurn = TRUE; - u16 lastMove = gUnknown_02024260[gBankAttacker]; - - if (lastMove != MOVE_PROTECT && lastMove != MOVE_DETECT && lastMove != MOVE_ENDURE) - gDisableStructs[gBankAttacker].protectUses = 0; - - if (gCurrentMoveTurn == (gNoOfAllBanks - 1)) - notLastTurn = FALSE; - - if (sProtectSuccessRates[gDisableStructs[gBankAttacker].protectUses] >= Random() && notLastTurn) - { - if (gBattleMoves[gCurrentMove].effect == EFFECT_PROTECT) - { - gProtectStructs[gBankAttacker].protected = 1; - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - } - if (gBattleMoves[gCurrentMove].effect == EFFECT_ENDURE) - { - gProtectStructs[gBankAttacker].endured = 1; - gBattleCommunication[MULTISTRING_CHOOSER] = 1; - } - gDisableStructs[gBankAttacker].protectUses++; - } - else - { - gDisableStructs[gBankAttacker].protectUses = 0; - gBattleCommunication[MULTISTRING_CHOOSER] = 2; - gBattleMoveFlags |= MOVESTATUS_MISSED; - } - - gBattlescriptCurrInstr++; -} - -static void atk78_faintifabilitynotdamp(void) -{ - if (gBattleExecBuffer) - return; - - for (gBankTarget = 0; gBankTarget < gNoOfAllBanks; gBankTarget++) - { - if (gBattleMons[gBankTarget].ability == ABILITY_DAMP) - break; - } - - if (gBankTarget == gNoOfAllBanks) - { - gActiveBank = gBankAttacker; - gBattleMoveDamage = gBattleMons[gActiveBank].hp; - EmitHealthBarUpdate(0, 0x7FFF); - MarkBufferBankForExecution(gActiveBank); - gBattlescriptCurrInstr++; - - for (gBankTarget = 0; gBankTarget < gNoOfAllBanks; gBankTarget++) - { - if (gBankTarget == gBankAttacker) - continue; - if (!(gAbsentBankFlags & gBitTable[gBankTarget])) - break; - } - } - else - { - gLastUsedAbility = ABILITY_DAMP; - RecordAbilityBattle(gBankTarget, gBattleMons[gBankTarget].ability); - gBattlescriptCurrInstr = BattleScript_DampStopsExplosion; - } -} - -static void atk79_setatkhptozero(void) -{ - if (gBattleExecBuffer) - return; - - gActiveBank = gBankAttacker; - gBattleMons[gActiveBank].hp = 0; - EmitSetMonData(0, REQUEST_HP_BATTLE, 0, 2, &gBattleMons[gActiveBank].hp); - MarkBufferBankForExecution(gActiveBank); - - gBattlescriptCurrInstr++; -} - -static void atk7A_jumpwhiletargetvalid(void) // Used by intimidate to loop through all targets. -{ - const u8* jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) - { - for (gBankTarget++; ; gBankTarget++) - { - if (gBankTarget == gBankAttacker) - continue; - if (!(gAbsentBankFlags & gBitTable[gBankTarget])) - break; - } - - if (gBankTarget >= gNoOfAllBanks) - gBattlescriptCurrInstr += 5; - else - gBattlescriptCurrInstr = jumpPtr; - } - else - gBattlescriptCurrInstr += 5; -} - -static void atk7B_healhalfHP_if_possible(void) -{ - const u8* failPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - - if (gBattlescriptCurrInstr[5] == BS_GET_ATTACKER) - gBankTarget = gBankAttacker; - - gBattleMoveDamage = gBattleMons[gBankTarget].maxHP / 2; - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - gBattleMoveDamage *= -1; - - if (gBattleMons[gBankTarget].hp == gBattleMons[gBankTarget].maxHP) - gBattlescriptCurrInstr = failPtr; - else - gBattlescriptCurrInstr += 6; -} - -static void atk7C_trymirrormove(void) -{ - s32 validMovesCount; - s32 i; - u16 move; - u16 movesArray[4]; - - for (i = 0; i < 3; i++) - movesArray[i] = 0; - - for (validMovesCount = 0, i = 0; i < gNoOfAllBanks; i++) - { - if (i != gBankAttacker) - { - move = *(i * 2 + gBankAttacker * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) - | (*(i * 2 + gBankAttacker * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) << 8); - - if (move != 0 && move != 0xFFFF) - { - movesArray[validMovesCount] = move; - validMovesCount++; - } - } - } - - move = *(gBattleStruct->mirrorMoves + gBankAttacker * 2 + 0) - | (*(gBattleStruct->mirrorMoves + gBankAttacker * 2 + 1) << 8); - - if (move != 0 && move != 0xFFFF) - { - gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); - gCurrentMove = move; - gBankTarget = GetMoveTarget(gCurrentMove, 0); - gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]; - } - else if (validMovesCount) - { - gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); - i = Random() % validMovesCount; - gCurrentMove = movesArray[i]; - gBankTarget = GetMoveTarget(gCurrentMove, 0); - gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]; - } - else - { - gSpecialStatuses[gBankAttacker].flag20 = 1; - gBattlescriptCurrInstr++; - } -} - -static void atk7D_set_rain(void) -{ - if (gBattleWeather & WEATHER_RAIN_ANY) - { - gBattleMoveFlags |= MOVESTATUS_MISSED; - gBattleCommunication[MULTISTRING_CHOOSER] = 2; - } - else - { - gBattleWeather = WEATHER_RAIN_TEMPORARY; - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - gWishFutureKnock.weatherDuration = 5; - } - gBattlescriptCurrInstr++; -} - -static void atk7E_setreflect(void) -{ - if (gSideAffecting[GET_BANK_SIDE(gBankAttacker)] & SIDE_STATUS_REFLECT) - { - gBattleMoveFlags |= MOVESTATUS_MISSED; - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - } - else - { - gSideAffecting[GET_BANK_SIDE(gBankAttacker)] |= SIDE_STATUS_REFLECT; - gSideTimers[GET_BANK_SIDE(gBankAttacker)].reflectTimer = 5; - gSideTimers[GET_BANK_SIDE(gBankAttacker)].reflectBank = gBankAttacker; - - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && CountAliveMonsInBattle(BATTLE_ALIVE_ATK_SIDE) == 2) - gBattleCommunication[MULTISTRING_CHOOSER] = 2; - else - gBattleCommunication[MULTISTRING_CHOOSER] = 1; - } - gBattlescriptCurrInstr++; -} - -static void atk7F_setseeded(void) -{ - if (gBattleMoveFlags & MOVESTATUS_NOEFFECT || gStatuses3[gBankTarget] & STATUS3_LEECHSEED) - { - gBattleMoveFlags |= MOVESTATUS_MISSED; - gBattleCommunication[MULTISTRING_CHOOSER] = 1; - } - else if (gBattleMons[gBankTarget].type1 == TYPE_GRASS || gBattleMons[gBankTarget].type2 == TYPE_GRASS) - { - gBattleMoveFlags |= MOVESTATUS_MISSED; - gBattleCommunication[MULTISTRING_CHOOSER] = 2; - } - else - { - gStatuses3[gBankTarget] |= gBankAttacker; - gStatuses3[gBankTarget] |= STATUS3_LEECHSEED; - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - } - - gBattlescriptCurrInstr++; -} - -static void atk80_manipulatedamage(void) -{ - switch (gBattlescriptCurrInstr[1]) - { - case ATK80_DMG_CHANGE_SIGN: - gBattleMoveDamage *= -1; - break; - case ATK80_DMG_HALF_BY_TWO_NOT_MORE_THAN_HALF_MAX_HP: - gBattleMoveDamage /= 2; - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - if ((gBattleMons[gBankTarget].maxHP / 2) < gBattleMoveDamage) - gBattleMoveDamage = gBattleMons[gBankTarget].maxHP / 2; - break; - case ATK80_DMG_DOUBLED: - gBattleMoveDamage *= 2; - break; - } - - gBattlescriptCurrInstr += 2; -} - -static void atk81_setrest(void) -{ - const u8* failJump = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - gActiveBank = gBankTarget = gBankAttacker; - gBattleMoveDamage = gBattleMons[gBankTarget].maxHP * (-1); - - if (gBattleMons[gBankTarget].hp == gBattleMons[gBankTarget].maxHP) - { - gBattlescriptCurrInstr = failJump; - } - else - { - if (gBattleMons[gBankTarget].status1 & ((u8)(~STATUS_SLEEP))) - gBattleCommunication[MULTISTRING_CHOOSER] = 1; - else - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - - gBattleMons[gBankTarget].status1 = 3; - EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); - MarkBufferBankForExecution(gActiveBank); - gBattlescriptCurrInstr += 5; - } -} - -static void atk82_jumpifnotfirstturn(void) -{ - const u8* failJump = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - - if (gDisableStructs[gBankAttacker].isFirstTurn) - gBattlescriptCurrInstr += 5; - else - gBattlescriptCurrInstr = failJump; -} - -static void atk83_nop(void) -{ - gBattlescriptCurrInstr++; -} - -bool8 UproarWakeUpCheck(u8 bank) -{ - s32 i; - - for (i = 0; i < gNoOfAllBanks; i++) - { - if (!(gBattleMons[i].status2 & STATUS2_UPROAR) || gBattleMons[bank].ability == ABILITY_SOUNDPROOF) - continue; - - gBattleScripting.bank = i; - - if (gBankTarget == 0xFF) - gBankTarget = i; - else if (gBankTarget == i) - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - else - gBattleCommunication[MULTISTRING_CHOOSER] = 1; - - break; - } - - if (i == gNoOfAllBanks) - return FALSE; - else - return TRUE; -} - -static void atk84_jump_if_cant_sleep(void) -{ - const u8* jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - - if (UproarWakeUpCheck(gBankTarget)) - { - gBattlescriptCurrInstr = jumpPtr; - } - else if (gBattleMons[gBankTarget].ability == ABILITY_INSOMNIA - || gBattleMons[gBankTarget].ability == ABILITY_VITAL_SPIRIT) - { - gLastUsedAbility = gBattleMons[gBankTarget].ability; - gBattleCommunication[MULTISTRING_CHOOSER] = 2; - gBattlescriptCurrInstr = jumpPtr; - RecordAbilityBattle(gBankTarget, gLastUsedAbility); - } - else - { - gBattlescriptCurrInstr += 5; - } -} - -static void atk85_stockpile(void) -{ - if (gDisableStructs[gBankAttacker].stockpileCounter == 3) - { - gBattleMoveFlags |= MOVESTATUS_MISSED; - gBattleCommunication[MULTISTRING_CHOOSER] = 1; - } - else - { - gDisableStructs[gBankAttacker].stockpileCounter++; - - PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff1, 1, gDisableStructs[gBankAttacker].stockpileCounter) - - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - } - gBattlescriptCurrInstr++; -} - -static void atk86_stockpiletobasedamage(void) -{ - const u8* jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - if (gDisableStructs[gBankAttacker].stockpileCounter == 0) - { - gBattlescriptCurrInstr = jumpPtr; - } - else - { - if (gBattleCommunication[6] != 1) - { - gBattleMoveDamage = CalculateBaseDamage(&gBattleMons[gBankAttacker], &gBattleMons[gBankTarget], gCurrentMove, - gSideAffecting[GET_BANK_SIDE(gBankTarget)], 0, - 0, gBankAttacker, gBankTarget) - * gDisableStructs[gBankAttacker].stockpileCounter; - gBattleScripting.animTurn = gDisableStructs[gBankAttacker].stockpileCounter; - - if (gProtectStructs[gBankAttacker].helpingHand) - gBattleMoveDamage = gBattleMoveDamage * 15 / 10; - } - - gDisableStructs[gBankAttacker].stockpileCounter = 0; - gBattlescriptCurrInstr += 5; - } -} - -static void atk87_stockpiletohpheal(void) -{ - const u8* jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - - if (gDisableStructs[gBankAttacker].stockpileCounter == 0) - { - gBattlescriptCurrInstr = jumpPtr; - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - } - else if (gBattleMons[gBankAttacker].maxHP == gBattleMons[gBankAttacker].hp) - { - gDisableStructs[gBankAttacker].stockpileCounter = 0; - gBattlescriptCurrInstr = jumpPtr; - gBankTarget = gBankAttacker; - gBattleCommunication[MULTISTRING_CHOOSER] = 1; - } - else - { - gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / (1 << (3 - gDisableStructs[gBankAttacker].stockpileCounter)); - - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - gBattleMoveDamage *= -1; - - gBattleScripting.animTurn = gDisableStructs[gBankAttacker].stockpileCounter; - gDisableStructs[gBankAttacker].stockpileCounter = 0; - gBattlescriptCurrInstr += 5; - gBankTarget = gBankAttacker; - } -} - -static void atk88_negativedamage(void) -{ - gBattleMoveDamage = -(gHpDealt / 2); - if (gBattleMoveDamage == 0) - gBattleMoveDamage = -1; - - gBattlescriptCurrInstr++; -} - -static u8 ChangeStatBuffs(s8 statValue, u8 statId, u8 flags, const u8* BS_ptr) -{ - bool8 certain = 0; - bool8 notProtectAffected = FALSE; - u32 index; - - if (flags & MOVE_EFFECT_AFFECTS_USER) - gActiveBank = gBankAttacker; - else - gActiveBank = gBankTarget; - - flags &= ~(MOVE_EFFECT_AFFECTS_USER); - - if (flags & MOVE_EFFECT_CERTAIN) - certain++; - flags &= ~(MOVE_EFFECT_CERTAIN); - - if (flags & STAT_CHANGE_NOT_PROTECT_AFFECTED) - notProtectAffected++; - flags &= ~(STAT_CHANGE_NOT_PROTECT_AFFECTED); - - PREPARE_STAT_BUFFER(gBattleTextBuff1, statId) - - if ((statValue << 0x18) < 0) // stat decrease - { - if (gSideTimers[GET_BANK_SIDE(gActiveBank)].mistTimer - && !certain && gCurrentMove != MOVE_CURSE) - { - if (flags == STAT_CHANGE_BS_PTR) - { - if (gSpecialStatuses[gActiveBank].statLowered) - { - gBattlescriptCurrInstr = BS_ptr; - } - else - { - BattleScriptPush(BS_ptr); - gBattleScripting.bank = gActiveBank; - gBattlescriptCurrInstr = BattleScript_MistProtected; - gSpecialStatuses[gActiveBank].statLowered = 1; - } - } - return STAT_CHANGE_DIDNT_WORK; - } - else if (gCurrentMove != MOVE_CURSE - && notProtectAffected != TRUE && JumpIfMoveAffectedByProtect(0)) - { - gBattlescriptCurrInstr = BattleScript_ButItFailed; - return STAT_CHANGE_DIDNT_WORK; - } - else if ((gBattleMons[gActiveBank].ability == ABILITY_CLEAR_BODY - || gBattleMons[gActiveBank].ability == ABILITY_WHITE_SMOKE) - && !certain && gCurrentMove != MOVE_CURSE) - { - if (flags == STAT_CHANGE_BS_PTR) - { - if (gSpecialStatuses[gActiveBank].statLowered) - { - gBattlescriptCurrInstr = BS_ptr; - } - else - { - BattleScriptPush(BS_ptr); - gBattleScripting.bank = gActiveBank; - gBattlescriptCurrInstr = BattleScript_AbilityNoStatLoss; - gLastUsedAbility = gBattleMons[gActiveBank].ability; - RecordAbilityBattle(gActiveBank, gLastUsedAbility); - gSpecialStatuses[gActiveBank].statLowered = 1; - } - } - return STAT_CHANGE_DIDNT_WORK; - } - else if (gBattleMons[gActiveBank].ability == ABILITY_KEEN_EYE - && !certain && statId == STAT_STAGE_ACC) - { - if (flags == STAT_CHANGE_BS_PTR) - { - BattleScriptPush(BS_ptr); - gBattleScripting.bank = gActiveBank; - gBattlescriptCurrInstr = BattleScript_AbilityNoSpecificStatLoss; - gLastUsedAbility = gBattleMons[gActiveBank].ability; - RecordAbilityBattle(gActiveBank, gLastUsedAbility); - } - return STAT_CHANGE_DIDNT_WORK; - } - else if (gBattleMons[gActiveBank].ability == ABILITY_HYPER_CUTTER - && !certain && statId == STAT_STAGE_ATK) - { - if (flags == STAT_CHANGE_BS_PTR) - { - BattleScriptPush(BS_ptr); - gBattleScripting.bank = gActiveBank; - gBattlescriptCurrInstr = BattleScript_AbilityNoSpecificStatLoss; - gLastUsedAbility = gBattleMons[gActiveBank].ability; - RecordAbilityBattle(gActiveBank, gLastUsedAbility); - } - return STAT_CHANGE_DIDNT_WORK; - } - else if (gBattleMons[gActiveBank].ability == ABILITY_SHIELD_DUST && flags == 0) - { - return STAT_CHANGE_DIDNT_WORK; - } - else // try to decrease - { - statValue = -GET_STAT_BUFF_VALUE(statValue); - gBattleTextBuff2[0] = B_BUFF_PLACEHOLDER_BEGIN; - index = 1; - if (statValue == -2) - { - gBattleTextBuff2[1] = B_BUFF_STRING; - gBattleTextBuff2[2] = 0xD3; // harshly - gBattleTextBuff2[3] = 0xD3 >> 8; - index = 4; - } - gBattleTextBuff2[index] = B_BUFF_STRING; - index++; - gBattleTextBuff2[index] = 0xD4; // fell - index++; - gBattleTextBuff2[index] = 0xD4 >> 8; - index++; - gBattleTextBuff2[index] = B_BUFF_EOS; - - if (gBattleMons[gActiveBank].statStages[statId] == 0) - gBattleCommunication[MULTISTRING_CHOOSER] = 2; - else - gBattleCommunication[MULTISTRING_CHOOSER] = (gBankTarget == gActiveBank); - - } - } - else // stat increase - { - statValue = GET_STAT_BUFF_VALUE(statValue); - gBattleTextBuff2[0] = B_BUFF_PLACEHOLDER_BEGIN; - index = 1; - if (statValue == 2) - { - gBattleTextBuff2[1] = B_BUFF_STRING; - gBattleTextBuff2[2] = 0xD1; // sharply - gBattleTextBuff2[3] = 0xD1 >> 8; - index = 4; - } - gBattleTextBuff2[index] = B_BUFF_STRING; - index++; - gBattleTextBuff2[index] = 0xD2; // rose - index++; - gBattleTextBuff2[index] = 0xD2 >> 8; - index++; - gBattleTextBuff2[index] = B_BUFF_EOS; - - if (gBattleMons[gActiveBank].statStages[statId] == 0xC) - gBattleCommunication[MULTISTRING_CHOOSER] = 2; - else - gBattleCommunication[MULTISTRING_CHOOSER] = (gBankTarget == gActiveBank); - } - - gBattleMons[gActiveBank].statStages[statId] += statValue; - if (gBattleMons[gActiveBank].statStages[statId] < 0) - gBattleMons[gActiveBank].statStages[statId] = 0; - if (gBattleMons[gActiveBank].statStages[statId] > 0xC) - gBattleMons[gActiveBank].statStages[statId] = 0xC; - - if (gBattleCommunication[MULTISTRING_CHOOSER] == 2 && flags & STAT_CHANGE_BS_PTR) - gBattleMoveFlags |= MOVESTATUS_MISSED; - - if (gBattleCommunication[MULTISTRING_CHOOSER] == 2 && !(flags & STAT_CHANGE_BS_PTR)) - return STAT_CHANGE_DIDNT_WORK; - - return STAT_CHANGE_WORKED; -} - -static void atk89_statbuffchange(void) -{ - const u8* jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); - if (ChangeStatBuffs(gBattleScripting.statChanger & 0xF0, GET_STAT_BUFF_ID(gBattleScripting.statChanger), gBattlescriptCurrInstr[1], jumpPtr) == STAT_CHANGE_WORKED) - gBattlescriptCurrInstr += 6; -} - -static void atk8A_normalisebuffs(void) // haze -{ - s32 i, j; - - for (i = 0; i < gNoOfAllBanks; i++) - { - for (j = 0; j < BATTLE_STATS_NO; j++) - gBattleMons[i].statStages[j] = 6; - } - - gBattlescriptCurrInstr++; -} - -static void atk8B_setbide(void) -{ - gBattleMons[gBankAttacker].status2 |= STATUS2_MULTIPLETURNS; - gLockedMoves[gBankAttacker] = gCurrentMove; - gTakenDmg[gBankAttacker] = 0; - gBattleMons[gBankAttacker].status2 |= (STATUS2_BIDE - 0x100); // 2 turns - - gBattlescriptCurrInstr++; -} - -static void atk8C_confuseifrepeatingattackends(void) -{ - if (!(gBattleMons[gBankAttacker].status2 & STATUS2_LOCK_CONFUSE)) - gBattleCommunication[MOVE_EFFECT_BYTE] = (MOVE_EFFECT_THRASH | MOVE_EFFECT_AFFECTS_USER); - - gBattlescriptCurrInstr++; -} - -static void atk8D_setmultihit_counter(void) -{ - if (gBattlescriptCurrInstr[1]) - { - gMultiHitCounter = gBattlescriptCurrInstr[1]; - } - else - { - gMultiHitCounter = Random() & 3; - if (gMultiHitCounter > 1) - gMultiHitCounter = (Random() & 3) + 2; - else - gMultiHitCounter += 2; - } - - gBattlescriptCurrInstr += 2; -} - -static void atk8E_init_multihit_string(void) -{ - PREPARE_BYTE_NUMBER_BUFFER(gBattleScripting.multihitString, 1, 0) - - gBattlescriptCurrInstr++; -} - -static bool8 sub_8051064(void) -{ - if (gBattleMons[gBankAttacker].level >= gBattleMons[gBankTarget].level) - { - *(gBattleStruct->field_58 + gBankTarget) = gBattlePartyID[gBankTarget]; - } - else - { - u16 random = Random() & 0xFF; - if ((u32)((random * (gBattleMons[gBankAttacker].level + gBattleMons[gBankTarget].level) >> 8) + 1) <= (gBattleMons[gBankTarget].level / 4)) - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - return FALSE; - } - *(gBattleStruct->field_58 + gBankTarget) = gBattlePartyID[gBankTarget]; - } - - gBattlescriptCurrInstr = gUnknown_082DADD8; - return TRUE; -} - -static void atk8F_forcerandomswitch(void) -{ - s32 i; - s32 bank1PartyId = 0; - s32 bank2PartyId = 0; - - #ifdef NONMATCHING - s32 lastMonId = 0; // + 1 - #else - register s32 lastMonId asm("r8") = 0; // + 1 - #endif // NONMATCHING - - s32 firstMonId = 0; - s32 monsCount = 0; - struct Pokemon* party = NULL; - s32 validMons = 0; - s32 minNeeded = 0; - - if ((gBattleTypeFlags & BATTLE_TYPE_TRAINER)) - { - if (GetBankSide(gBankTarget) == SIDE_PLAYER) - party = gPlayerParty; - else - party = gEnemyParty; - - if ((gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER && gBattleTypeFlags & BATTLE_TYPE_LINK) - || (gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER && gBattleTypeFlags & BATTLE_TYPE_x2000000) - || (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)) - { - if ((gBankTarget & BIT_MON) != 0) - { - firstMonId = 3; - lastMonId = 6; - } - else - { - firstMonId = 0; - lastMonId = 3; - } - monsCount = 3; - minNeeded = 1; - bank2PartyId = gBattlePartyID[gBankTarget]; - bank1PartyId = gBattlePartyID[gBankTarget ^ BIT_MON]; - } - else if ((gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_LINK) - || (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_x2000000)) - { - if (sub_806D82C(sub_806D864(gBankTarget)) == 1) - { - firstMonId = 3; - lastMonId = 6; - } - else - { - firstMonId = 0; - lastMonId = 3; - } - monsCount = 3; - minNeeded = 1; - bank2PartyId = gBattlePartyID[gBankTarget]; - bank1PartyId = gBattlePartyID[gBankTarget ^ BIT_MON]; - } - else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) - { - if (GetBankSide(gBankTarget) == SIDE_PLAYER) - { - firstMonId = 0; - lastMonId = 6; - monsCount = 6; - minNeeded = 2; // since there are two opponents, it has to be a double battle - } - else - { - if ((gBankTarget & BIT_MON) != 0) - { - firstMonId = 3; - lastMonId = 6; - } - else - { - firstMonId = 0; - lastMonId = 3; - } - monsCount = 3; - minNeeded = 1; - } - bank2PartyId = gBattlePartyID[gBankTarget]; - bank1PartyId = gBattlePartyID[gBankTarget ^ BIT_MON]; - } - else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) - { - firstMonId = 0; - lastMonId = 6; - monsCount = 6; - minNeeded = 2; - bank2PartyId = gBattlePartyID[gBankTarget]; - bank1PartyId = gBattlePartyID[gBankTarget ^ BIT_MON]; - } - else - { - firstMonId = 0; - lastMonId = 6; - monsCount = 6; - minNeeded = 1; - bank2PartyId = gBattlePartyID[gBankTarget]; // there is only one pokemon out in single battles - bank1PartyId = gBattlePartyID[gBankTarget]; - } - - for (i = firstMonId; i < lastMonId; i++) - { - if (GetMonData(&party[i], MON_DATA_SPECIES) != SPECIES_NONE - && !GetMonData(&party[i], MON_DATA_IS_EGG) - && GetMonData(&party[i], MON_DATA_HP) != 0) - { - validMons++; - } - } - - if (validMons <= minNeeded) - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - else - { - if (sub_8051064()) - { - do - { - i = Random() % monsCount; - i += firstMonId; - } - while (i == bank2PartyId - || i == bank1PartyId - || GetMonData(&party[i], MON_DATA_SPECIES) == SPECIES_NONE - || GetMonData(&party[i], MON_DATA_IS_EGG) == TRUE - || GetMonData(&party[i], MON_DATA_HP) == 0); - } - *(gBattleStruct->field_5C + gBankTarget) = i; - - if (!sub_81B1250()) - sub_803BDA0(gBankTarget); - - if ((gBattleTypeFlags & BATTLE_TYPE_LINK && gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER) - || (gBattleTypeFlags & BATTLE_TYPE_LINK && gBattleTypeFlags & BATTLE_TYPE_MULTI) - || (gBattleTypeFlags & BATTLE_TYPE_x2000000 && gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER) - || (gBattleTypeFlags & BATTLE_TYPE_x2000000 && gBattleTypeFlags & BATTLE_TYPE_MULTI)) - { - sub_81B8E80(gBankTarget, i, 0); - sub_81B8E80(gBankTarget ^ BIT_MON, i, 1); - } - - if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) - sub_80571DC(gBankTarget, i); - } - } - else - { - sub_8051064(); - } -} - -static void atk90_conversion_type_change(void) // randomly changes user's type to one of its moves' type -{ - u8 validMoves = 0; - u8 moveChecked; - u8 moveType; - - while (validMoves < 4) - { - if (gBattleMons[gBankAttacker].moves[validMoves] == 0) - break; - - validMoves++; - } - - for (moveChecked = 0; moveChecked < validMoves; moveChecked++) - { - moveType = gBattleMoves[gBattleMons[gBankAttacker].moves[moveChecked]].type; - - if (moveType == TYPE_MYSTERY) - { - if (gBattleMons[gBankAttacker].type1 == TYPE_GHOST || gBattleMons[gBankAttacker].type2 == TYPE_GHOST) - moveType = TYPE_GHOST; - else - moveType = TYPE_NORMAL; - } - if (moveType != gBattleMons[gBankAttacker].type1 - && moveType != gBattleMons[gBankAttacker].type2) - { - break; - } - } - - if (moveChecked == validMoves) - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - else - { - do - { - - while ((moveChecked = Random() & 3) >= validMoves); - - moveType = gBattleMoves[gBattleMons[gBankAttacker].moves[moveChecked]].type; - - if (moveType == TYPE_MYSTERY) - { - if (gBattleMons[gBankAttacker].type1 == TYPE_GHOST || gBattleMons[gBankAttacker].type2 == TYPE_GHOST) - moveType = TYPE_GHOST; - else - moveType = TYPE_NORMAL; - } - } - while (moveType == gBattleMons[gBankAttacker].type1 || moveType == gBattleMons[gBankAttacker].type2); - - gBattleMons[gBankAttacker].type1 = moveType; - gBattleMons[gBankAttacker].type2 = moveType; - - PREPARE_TYPE_BUFFER(gBattleTextBuff1, moveType) - - gBattlescriptCurrInstr += 5; - } -} - -static void atk91_givepaydaymoney(void) -{ - if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000)) && gPaydayMoney != 0) - { - u32 bonusMoney = gPaydayMoney * gBattleStruct->moneyMultiplier; - AddMoney(&gSaveBlock1Ptr->money, bonusMoney); - - PREPARE_HWORD_NUMBER_BUFFER(gBattleTextBuff1, 5, bonusMoney) - - BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_PrintPayDayMoneyString; - } - else - { - gBattlescriptCurrInstr++; - } -} - -static void atk92_setlightscreen(void) -{ - if (gSideAffecting[GET_BANK_SIDE(gBankAttacker)] & SIDE_STATUS_LIGHTSCREEN) - { - gBattleMoveFlags |= MOVESTATUS_MISSED; - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - } - else - { - gSideAffecting[GET_BANK_SIDE(gBankAttacker)] |= SIDE_STATUS_LIGHTSCREEN; - gSideTimers[GET_BANK_SIDE(gBankAttacker)].lightscreenTimer = 5; - gSideTimers[GET_BANK_SIDE(gBankAttacker)].lightscreenBank = gBankAttacker; - - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && CountAliveMonsInBattle(BATTLE_ALIVE_ATK_SIDE) == 2) - gBattleCommunication[MULTISTRING_CHOOSER] = 4; - else - gBattleCommunication[MULTISTRING_CHOOSER] = 3; - } - - gBattlescriptCurrInstr++; -} - -static void atk93_ko_move(void) -{ - u8 holdEffect, param; - - if (gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY) - { - holdEffect = gEnigmaBerries[gBankTarget].holdEffect; - param = gEnigmaBerries[gBankTarget].holdEffectParam; - } - else - { - holdEffect = ItemId_GetHoldEffect(gBattleMons[gBankTarget].item); - param = ItemId_GetHoldEffectParam(gBattleMons[gBankTarget].item); - } - - gStringBank = gBankTarget; - - if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < param) - { - RecordItemEffectBattle(gBankTarget, HOLD_EFFECT_FOCUS_BAND); - gSpecialStatuses[gBankTarget].focusBanded = 1; - } - - if (gBattleMons[gBankTarget].ability == ABILITY_STURDY) - { - gBattleMoveFlags |= MOVESTATUS_MISSED; - gLastUsedAbility = ABILITY_STURDY; - gBattlescriptCurrInstr = BattleScript_SturdyPreventsOHKO; - RecordAbilityBattle(gBankTarget, ABILITY_STURDY); - } - else - { - u16 chance; - if (!(gStatuses3[gBankTarget] & STATUS3_ALWAYS_HITS)) - { - chance = gBattleMoves[gCurrentMove].accuracy + (gBattleMons[gBankAttacker].level - gBattleMons[gBankTarget].level); - if (Random() % 100 + 1 < chance && gBattleMons[gBankAttacker].level >= gBattleMons[gBankTarget].level) - chance = TRUE; - else - chance = FALSE; - } - else if (gDisableStructs[gBankTarget].bankWithSureHit == gBankAttacker - && gBattleMons[gBankAttacker].level >= gBattleMons[gBankTarget].level) - { - chance = TRUE; - } - else - { - chance = gBattleMoves[gCurrentMove].accuracy + (gBattleMons[gBankAttacker].level - gBattleMons[gBankTarget].level); - if (Random() % 100 + 1 < chance && gBattleMons[gBankAttacker].level >= gBattleMons[gBankTarget].level) - chance = TRUE; - else - chance = FALSE; - } - if (chance) - { - if (gProtectStructs[gBankTarget].endured) - { - gBattleMoveDamage = gBattleMons[gBankTarget].hp - 1; - gBattleMoveFlags |= MOVESTATUS_ENDURED; - } - else if (gSpecialStatuses[gBankTarget].focusBanded) - { - gBattleMoveDamage = gBattleMons[gBankTarget].hp - 1; - gBattleMoveFlags |= MOVESTATUS_HUNGON; - gLastUsedItem = gBattleMons[gBankTarget].item; - } - else - { - gBattleMoveDamage = gBattleMons[gBankTarget].hp; - gBattleMoveFlags |= MOVESTATUS_ONEHITKO; - } - gBattlescriptCurrInstr += 5; - } - else - { - gBattleMoveFlags |= MOVESTATUS_MISSED; - if (gBattleMons[gBankAttacker].level >= gBattleMons[gBankTarget].level) - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - else - gBattleCommunication[MULTISTRING_CHOOSER] = 1; - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - } -} - -static void atk94_damagetohalftargethp(void) // super fang -{ - gBattleMoveDamage = gBattleMons[gBankTarget].hp / 2; - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - - gBattlescriptCurrInstr++; -} - -static void atk95_setsandstorm(void) -{ - if (gBattleWeather & WEATHER_SANDSTORM_ANY) - { - gBattleMoveFlags |= MOVESTATUS_MISSED; - gBattleCommunication[MULTISTRING_CHOOSER] = 2; - } - else - { - gBattleWeather = WEATHER_SANDSTORM_TEMPORARY; - gBattleCommunication[MULTISTRING_CHOOSER] = 3; - gWishFutureKnock.weatherDuration = 5; - } - gBattlescriptCurrInstr++; -} - -static void atk96_weatherdamage(void) -{ - if (WEATHER_HAS_EFFECT) - { - if (gBattleWeather & WEATHER_SANDSTORM_ANY) - { - if (gBattleMons[gBankAttacker].type1 != TYPE_ROCK - && gBattleMons[gBankAttacker].type1 != TYPE_STEEL - && gBattleMons[gBankAttacker].type1 != TYPE_GROUND - && gBattleMons[gBankAttacker].type2 != TYPE_ROCK - && gBattleMons[gBankAttacker].type2 != TYPE_STEEL - && gBattleMons[gBankAttacker].type2 != TYPE_GROUND - && gBattleMons[gBankAttacker].ability != ABILITY_SAND_VEIL - && !(gStatuses3[gBankAttacker] & STATUS3_UNDERGROUND) - && !(gStatuses3[gBankAttacker] & STATUS3_UNDERWATER)) - { - gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 16; - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - } - else - { - gBattleMoveDamage = 0; - } - } - if (gBattleWeather & WEATHER_HAIL) - { - if (gBattleMons[gBankAttacker].type1 != TYPE_ICE - && gBattleMons[gBankAttacker].type2 != TYPE_ICE - && !(gStatuses3[gBankAttacker] & STATUS3_UNDERGROUND) - && !(gStatuses3[gBankAttacker] & STATUS3_UNDERWATER)) - { - gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 16; - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - } - else - { - gBattleMoveDamage = 0; - } - } - } - else - { - gBattleMoveDamage = 0; - } - - if (gAbsentBankFlags & gBitTable[gBankAttacker]) - gBattleMoveDamage = 0; - - gBattlescriptCurrInstr++; -} - -static void atk97_try_infatuation(void) -{ - struct Pokemon *monAttacker, *monTarget; - u16 speciesAttacker, speciesTarget; - u32 personalityAttacker, personalityTarget; - - if (GetBankSide(gBankAttacker) == SIDE_PLAYER) - monAttacker = &gPlayerParty[gBattlePartyID[gBankAttacker]]; - else - monAttacker = &gEnemyParty[gBattlePartyID[gBankAttacker]]; - - if (GetBankSide(gBankTarget) == SIDE_PLAYER) - monTarget = &gPlayerParty[gBattlePartyID[gBankTarget]]; - else - monTarget = &gEnemyParty[gBattlePartyID[gBankTarget]]; - - speciesAttacker = GetMonData(monAttacker, MON_DATA_SPECIES); - personalityAttacker = GetMonData(monAttacker, MON_DATA_PERSONALITY); - - speciesTarget = GetMonData(monTarget, MON_DATA_SPECIES); - personalityTarget = GetMonData(monTarget, MON_DATA_PERSONALITY); - - if (gBattleMons[gBankTarget].ability == ABILITY_OBLIVIOUS) - { - gBattlescriptCurrInstr = BattleScript_ObliviousPreventsAttraction; - gLastUsedAbility = ABILITY_OBLIVIOUS; - RecordAbilityBattle(gBankTarget, ABILITY_OBLIVIOUS); - } - else - { - if (GetGenderFromSpeciesAndPersonality(speciesAttacker, personalityAttacker) == GetGenderFromSpeciesAndPersonality(speciesTarget, personalityTarget) - || gBattleMons[gBankTarget].status2 & STATUS2_INFATUATION - || GetGenderFromSpeciesAndPersonality(speciesAttacker, personalityAttacker) == MON_GENDERLESS - || GetGenderFromSpeciesAndPersonality(speciesTarget, personalityTarget) == MON_GENDERLESS) - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - else - { - gBattleMons[gBankTarget].status2 |= STATUS2_INFATUATED_WITH(gBankAttacker); - gBattlescriptCurrInstr += 5; - } - } -} - -static void atk98_status_icon_update(void) -{ - if (gBattleExecBuffer) - return; - - if (gBattlescriptCurrInstr[1] != BS_ATTACKER_WITH_PARTNER) - { - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - EmitStatusIconUpdate(0, gBattleMons[gActiveBank].status1, gBattleMons[gActiveBank].status2); - MarkBufferBankForExecution(gActiveBank); - gBattlescriptCurrInstr += 2; - } - else - { - gActiveBank = gBankAttacker; - if (!(gAbsentBankFlags & gBitTable[gActiveBank])) - { - EmitStatusIconUpdate(0, gBattleMons[gActiveBank].status1, gBattleMons[gActiveBank].status2); - MarkBufferBankForExecution(gActiveBank); - } - if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) - { - gActiveBank = GetBankByIdentity(GetBankIdentity(gBankAttacker) ^ BIT_MON); - if (!(gAbsentBankFlags & gBitTable[gActiveBank])) - { - EmitStatusIconUpdate(0, gBattleMons[gActiveBank].status1, gBattleMons[gActiveBank].status2); - MarkBufferBankForExecution(gActiveBank); - } - } - gBattlescriptCurrInstr += 2; - } -} - -static void atk99_setmist(void) -{ - if (gSideTimers[GET_BANK_SIDE(gBankAttacker)].mistTimer) - { - gBattleMoveFlags |= MOVESTATUS_FAILED; - gBattleCommunication[MULTISTRING_CHOOSER] = 1; - } - else - { - gSideTimers[GET_BANK_SIDE(gBankAttacker)].mistTimer = 5; - gSideTimers[GET_BANK_SIDE(gBankAttacker)].mistBank = gBankAttacker; - gSideAffecting[GET_BANK_SIDE(gBankAttacker)] |= SIDE_STATUS_MIST; - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - } - gBattlescriptCurrInstr++; -} - -static void atk9A_set_focusenergy(void) -{ - if (gBattleMons[gBankAttacker].status2 & STATUS2_FOCUS_ENERGY) - { - gBattleMoveFlags |= MOVESTATUS_FAILED; - gBattleCommunication[MULTISTRING_CHOOSER] = 1; - } - else - { - gBattleMons[gBankAttacker].status2 |= STATUS2_FOCUS_ENERGY; - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - } - gBattlescriptCurrInstr++; -} - -static void atk9B_transformdataexecution(void) -{ - gLastUsedMove = 0xFFFF; - gBattlescriptCurrInstr++; - if (gBattleMons[gBankTarget].status2 & STATUS2_TRANSFORMED - || gStatuses3[gBankTarget] & STATUS3_SEMI_INVULNERABLE) - { - gBattleMoveFlags |= MOVESTATUS_FAILED; - gBattleCommunication[MULTISTRING_CHOOSER] = 1; - } - else - { - s32 i; - u8 *battleMonAttacker, *battleMonTarget; - - gBattleMons[gBankAttacker].status2 |= STATUS2_TRANSFORMED; - gDisableStructs[gBankAttacker].disabledMove = 0; - gDisableStructs[gBankAttacker].disableTimer1 = 0; - gDisableStructs[gBankAttacker].unk0 = gBattleMons[gBankTarget].personality; - gDisableStructs[gBankAttacker].unk18_b = 0; - - PREPARE_SPECIES_BUFFER(gBattleTextBuff1, gBattleMons[gBankTarget].species) - - battleMonAttacker = (u8*)(&gBattleMons[gBankAttacker]); - battleMonTarget = (u8*)(&gBattleMons[gBankTarget]); - - for (i = 0; i < offsetof(struct BattlePokemon, pp); i++) - battleMonAttacker[i] = battleMonTarget[i]; - - for (i = 0; i < 4; i++) - { - if (gBattleMoves[gBattleMons[gBankAttacker].moves[i]].pp < 5) - gBattleMons[gBankAttacker].pp[i] = gBattleMoves[gBattleMons[gBankAttacker].moves[i]].pp; - else - gBattleMons[gBankAttacker].pp[i] = 5; - } - - gActiveBank = gBankAttacker; - EmitResetActionMoveSelection(0, RESET_MOVE_SELECTION); - MarkBufferBankForExecution(gActiveBank); - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - } -} - -static void atk9C_set_substitute(void) -{ - u32 hp = gBattleMons[gBankAttacker].maxHP / 4; - if (gBattleMons[gBankAttacker].maxHP / 4 == 0) - hp = 1; - - if (gBattleMons[gBankAttacker].hp <= hp) - { - gBattleMoveDamage = 0; - gBattleCommunication[MULTISTRING_CHOOSER] = 1; - } - else - { - gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 4; // one bit value will only work for pokemon which max hp can go to 1020(which is more than possible in games) - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - - gBattleMons[gBankAttacker].status2 |= STATUS2_SUBSTITUTE; - gBattleMons[gBankAttacker].status2 &= ~(STATUS2_WRAPPED); - gDisableStructs[gBankAttacker].substituteHP = gBattleMoveDamage; - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - gHitMarker |= HITMARKER_IGNORE_SUBSTITUTE; - } - - gBattlescriptCurrInstr++; -} - -static bool8 IsMoveUncopyableByMimic(u16 move) -{ - s32 i; - for (i = 0; sMovesForbiddenToCopy[i] != MIMIC_FORBIDDEN_END - && sMovesForbiddenToCopy[i] != move; i++); - - return (sMovesForbiddenToCopy[i] != MIMIC_FORBIDDEN_END); -} - -static void atk9D_mimicattackcopy(void) -{ - gLastUsedMove = 0xFFFF; - - if (IsMoveUncopyableByMimic(gLastUsedMovesByBanks[gBankTarget]) - || gBattleMons[gBankAttacker].status2 & STATUS2_TRANSFORMED - || gLastUsedMovesByBanks[gBankTarget] == 0 - || gLastUsedMovesByBanks[gBankTarget] == 0xFFFF) - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - else - { - s32 i; - - for (i = 0; i < 4; i++) - { - if (gBattleMons[gBankAttacker].moves[i] == gLastUsedMovesByBanks[gBankTarget]) - break; - } - - if (i == 4) - { - gBattleMons[gBankAttacker].moves[gCurrMovePos] = gLastUsedMovesByBanks[gBankTarget]; - if (gBattleMoves[gLastUsedMovesByBanks[gBankTarget]].pp < 5) - gBattleMons[gBankAttacker].pp[gCurrMovePos] = gBattleMoves[gLastUsedMovesByBanks[gBankTarget]].pp; - else - gBattleMons[gBankAttacker].pp[gCurrMovePos] = 5; - - - PREPARE_MOVE_BUFFER(gBattleTextBuff1, gLastUsedMovesByBanks[gBankTarget]) - - gDisableStructs[gBankAttacker].unk18_b |= gBitTable[gCurrMovePos]; - gBattlescriptCurrInstr += 5; - } - else - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - } -} - -#ifdef NONMATCHING -static void atk9E_metronome(void) -{ - while (1) - { - const u16 *move; - s32 i, j; - - gCurrentMove = (Random() & 0x1FF) + 1; - if (gCurrentMove > LAST_MOVE_INDEX) - continue; - - for (i = 0; i < 4; i++); // ? - - for (move = sMovesForbiddenToCopy; ; move++) - { - if (*move == gCurrentMove) - break; - if (*move == METRONOME_FORBIDDEN_END) - break; - } - - if (*move == METRONOME_FORBIDDEN_END) - break; - } - - gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); - gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]; - gBankTarget = GetMoveTarget(gCurrentMove, 0); -} - -#else -__attribute__((naked)) -static void atk9E_metronome(void) -{ - asm( - "\n\ - .syntax unified\n\ - push {r4-r7,lr}\n\ - mov r7, r8\n\ - push {r7}\n\ - ldr r7, =gCurrentMove\n\ - movs r6, 0xB1\n\ - lsls r6, 1\n\ - ldr r5, =sMovesForbiddenToCopy\n\ - ldr r0, =gBattlescriptCurrInstr\n\ - mov r8, r0\n\ -_080524EE:\n\ - bl Random\n\ - ldr r2, =0x000001ff\n\ - adds r1, r2, 0\n\ - ands r0, r1\n\ - adds r0, 0x1\n\ - strh r0, [r7]\n\ - cmp r0, r6\n\ - bhi _080524EE\n\ - movs r0, 0x3\n\ -_08052502:\n\ - subs r0, 0x1\n\ - cmp r0, 0\n\ - bge _08052502\n\ - ldr r4, =gCurrentMove\n\ - ldrh r2, [r4]\n\ - ldr r3, =0x0000ffff\n\ - subs r0, r5, 0x2\n\ -_08052510:\n\ - adds r0, 0x2\n\ - ldrh r1, [r0]\n\ - cmp r1, r2\n\ - beq _0805251C\n\ - cmp r1, r3\n\ - bne _08052510\n\ -_0805251C:\n\ - ldr r0, =0x0000ffff\n\ - cmp r1, r0\n\ - bne _080524EE\n\ - ldr r2, =gHitMarker\n\ - ldr r0, [r2]\n\ - ldr r1, =0xfffffbff\n\ - ands r0, r1\n\ - str r0, [r2]\n\ - ldr r3, =gBattleScriptsForMoveEffects\n\ - ldr r2, =gBattleMoves\n\ - ldrh r1, [r4]\n\ - lsls r0, r1, 1\n\ - adds r0, r1\n\ - lsls r0, 2\n\ - adds r0, r2\n\ - ldrb r0, [r0]\n\ - lsls r0, 2\n\ - adds r0, r3\n\ - ldr r0, [r0]\n\ - mov r1, r8\n\ - str r0, [r1]\n\ - ldrh r0, [r4]\n\ - movs r1, 0\n\ - bl GetMoveTarget\n\ - ldr r1, =gBankTarget\n\ - strb r0, [r1]\n\ - pop {r3}\n\ - mov r8, r3\n\ - pop {r4-r7}\n\ - pop {r0}\n\ - bx r0\n\ - .pool\n\ - .syntax divided"); -} - -#endif // NONMATCHING - -static void atk9F_dmgtolevel(void) -{ - gBattleMoveDamage = gBattleMons[gBankAttacker].level; - gBattlescriptCurrInstr++; -} - -static void atkA0_psywavedamageeffect(void) -{ - s32 randDamage; - - while ((randDamage = (Random() & 0xF)) > 10); - - randDamage *= 10; - gBattleMoveDamage = gBattleMons[gBankAttacker].level * (randDamage + 50) / 100; - gBattlescriptCurrInstr++; -} - -static void atkA1_counterdamagecalculator(void) -{ - u8 sideAttacker = GetBankSide(gBankAttacker); - u8 sideTarget = GetBankSide(gProtectStructs[gBankAttacker].physicalBank); - - if (gProtectStructs[gBankAttacker].physicalDmg - && sideAttacker != sideTarget - && gBattleMons[gProtectStructs[gBankAttacker].physicalBank].hp) - { - gBattleMoveDamage = gProtectStructs[gBankAttacker].physicalDmg * 2; - - if (gSideTimers[sideTarget].followmeTimer && gBattleMons[gSideTimers[sideTarget].followmeTarget].hp) - gBankTarget = gSideTimers[sideTarget].followmeTarget; - else - gBankTarget = gProtectStructs[gBankAttacker].physicalBank; - - gBattlescriptCurrInstr += 5; - } - else - { - gSpecialStatuses[gBankAttacker].flag20 = 1; - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } -} - -static void atkA2_mirrorcoatdamagecalculator(void) // a copy of atkA1 with the physical -> special field changes -{ - u8 sideAttacker = GetBankSide(gBankAttacker); - u8 sideTarget = GetBankSide(gProtectStructs[gBankAttacker].specialBank); - - if (gProtectStructs[gBankAttacker].specialDmg && sideAttacker != sideTarget && gBattleMons[gProtectStructs[gBankAttacker].specialBank].hp) - { - gBattleMoveDamage = gProtectStructs[gBankAttacker].specialDmg * 2; - - if (gSideTimers[sideTarget].followmeTimer && gBattleMons[gSideTimers[sideTarget].followmeTarget].hp) - gBankTarget = gSideTimers[sideTarget].followmeTarget; - else - gBankTarget = gProtectStructs[gBankAttacker].specialBank; - - gBattlescriptCurrInstr += 5; - } - else - { - gSpecialStatuses[gBankAttacker].flag20 = 1; - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } -} - -static void atkA3_disablelastusedattack(void) -{ - s32 i; - - for (i = 0; i < 4; i++) - { - if (gBattleMons[gBankTarget].moves[i] == gLastUsedMovesByBanks[gBankTarget]) - break; - } - if (gDisableStructs[gBankTarget].disabledMove == 0 - && i != 4 && gBattleMons[gBankTarget].pp[i] != 0) - { - PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleMons[gBankTarget].moves[i]) - - gDisableStructs[gBankTarget].disabledMove = gBattleMons[gBankTarget].moves[i]; - gDisableStructs[gBankTarget].disableTimer1 = (Random() & 3) + 2; - gDisableStructs[gBankTarget].disableTimer2 = gDisableStructs[gBankTarget].disableTimer1; // used to save the random amount of turns? - gBattlescriptCurrInstr += 5; - } - else - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } -} - -static void atkA4_setencore(void) -{ - s32 i; - - for (i = 0; i < 4; i++) - { - if (gBattleMons[gBankTarget].moves[i] == gLastUsedMovesByBanks[gBankTarget]) - break; - } - - if (gLastUsedMovesByBanks[gBankTarget] == MOVE_STRUGGLE - || gLastUsedMovesByBanks[gBankTarget] == MOVE_ENCORE - || gLastUsedMovesByBanks[gBankTarget] == MOVE_MIRROR_MOVE) - { - i = 4; - } - - if (gDisableStructs[gBankTarget].encoredMove == 0 - && i != 4 && gBattleMons[gBankTarget].pp[i] != 0) - { - gDisableStructs[gBankTarget].encoredMove = gBattleMons[gBankTarget].moves[i]; - gDisableStructs[gBankTarget].encoredMovePos = i; - gDisableStructs[gBankTarget].encoreTimer1 = (Random() & 3) + 3; - gDisableStructs[gBankTarget].encoreTimer2 = gDisableStructs[gBankTarget].encoreTimer1; - gBattlescriptCurrInstr += 5; - } - else - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } -} - -static void atkA5_painsplitdmgcalc(void) -{ - if (!(gBattleMons[gBankTarget].status2 & STATUS2_SUBSTITUTE)) - { - s32 hpDiff = (gBattleMons[gBankAttacker].hp + gBattleMons[gBankTarget].hp) / 2; - s32 painSplitHp = gBattleMoveDamage = gBattleMons[gBankTarget].hp - hpDiff; - u8* storeLoc = (void*)(&gBattleScripting.painSplitHp); - - storeLoc[0] = (painSplitHp); - storeLoc[1] = (painSplitHp & 0x0000FF00) >> 8; - storeLoc[2] = (painSplitHp & 0x00FF0000) >> 16; - storeLoc[3] = (painSplitHp & 0xFF000000) >> 24; - - gBattleMoveDamage = gBattleMons[gBankAttacker].hp - hpDiff; - gSpecialStatuses[gBankTarget].moveturnLostHP = 0xFFFF; - - gBattlescriptCurrInstr += 5; - } - else - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } -} - -#ifdef NONMATCHING -static void atkA6_settypetorandomresistance(void) // conversion 2 -{ - if (gUnknown_02024250[gBankAttacker] == 0 - || gUnknown_02024250[gBankAttacker] == 0xFFFF) - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - else if (IsTwoTurnsMove(gUnknown_02024250[gBankAttacker]) - && gBattleMons[gUnknown_02024270[gBankAttacker]].status2 & STATUS2_MULTIPLETURNS) - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - else - { - s32 type = 0, rands = 0; - do - { - while (((type = (Random() & 0x7F)) > 0x70)); - - type *= 3; - - if (gTypeEffectiveness[type] == gUnknown_02024258[gBankAttacker] - && gTypeEffectiveness[type + 2] <= 5 - && gBattleMons[gBankAttacker].type1 != gTypeEffectiveness[type + 1] - && gBattleMons[gBankAttacker].type2 != gTypeEffectiveness[type + 1]) - { - gBattleMons[gBankAttacker].type1 = type; - gBattleMons[gBankAttacker].type2 = type; - - PREPARE_TYPE_BUFFER(gBattleTextBuff1, type) - - gBattlescriptCurrInstr += 5; - return; - } - - rands++; - } while (rands <= 999); - - type = 0, rands = 0; - do - { - s8 var = (s8)(gTypeEffectiveness[type]); - if (var > -1 || var < -2) - { - if (gTypeEffectiveness[type] == gUnknown_02024258[gBankAttacker] - && gTypeEffectiveness[type + 2] <= 5 - && gBattleMons[gBankAttacker].type1 != gTypeEffectiveness[type + 1] - && gBattleMons[gBankAttacker].type2 != gTypeEffectiveness[type + 1]) - { - gBattleMons[gBankAttacker].type1 = gTypeEffectiveness[rands + 1]; - gBattleMons[gBankAttacker].type2 = gTypeEffectiveness[rands + 1]; - - PREPARE_TYPE_BUFFER(gBattleTextBuff1, gTypeEffectiveness[rands + 1]) - - gBattlescriptCurrInstr += 5; - return; - } - } - type += 3, rands += 3; - } while (rands < 336); - - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } -} - -#else -__attribute__((naked)) -static void atkA6_settypetorandomresistance(void) // conversion 2 -{ - asm(".syntax unified\n\ - push {r4-r7,lr}\n\ - mov r7, r10\n\ - mov r6, r9\n\ - mov r5, r8\n\ - push {r5-r7}\n\ - ldr r1, =gUnknown_02024250\n\ - ldr r4, =gBankAttacker\n\ - ldrb r0, [r4]\n\ - lsls r0, 1\n\ - adds r2, r0, r1\n\ - ldrh r1, [r2]\n\ - cmp r1, 0\n\ - beq _08052B7E\n\ - ldr r0, =0x0000ffff\n\ - cmp r1, r0\n\ - beq _08052B7E\n\ - ldrh r0, [r2]\n\ - bl IsTwoTurnsMove\n\ - lsls r0, 24\n\ - cmp r0, 0\n\ - beq _08052C1C\n\ - ldr r1, =gBattleMons\n\ - ldr r2, =gUnknown_02024270\n\ - ldrb r0, [r4]\n\ - adds r0, r2\n\ - ldrb r2, [r0]\n\ - movs r0, 0x58\n\ - muls r0, r2\n\ - adds r1, 0x50\n\ - adds r0, r1\n\ - ldr r0, [r0]\n\ - movs r1, 0x80\n\ - lsls r1, 5\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _08052C1C\n\ -_08052B7E:\n\ - ldr r3, =gBattlescriptCurrInstr\n\ - ldr r2, [r3]\n\ - ldrb r1, [r2, 0x1]\n\ - ldrb r0, [r2, 0x2]\n\ - lsls r0, 8\n\ - orrs r1, r0\n\ - ldrb r0, [r2, 0x3]\n\ - lsls r0, 16\n\ - orrs r1, r0\n\ - ldrb r0, [r2, 0x4]\n\ - lsls r0, 24\n\ - orrs r1, r0\n\ - str r1, [r3]\n\ - b _08052D08\n\ - .pool\n\ -_08052BB4:\n\ - mov r0, r12\n\ - strb r5, [r0]\n\ - mov r1, r10\n\ - ldrb r0, [r1]\n\ - muls r0, r2\n\ - adds r0, r7\n\ - adds r0, 0x22\n\ - strb r5, [r0]\n\ - ldr r1, =gBattleTextBuff1\n\ - movs r0, 0xFD\n\ - strb r0, [r1]\n\ - movs r0, 0x3\n\ - strb r0, [r1, 0x1]\n\ - strb r5, [r1, 0x2]\n\ - movs r0, 0xFF\n\ - strb r0, [r1, 0x3]\n\ - ldr r1, =gBattlescriptCurrInstr\n\ - b _08052C0A\n\ - .pool\n\ -_08052BE0:\n\ - mov r0, r8\n\ - adds r0, 0x1\n\ - adds r0, r3\n\ - ldrb r2, [r0]\n\ - strb r2, [r4]\n\ - mov r4, r10\n\ - ldrb r0, [r4]\n\ - muls r0, r6\n\ - ldr r7, =gBattleMons\n\ - adds r0, r7\n\ - adds r0, 0x22\n\ - strb r2, [r0]\n\ - ldr r1, =gBattleTextBuff1\n\ - movs r0, 0xFD\n\ - strb r0, [r1]\n\ - movs r0, 0x3\n\ - strb r0, [r1, 0x1]\n\ - strb r2, [r1, 0x2]\n\ - movs r0, 0xFF\n\ - strb r0, [r1, 0x3]\n\ - mov r1, r12\n\ -_08052C0A:\n\ - ldr r0, [r1]\n\ - adds r0, 0x5\n\ - str r0, [r1]\n\ - b _08052D08\n\ - .pool\n\ -_08052C1C:\n\ - movs r4, 0\n\ - mov r8, r4\n\ - movs r7, 0x7F\n\ - mov r9, r7\n\ -_08052C24:\n\ - bl Random\n\ - mov r4, r9\n\ - ands r4, r0\n\ - cmp r4, 0x70\n\ - bhi _08052C24\n\ - lsls r0, r4, 1\n\ - adds r4, r0, r4\n\ - ldr r6, =gTypeEffectiveness\n\ - adds r3, r4, r6\n\ - ldr r1, =gUnknown_02024258\n\ - ldr r2, =gBankAttacker\n\ - ldrb r5, [r2]\n\ - lsls r0, r5, 1\n\ - adds r0, r1\n\ - ldrb r1, [r3]\n\ - mov r10, r2\n\ - ldrh r0, [r0]\n\ - cmp r1, r0\n\ - bne _08052C80\n\ - adds r0, r4, 0x2\n\ - adds r0, r6\n\ - ldrb r0, [r0]\n\ - cmp r0, 0x5\n\ - bhi _08052C80\n\ - ldr r7, =gBattleMons\n\ - movs r2, 0x58\n\ - adds r0, r5, 0\n\ - muls r0, r2\n\ - adds r3, r0, r7\n\ - movs r0, 0x21\n\ - adds r0, r3\n\ - mov r12, r0\n\ - adds r0, r4, 0x1\n\ - adds r0, r6\n\ - ldrb r5, [r0]\n\ - mov r1, r12\n\ - ldrb r0, [r1]\n\ - adds r1, r5, 0\n\ - cmp r0, r1\n\ - beq _08052C80\n\ - adds r0, r3, 0\n\ - adds r0, 0x22\n\ - ldrb r0, [r0]\n\ - cmp r0, r1\n\ - bne _08052BB4\n\ -_08052C80:\n\ - movs r7, 0x1\n\ - add r8, r7\n\ - ldr r0, =0x000003e7\n\ - cmp r8, r0\n\ - ble _08052C24\n\ - movs r0, 0\n\ - mov r8, r0\n\ - ldr r1, =gBattlescriptCurrInstr\n\ - mov r12, r1\n\ - ldr r3, =gTypeEffectiveness\n\ - adds r0, r4, 0x1\n\ - adds r0, r3\n\ - mov r9, r0\n\ - adds r5, r3, 0\n\ -_08052C9C:\n\ - ldrb r1, [r5]\n\ - cmp r1, 0xFF\n\ - bgt _08052CA6\n\ - cmp r1, 0xFE\n\ - bge _08052CE0\n\ -_08052CA6:\n\ - mov r4, r10\n\ - ldrb r2, [r4]\n\ - lsls r0, r2, 1\n\ - ldr r7, =gUnknown_02024258\n\ - adds r0, r7\n\ - ldrh r0, [r0]\n\ - cmp r1, r0\n\ - bne _08052CE0\n\ - ldrb r0, [r5, 0x2]\n\ - cmp r0, 0x5\n\ - bhi _08052CE0\n\ - movs r6, 0x58\n\ - adds r0, r2, 0\n\ - muls r0, r6\n\ - ldr r1, =gBattleMons\n\ - adds r2, r0, r1\n\ - adds r4, r2, 0\n\ - adds r4, 0x21\n\ - ldrb r0, [r4]\n\ - mov r7, r9\n\ - ldrb r1, [r7]\n\ - cmp r0, r1\n\ - beq _08052CE0\n\ - adds r0, r2, 0\n\ - adds r0, 0x22\n\ - ldrb r0, [r0]\n\ - cmp r0, r1\n\ - beq _08052CE0\n\ - b _08052BE0\n\ -_08052CE0:\n\ - adds r5, 0x3\n\ - movs r0, 0x3\n\ - add r8, r0\n\ - ldr r0, =0x0000014f\n\ - cmp r8, r0\n\ - bls _08052C9C\n\ - mov r1, r12\n\ - ldr r2, [r1]\n\ - ldrb r1, [r2, 0x1]\n\ - ldrb r0, [r2, 0x2]\n\ - lsls r0, 8\n\ - orrs r1, r0\n\ - ldrb r0, [r2, 0x3]\n\ - lsls r0, 16\n\ - orrs r1, r0\n\ - ldrb r0, [r2, 0x4]\n\ - lsls r0, 24\n\ - orrs r1, r0\n\ - mov r4, r12\n\ - str r1, [r4]\n\ -_08052D08:\n\ - pop {r3-r5}\n\ - mov r8, r3\n\ - mov r9, r4\n\ - mov r10, r5\n\ - pop {r4-r7}\n\ - pop {r0}\n\ - bx r0\n\ - .pool\n\ - .syntax divided"); -} -#endif // NONMATCHING - -static void atkA7_setalwayshitflag(void) -{ - gStatuses3[gBankTarget] &= ~(STATUS3_ALWAYS_HITS); - gStatuses3[gBankTarget] |= 0x10; - gDisableStructs[gBankTarget].bankWithSureHit = gBankAttacker; - gBattlescriptCurrInstr++; -} - -static void atkA8_copymovepermanently(void) // sketch -{ - gLastUsedMove = 0xFFFF; - - if (!(gBattleMons[gBankAttacker].status2 & STATUS2_TRANSFORMED) - && gUnknownMovesUsedByBanks[gBankTarget] != MOVE_STRUGGLE - && gUnknownMovesUsedByBanks[gBankTarget] != 0 - && gUnknownMovesUsedByBanks[gBankTarget] != 0xFFFF - && gUnknownMovesUsedByBanks[gBankTarget] != MOVE_SKETCH) - { - s32 i; - - for (i = 0; i < 4; i++) - { - if (gBattleMons[gBankAttacker].moves[i] == MOVE_SKETCH) - continue; - if (gBattleMons[gBankAttacker].moves[i] == gUnknownMovesUsedByBanks[gBankTarget]) - break; - } - - if (i != 4) - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - else // sketch worked - { - struct MovePpInfo movePpData; - - gBattleMons[gBankAttacker].moves[gCurrMovePos] = gUnknownMovesUsedByBanks[gBankTarget]; - gBattleMons[gBankAttacker].pp[gCurrMovePos] = gBattleMoves[gUnknownMovesUsedByBanks[gBankTarget]].pp; - gActiveBank = gBankAttacker; - - for (i = 0; i < 4; i++) - { - movePpData.move[i] = gBattleMons[gBankAttacker].moves[i]; - movePpData.pp[i] = gBattleMons[gBankAttacker].pp[i]; - } - movePpData.ppBonuses = gBattleMons[gBankAttacker].ppBonuses; - - EmitSetMonData(0, REQUEST_MOVES_PP_BATTLE, 0, sizeof(struct MovePpInfo), &movePpData); - MarkBufferBankForExecution(gActiveBank); - - PREPARE_MOVE_BUFFER(gBattleTextBuff1, gUnknownMovesUsedByBanks[gBankTarget]) - - gBattlescriptCurrInstr += 5; - } - } - else - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } -} - -static bool8 IsTwoTurnsMove(u16 move) -{ - if (gBattleMoves[move].effect == EFFECT_SKULL_BASH - || gBattleMoves[move].effect == EFFECT_RAZOR_WIND - || gBattleMoves[move].effect == EFFECT_SKY_ATTACK - || gBattleMoves[move].effect == EFFECT_SOLARBEAM - || gBattleMoves[move].effect == EFFECT_FLY - || gBattleMoves[move].effect == EFFECT_BIDE) - return TRUE; - else - return FALSE; -} - -static bool8 IsInvalidForSleepTalkOrAssist(u16 move) -{ - if (move == 0 || move == MOVE_SLEEP_TALK || move == MOVE_ASSIST - || move == MOVE_MIRROR_MOVE || move == MOVE_METRONOME) - return TRUE; - else - return FALSE; -} - -static u8 AttacksThisTurn(u8 bank, u16 move) // Note: returns 1 if it's a charging turn, otherwise 2 -{ - // first argument is unused - if (gBattleMoves[move].effect == EFFECT_SOLARBEAM - && (gBattleWeather & WEATHER_SUN_ANY)) - return 2; - - if (gBattleMoves[move].effect == EFFECT_SKULL_BASH - || gBattleMoves[move].effect == EFFECT_RAZOR_WIND - || gBattleMoves[move].effect == EFFECT_SKY_ATTACK - || gBattleMoves[move].effect == EFFECT_SOLARBEAM - || gBattleMoves[move].effect == EFFECT_FLY - || gBattleMoves[move].effect == EFFECT_BIDE) - { - if ((gHitMarker & HITMARKER_x8000000)) - return 1; - } - return 2; -} - -static void atkA9_sleeptalk_choose_move(void) -{ - s32 i; - u8 unusableMovesBits = 0; - - for (i = 0; i < 4; i++) - { - if (IsInvalidForSleepTalkOrAssist(gBattleMons[gBankAttacker].moves[i]) - || gBattleMons[gBankAttacker].moves[i] == MOVE_FOCUS_PUNCH - || gBattleMons[gBankAttacker].moves[i] == MOVE_UPROAR - || IsTwoTurnsMove(gBattleMons[gBankAttacker].moves[i])) - { - unusableMovesBits |= gBitTable[i]; - } - - } - - unusableMovesBits = CheckMoveLimitations(gBankAttacker, unusableMovesBits, ~(MOVE_LIMITATION_PP)); - if (unusableMovesBits == 0xF) // all 4 moves cannot be chosen - { - gBattlescriptCurrInstr += 5; - } - else // at least one move can be chosen - { - u32 movePosition; - - do - { - movePosition = Random() & 3; - } while ((gBitTable[movePosition] & unusableMovesBits)); - - gRandomMove = gBattleMons[gBankAttacker].moves[movePosition]; - gCurrMovePos = movePosition; - gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); - gBankTarget = GetMoveTarget(gRandomMove, 0); - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } -} - -static void atkAA_set_destinybond(void) -{ - gBattleMons[gBankAttacker].status2 |= STATUS2_DESTINY_BOND; - gBattlescriptCurrInstr++; -} - -static void DestinyBondFlagUpdate(void) -{ - u8 sideAttacker = GetBankSide(gBankAttacker); - u8 sideTarget = GetBankSide(gBankTarget); - if (gBattleMons[gBankTarget].status2 & STATUS2_DESTINY_BOND - && sideAttacker != sideTarget - && !(gHitMarker & HITMARKER_GRUDGE)) - { - gHitMarker |= HITMARKER_DESTINYBOND; - } -} - -static void atkAB_DestinyBondFlagUpdate(void) -{ - DestinyBondFlagUpdate(); - gBattlescriptCurrInstr++; -} - -static void atkAC_remaininghptopower(void) -{ - s32 i; - s32 hpFraction = GetScaledHPFraction(gBattleMons[gBankAttacker].hp, gBattleMons[gBankAttacker].maxHP, 48); - - for (i = 0; i < (s32) sizeof(sFlailHpScaleToPowerTable); i += 2) - { - if (hpFraction <= sFlailHpScaleToPowerTable[i]) - break; - } - - gDynamicBasePower = sFlailHpScaleToPowerTable[i + 1]; - gBattlescriptCurrInstr++; -} - -static void atkAD_spite_ppreduce(void) -{ - if (gLastUsedMovesByBanks[gBankTarget] != 0 - && gLastUsedMovesByBanks[gBankTarget] != 0xFFFF) - { - s32 i; - - for (i = 0; i < 4; i++) - { - if (gLastUsedMovesByBanks[gBankTarget] == gBattleMons[gBankTarget].moves[i]) - break; - } - - if (i != 4 && gBattleMons[gBankTarget].pp[i] > 1) - { - s32 ppToDeduct = (Random() & 3) + 2; - if (gBattleMons[gBankTarget].pp[i] < ppToDeduct) - ppToDeduct = gBattleMons[gBankTarget].pp[i]; - - PREPARE_MOVE_BUFFER(gBattleTextBuff1, gLastUsedMovesByBanks[gBankTarget]) - - ConvertIntToDecimalStringN(gBattleTextBuff2, ppToDeduct, 0, 1); - - PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff2, 1, ppToDeduct) - - gBattleMons[gBankTarget].pp[i] -= ppToDeduct; - gActiveBank = gBankTarget; - - if (!(gDisableStructs[gActiveBank].unk18_b & gBitTable[i]) - && !(gBattleMons[gActiveBank].status2 & STATUS2_TRANSFORMED)) - { - EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + i, 0, 1, &gBattleMons[gActiveBank].pp[i]); - MarkBufferBankForExecution(gActiveBank); - } - - gBattlescriptCurrInstr += 5; - - if (gBattleMons[gBankTarget].pp[i] == 0) - CancelMultiTurnMoves(gBankTarget); - } - else - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - } - else - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } -} - -static void atkAE_heal_party_status(void) -{ - u32 zero = 0; - u8 toHeal = 0; - - if (gCurrentMove == MOVE_HEAL_BELL) - { - struct Pokemon* party; - s32 i; - - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - - if (GetBankSide(gBankAttacker) == SIDE_PLAYER) - party = gPlayerParty; - else - party = gEnemyParty; - - if (gBattleMons[gBankAttacker].ability != ABILITY_SOUNDPROOF) - { - gBattleMons[gBankAttacker].status1 = 0; - gBattleMons[gBankAttacker].status2 &= ~(STATUS2_NIGHTMARE); - } - else - { - RecordAbilityBattle(gBankAttacker, gBattleMons[gBankAttacker].ability); - gBattleCommunication[MULTISTRING_CHOOSER] |= 1; - } - - gActiveBank = gBattleScripting.bank = GetBankByIdentity(GetBankIdentity(gBankAttacker) ^ BIT_MON); - - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE - && !(gAbsentBankFlags & gBitTable[gActiveBank])) - { - if (gBattleMons[gActiveBank].ability != ABILITY_SOUNDPROOF) - { - gBattleMons[gActiveBank].status1 = 0; - gBattleMons[gActiveBank].status2 &= ~(STATUS2_NIGHTMARE); - } - else - { - RecordAbilityBattle(gActiveBank, gBattleMons[gActiveBank].ability); - gBattleCommunication[MULTISTRING_CHOOSER] |= 2; - } - } - - for (i = 0; i < 6; i++) - { - u16 species = GetMonData(&party[i], MON_DATA_SPECIES2); - u8 abilityBit = GetMonData(&party[i], MON_DATA_ALT_ABILITY); - - if (species != 0 && species != SPECIES_EGG) - { - u8 ability; - - if (gBattlePartyID[gBankAttacker] == i) - ability = gBattleMons[gBankAttacker].ability; - else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE - && gBattlePartyID[gActiveBank] == i - && !(gAbsentBankFlags & gBitTable[gActiveBank])) - ability = gBattleMons[gActiveBank].ability; - else - ability = GetAbilityBySpecies(species, abilityBit); - - if (ability != ABILITY_SOUNDPROOF) - toHeal |= (1 << i); - } - } - } - else // Aromatherapy - { - gBattleCommunication[MULTISTRING_CHOOSER] = 4; - toHeal = 0x3F; - - gBattleMons[gBankAttacker].status1 = 0; - gBattleMons[gBankAttacker].status2 &= ~(STATUS2_NIGHTMARE); - - gActiveBank = GetBankByIdentity(GetBankIdentity(gBankAttacker) ^ 2); - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE - && !(gAbsentBankFlags & gBitTable[gActiveBank])) - { - gBattleMons[gActiveBank].status1 = 0; - gBattleMons[gActiveBank].status2 &= ~(STATUS2_NIGHTMARE); - } - - } - - if (toHeal) - { - gActiveBank = gBankAttacker; - EmitSetMonData(0, REQUEST_STATUS_BATTLE, toHeal, 4, &zero); - MarkBufferBankForExecution(gActiveBank); - } - - gBattlescriptCurrInstr++; -} - -static void atkAF_cursetarget(void) -{ - if (gBattleMons[gBankTarget].status2 & STATUS2_CURSED) - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - else - { - gBattleMons[gBankTarget].status2 |= STATUS2_CURSED; - gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 2; - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - - gBattlescriptCurrInstr += 5; - } -} - -static void atkB0_set_spikes(void) -{ - u8 targetSide = GetBankSide(gBankAttacker) ^ BIT_SIDE; - - if (gSideTimers[targetSide].spikesAmount == 3) - { - gSpecialStatuses[gBankAttacker].flag20 = 1; - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - else - { - gSideAffecting[targetSide] |= SIDE_STATUS_SPIKES; - gSideTimers[targetSide].spikesAmount++; - gBattlescriptCurrInstr += 5; - } -} - -static void atkB1_set_foresight(void) -{ - gBattleMons[gBankTarget].status2 |= STATUS2_FORESIGHT; - gBattlescriptCurrInstr++; -} - -static void atkB2_setperishsong(void) -{ - s32 i; - s32 notAffectedCount = 0; - - for (i = 0; i < gNoOfAllBanks; i++) - { - if (gStatuses3[i] & STATUS3_PERISH_SONG - || gBattleMons[i].ability == ABILITY_SOUNDPROOF) - { - notAffectedCount++; - } - else - { - gStatuses3[i] |= STATUS3_PERISH_SONG; - gDisableStructs[i].perishSong1 = 3; - gDisableStructs[i].perishSong2 = 3; - } - } - - PressurePPLoseOnUsingPerishSong(gBankAttacker); - - if (notAffectedCount == gNoOfAllBanks) - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - else - gBattlescriptCurrInstr += 5; -} - -static void atkB3_rolloutdamagecalculation(void) -{ - if (gBattleMoveFlags & MOVESTATUS_NOEFFECT) - { - CancelMultiTurnMoves(gBankAttacker); - gBattlescriptCurrInstr = BattleScript_PauseEffectivenessSoundResultMsgEndMove; - } - else - { - s32 i; - - if (!(gBattleMons[gBankAttacker].status2 & STATUS2_MULTIPLETURNS)) // first hit - { - gDisableStructs[gBankAttacker].rolloutTimer1 = 5; - gDisableStructs[gBankAttacker].rolloutTimer2 = 5; - gBattleMons[gBankAttacker].status2 |= STATUS2_MULTIPLETURNS; - gLockedMoves[gBankAttacker] = gCurrentMove; - } - if (--gDisableStructs[gBankAttacker].rolloutTimer1 == 0) // last hit - { - gBattleMons[gBankAttacker].status2 &= ~(STATUS2_MULTIPLETURNS); - } - - gDynamicBasePower = gBattleMoves[gCurrentMove].power; - - for (i = 1; i < (5 - gDisableStructs[gBankAttacker].rolloutTimer1); i++) - gDynamicBasePower *= 2; - - if (gBattleMons[gBankAttacker].status2 & STATUS2_DEFENSE_CURL) - gDynamicBasePower *= 2; - - gBattlescriptCurrInstr++; - } -} - -static void atkB4_jumpifconfusedandstatmaxed(void) -{ - if (gBattleMons[gBankTarget].status2 & STATUS2_CONFUSION - && gBattleMons[gBankTarget].statStages[gBattlescriptCurrInstr[1]] == 0xC) - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); - else - gBattlescriptCurrInstr += 6; -} - -static void atkB5_furycuttercalc(void) -{ - if (gBattleMoveFlags & MOVESTATUS_NOEFFECT) - { - gDisableStructs[gBankAttacker].furyCutterCounter = 0; - gBattlescriptCurrInstr = BattleScript_PauseEffectivenessSoundResultMsgEndMove; - } - else - { - s32 i; - - if (gDisableStructs[gBankAttacker].furyCutterCounter != 5) - gDisableStructs[gBankAttacker].furyCutterCounter++; - - gDynamicBasePower = gBattleMoves[gCurrentMove].power; - - for (i = 1; i < gDisableStructs[gBankAttacker].furyCutterCounter; i++) - gDynamicBasePower *= 2; - - gBattlescriptCurrInstr++; - } -} - -static void atkB6_happinesstodamagecalculation(void) -{ - if (gBattleMoves[gCurrentMove].effect == EFFECT_RETURN) - gDynamicBasePower = 10 * (gBattleMons[gBankAttacker].friendship) / 25; - else // EFFECT_FRUSTRATION - gDynamicBasePower = 10 * (255 - gBattleMons[gBankAttacker].friendship) / 25; - - gBattlescriptCurrInstr++; -} - -static void atkB7_presentdamagecalculation(void) -{ - s32 rand = Random() & 0xFF; - - if (rand < 102) - gDynamicBasePower = 40; - else if (rand < 178) - gDynamicBasePower = 80; - else if (rand < 204) - gDynamicBasePower = 120; - else - { - gBattleMoveDamage = gBattleMons[gBankTarget].maxHP / 4; - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - gBattleMoveDamage *= -1; - } - if (rand < 204) - gBattlescriptCurrInstr = BattleScript_PresentDamageTarget; - else if (gBattleMons[gBankTarget].maxHP == gBattleMons[gBankTarget].hp) - gBattlescriptCurrInstr = BattleScript_AlreadyAtFullHp; - else - { - gBattleMoveFlags &= ~(MOVESTATUS_NOTAFFECTED); - gBattlescriptCurrInstr = BattleScript_PresentHealTarget; - } -} - -static void atkB8_set_safeguard(void) -{ - if (gSideAffecting[GET_BANK_SIDE(gBankAttacker)] & SIDE_STATUS_SAFEGUARD) - { - gBattleMoveFlags |= MOVESTATUS_MISSED; - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - } - else - { - gSideAffecting[GET_BANK_SIDE(gBankAttacker)] |= SIDE_STATUS_SAFEGUARD; - gSideTimers[GET_BANK_SIDE(gBankAttacker)].safeguardTimer = 5; - gSideTimers[GET_BANK_SIDE(gBankAttacker)].safeguardBank = gBankAttacker; - gBattleCommunication[MULTISTRING_CHOOSER] = 5; - } - - gBattlescriptCurrInstr++; -} - -static void atkB9_magnitudedamagecalculation(void) -{ - s32 magnitude = Random() % 100; - - if (magnitude < 5) - { - gDynamicBasePower = 10; - magnitude = 4; - } - else if (magnitude < 15) - { - gDynamicBasePower = 30; - magnitude = 5; - } - else if (magnitude < 35) - { - gDynamicBasePower = 50; - magnitude = 6; - } - else if (magnitude < 65) - { - gDynamicBasePower = 70; - magnitude = 7; - } - else if (magnitude < 85) - { - gDynamicBasePower = 90; - magnitude = 8; - } - else if (magnitude < 95) - { - gDynamicBasePower = 110; - magnitude = 9; - } - else - { - gDynamicBasePower = 150; - magnitude = 10; - } - - - PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff1, 2, magnitude) - - for (gBankTarget = 0; gBankTarget < gNoOfAllBanks; gBankTarget++) - { - if (gBankTarget == gBankAttacker) - continue; - if (!(gAbsentBankFlags & gBitTable[gBankTarget])) // a valid target was found - break; - } - - gBattlescriptCurrInstr++; -} - -static void atkBA_jumpifnopursuitswitchdmg(void) -{ - if (gMultiHitCounter == 1) - { - if (GetBankSide(gBankAttacker) == SIDE_PLAYER) - gBankTarget = GetBankByIdentity(IDENTITY_OPPONENT_MON1); - else - gBankTarget = GetBankByIdentity(IDENTITY_PLAYER_MON1); - } - else - { - if (GetBankSide(gBankAttacker) == SIDE_PLAYER) - gBankTarget = GetBankByIdentity(IDENTITY_OPPONENT_MON2); - else - gBankTarget = GetBankByIdentity(IDENTITY_PLAYER_MON2); - } - - if (gActionForBanks[gBankTarget] == 0 - && gBankAttacker == *(gBattleStruct->moveTarget + gBankTarget) - && !(gBattleMons[gBankTarget].status1 & (STATUS_SLEEP | STATUS_FREEZE)) - && gBattleMons[gBankAttacker].hp - && !gDisableStructs[gBankTarget].truantCounter - && gChosenMovesByBanks[gBankTarget] == MOVE_PURSUIT) - { - s32 i; - - for (i = 0; i < gNoOfAllBanks; i++) - { - if (gTurnOrder[i] == gBankTarget) - gUnknown_0202407A[i] = 11; - } - - gCurrentMove = MOVE_PURSUIT; - gCurrMovePos = gUnknown_020241E9 = *(gBattleStruct->chosenMovesIds + gBankTarget); - gBattlescriptCurrInstr += 5; - gBattleScripting.animTurn = 1; - gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); - } - else - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } -} - -static void atkBB_setsunny(void) -{ - if (gBattleWeather & WEATHER_SUN_ANY) - { - gBattleMoveFlags |= MOVESTATUS_MISSED; - gBattleCommunication[MULTISTRING_CHOOSER] = 2; - } - else - { - gBattleWeather = WEATHER_SUN_TEMPORARY; - gBattleCommunication[MULTISTRING_CHOOSER] = 4; - gWishFutureKnock.weatherDuration = 5; - } - - gBattlescriptCurrInstr++; -} - -static void atkBC_maxattackhalvehp(void) // belly drum -{ - u32 halfHp = gBattleMons[gBankAttacker].maxHP / 2; - - if (!(gBattleMons[gBankAttacker].maxHP / 2)) - halfHp = 1; - - if (gBattleMons[gBankAttacker].statStages[STAT_STAGE_ATK] < 12 - && gBattleMons[gBankAttacker].hp > halfHp) - { - gBattleMons[gBankAttacker].statStages[STAT_STAGE_ATK] = 12; - gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 2; - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - - gBattlescriptCurrInstr += 5; - } - else - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } -} - -static void atkBD_copyfoestats(void) // psych up -{ - s32 i; - - for (i = 0; i < BATTLE_STATS_NO; i++) - { - gBattleMons[gBankAttacker].statStages[i] = gBattleMons[gBankTarget].statStages[i]; - } - - gBattlescriptCurrInstr += 5; // Has an unused jump ptr(possibly for a failed attempt) parameter. -} - -static void atkBE_rapidspinfree(void) -{ - if (gBattleMons[gBankAttacker].status2 & STATUS2_WRAPPED) - { - gBattleScripting.bank = gBankTarget; - gBattleMons[gBankAttacker].status2 &= ~(STATUS2_WRAPPED); - gBankTarget = *(gBattleStruct->wrappedBy + gBankAttacker); - - gBattleTextBuff1[0] = B_BUFF_PLACEHOLDER_BEGIN; - gBattleTextBuff1[1] = B_BUFF_MOVE; - gBattleTextBuff1[2] = *(gBattleStruct->wrappedMove + gBankAttacker * 2 + 0); - gBattleTextBuff1[3] = *(gBattleStruct->wrappedMove + gBankAttacker * 2 + 1); - gBattleTextBuff1[4] = B_BUFF_EOS; - - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_WrapFree; - } - else if (gStatuses3[gBankAttacker] & STATUS3_LEECHSEED) - { - gStatuses3[gBankAttacker] &= ~(STATUS3_LEECHSEED); - gStatuses3[gBankAttacker] &= ~(STATUS3_LEECHSEED_BANK); - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_LeechSeedFree; - } - else if (gSideAffecting[GetBankSide(gBankAttacker)] & SIDE_STATUS_SPIKES) - { - gSideAffecting[GetBankSide(gBankAttacker)] &= ~(SIDE_STATUS_SPIKES); - gSideTimers[GetBankSide(gBankAttacker)].spikesAmount = 0; - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_SpikesFree; - } - else - { - gBattlescriptCurrInstr++; - } -} - -static void atkBF_set_defense_curl(void) -{ - gBattleMons[gBankAttacker].status2 |= STATUS2_DEFENSE_CURL; - gBattlescriptCurrInstr++; -} - -static void atkC0_recoverbasedonsunlight(void) -{ - gBankTarget = gBankAttacker; - - if (gBattleMons[gBankAttacker].hp != gBattleMons[gBankAttacker].maxHP) - { - if (gBattleWeather == 0 || !WEATHER_HAS_EFFECT) - gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 2; - else if (gBattleWeather & WEATHER_SUN_ANY) - gBattleMoveDamage = 20 * gBattleMons[gBankAttacker].maxHP / 30; - else // not sunny weather - gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 4; - - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - gBattleMoveDamage *= -1; - - gBattlescriptCurrInstr += 5; - } - else - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } -} - -#ifdef NONMATCHING -static void atkC1_hidden_power(void) -{ - s32 powerBits; - s32 typeBits; - - powerBits = ((gBattleMons[gBankAttacker].hpIV & 2) >> 1) - | ((gBattleMons[gBankAttacker].attackIV & 2) << 0) - | ((gBattleMons[gBankAttacker].defenseIV & 2) << 1) - | ((gBattleMons[gBankAttacker].speedIV & 2) << 2) - | ((gBattleMons[gBankAttacker].spAttackIV & 2) << 3) - | ((gBattleMons[gBankAttacker].spDefenseIV & 2) << 4); - - typeBits = ((gBattleMons[gBankAttacker].hpIV & 1) << 0) - | ((gBattleMons[gBankAttacker].attackIV & 1) << 1) - | ((gBattleMons[gBankAttacker].defenseIV & 1) << 2) - | ((gBattleMons[gBankAttacker].speedIV & 1) << 3) - | ((gBattleMons[gBankAttacker].spAttackIV & 1) << 4) - | ((gBattleMons[gBankAttacker].spDefenseIV & 1) << 5); - - gDynamicBasePower = (40 * powerBits) / 63 + 30; - - gBattleStruct->dynamicMoveType = (15 * typeBits) / 63 + 1; - if (gBattleStruct->dynamicMoveType > 8) - gBattleStruct->dynamicMoveType++; - gBattleStruct->dynamicMoveType |= 0xC0; - - gBattlescriptCurrInstr++; -} - -#else -__attribute__((naked)) -static void atkC1_hidden_power(void) -{ - asm(".syntax unified\n\ - push {r4-r7,lr}\n\ - mov r7, r10\n\ - mov r6, r9\n\ - mov r5, r8\n\ - push {r5-r7}\n\ - ldr r2, =gBattleMons\n\ - ldr r0, =gBankAttacker\n\ - ldrb r1, [r0]\n\ - movs r0, 0x58\n\ - adds r4, r1, 0\n\ - muls r4, r0\n\ - adds r4, r2\n\ - ldrb r0, [r4, 0x14]\n\ - mov r10, r0\n\ - mov r7, r10\n\ - lsls r7, 27\n\ - adds r0, r7, 0\n\ - lsrs r0, 27\n\ - mov r10, r0\n\ - movs r1, 0x2\n\ - mov r2, r10\n\ - ands r2, r1\n\ - asrs r2, 1\n\ - ldrh r7, [r4, 0x14]\n\ - mov r9, r7\n\ - mov r0, r9\n\ - lsls r0, 22\n\ - mov r9, r0\n\ - lsrs r3, r0, 27\n\ - adds r0, r1, 0\n\ - ands r0, r3\n\ - orrs r2, r0\n\ - ldrb r7, [r4, 0x15]\n\ - mov r8, r7\n\ - mov r0, r8\n\ - lsls r0, 25\n\ - mov r8, r0\n\ - lsrs r3, r0, 27\n\ - adds r0, r1, 0\n\ - ands r0, r3\n\ - lsls r0, 1\n\ - orrs r2, r0\n\ - ldr r6, [r4, 0x14]\n\ - lsls r6, 12\n\ - lsrs r3, r6, 27\n\ - adds r0, r1, 0\n\ - ands r0, r3\n\ - lsls r0, 2\n\ - orrs r2, r0\n\ - ldrh r5, [r4, 0x16]\n\ - lsls r5, 23\n\ - lsrs r3, r5, 27\n\ - adds r0, r1, 0\n\ - ands r0, r3\n\ - lsls r0, 3\n\ - orrs r2, r0\n\ - ldrb r3, [r4, 0x17]\n\ - lsls r3, 26\n\ - lsrs r0, r3, 27\n\ - ands r1, r0\n\ - lsls r1, 4\n\ - orrs r2, r1\n\ - movs r1, 0x1\n\ - adds r4, r1, 0\n\ - mov r7, r10\n\ - ands r4, r7\n\ - mov r0, r9\n\ - lsrs r0, 27\n\ - mov r9, r0\n\ - adds r0, r1, 0\n\ - mov r7, r9\n\ - ands r0, r7\n\ - lsls r0, 1\n\ - orrs r4, r0\n\ - mov r0, r8\n\ - lsrs r0, 27\n\ - mov r8, r0\n\ - adds r0, r1, 0\n\ - mov r7, r8\n\ - ands r0, r7\n\ - lsls r0, 2\n\ - orrs r4, r0\n\ - lsrs r6, 27\n\ - adds r0, r1, 0\n\ - ands r0, r6\n\ - lsls r0, 3\n\ - orrs r4, r0\n\ - lsrs r5, 27\n\ - adds r0, r1, 0\n\ - ands r0, r5\n\ - lsls r0, 4\n\ - orrs r4, r0\n\ - lsrs r3, 27\n\ - ands r1, r3\n\ - lsls r1, 5\n\ - orrs r4, r1\n\ - ldr r5, =gDynamicBasePower\n\ - lsls r0, r2, 2\n\ - adds r0, r2\n\ - lsls r0, 3\n\ - movs r1, 0x3F\n\ - bl __divsi3\n\ - adds r0, 0x1E\n\ - strh r0, [r5]\n\ - ldr r6, =gBattleStruct\n\ - ldr r5, [r6]\n\ - lsls r0, r4, 4\n\ - subs r0, r4\n\ - movs r1, 0x3F\n\ - bl __divsi3\n\ - adds r0, 0x1\n\ - strb r0, [r5, 0x13]\n\ - ldr r1, [r6]\n\ - ldrb r0, [r1, 0x13]\n\ - cmp r0, 0x8\n\ - bls _080544F0\n\ - adds r0, 0x1\n\ - strb r0, [r1, 0x13]\n\ -_080544F0:\n\ - ldr r2, [r6]\n\ - ldrb r0, [r2, 0x13]\n\ - movs r1, 0xC0\n\ - orrs r0, r1\n\ - strb r0, [r2, 0x13]\n\ - ldr r1, =gBattlescriptCurrInstr\n\ - ldr r0, [r1]\n\ - adds r0, 0x1\n\ - str r0, [r1]\n\ - pop {r3-r5}\n\ - mov r8, r3\n\ - mov r9, r4\n\ - mov r10, r5\n\ - pop {r4-r7}\n\ - pop {r0}\n\ - bx r0\n\ - .pool\n\ - .syntax divided"); -} -#endif // NONMATCHING - -static void atkC2_selectnexttarget(void) -{ - for (gBankTarget = 0; gBankTarget < gNoOfAllBanks; gBankTarget++) - { - if (gBankTarget == gBankAttacker) - continue; - if (!(gAbsentBankFlags & gBitTable[gBankTarget])) - break; - } - gBattlescriptCurrInstr++; -} - -static void atkC3_setfutureattack(void) -{ - if (gWishFutureKnock.futureSightCounter[gBankTarget] != 0) - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - else - { - gSideAffecting[GET_BANK_SIDE(gBankTarget)] |= SIDE_STATUS_FUTUREATTACK; - gWishFutureKnock.futureSightMove[gBankTarget] = gCurrentMove; - gWishFutureKnock.futureSightAttacker[gBankTarget] = gBankAttacker; - gWishFutureKnock.futureSightCounter[gBankTarget] = 3; - gWishFutureKnock.futureSightDmg[gBankTarget] = CalculateBaseDamage(&gBattleMons[gBankAttacker], &gBattleMons[gBankTarget], gCurrentMove, - gSideAffecting[GET_BANK_SIDE(gBankTarget)], 0, - 0, gBankAttacker, gBankTarget); - - if (gProtectStructs[gBankAttacker].helpingHand) - gWishFutureKnock.futureSightDmg[gBankTarget] = gWishFutureKnock.futureSightDmg[gBankTarget] * 15 / 10; - - if (gCurrentMove == MOVE_DOOM_DESIRE) - gBattleCommunication[MULTISTRING_CHOOSER] = 1; - else - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - - gBattlescriptCurrInstr += 5; - } -} - -static void atkC4_beat_up(void) -{ - struct Pokemon* party; - - if (GetBankSide(gBankAttacker) == SIDE_PLAYER) - party = gPlayerParty; - else - party = gEnemyParty; - - if (gBattleMons[gBankTarget].hp == 0) - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - else - { - u8 beforeLoop = gBattleCommunication[0]; - for (;gBattleCommunication[0] < 6; gBattleCommunication[0]++) - { - if (GetMonData(&party[gBattleCommunication[0]], MON_DATA_HP) - && GetMonData(&party[gBattleCommunication[0]], MON_DATA_SPECIES2) - && GetMonData(&party[gBattleCommunication[0]], MON_DATA_SPECIES2) != SPECIES_EGG - && !GetMonData(&party[gBattleCommunication[0]], MON_DATA_STATUS)) - break; - } - if (gBattleCommunication[0] < 6) - { - PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBankAttacker, gBattleCommunication[0]) - - gBattlescriptCurrInstr += 9; - - gBattleMoveDamage = gBaseStats[GetMonData(&party[gBattleCommunication[0]], MON_DATA_SPECIES)].baseAttack; - gBattleMoveDamage *= gBattleMoves[gCurrentMove].power; - gBattleMoveDamage *= (GetMonData(&party[gBattleCommunication[0]], MON_DATA_LEVEL) * 2 / 5 + 2); - gBattleMoveDamage /= gBaseStats[gBattleMons[gBankTarget].species].baseDefense; - gBattleMoveDamage = (gBattleMoveDamage / 50) + 2; - if (gProtectStructs[gBankAttacker].helpingHand) - gBattleMoveDamage = gBattleMoveDamage * 15 / 10; - - gBattleCommunication[0]++; - } - else if (beforeLoop != 0) - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - else - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 5); - } -} - -static void atkC5_setsemiinvulnerablebit(void) -{ - switch (gCurrentMove) - { - case MOVE_FLY: - case MOVE_BOUNCE: - gStatuses3[gBankAttacker] |= STATUS3_ON_AIR; - break; - case MOVE_DIG: - gStatuses3[gBankAttacker] |= STATUS3_UNDERGROUND; - break; - case MOVE_DIVE: - gStatuses3[gBankAttacker] |= STATUS3_UNDERWATER; - break; - } - - gBattlescriptCurrInstr++; -} - -static void atkC6_clearsemiinvulnerablebit(void) -{ - switch (gCurrentMove) - { - case MOVE_FLY: - case MOVE_BOUNCE: - gStatuses3[gBankAttacker] &= ~STATUS3_ON_AIR; - break; - case MOVE_DIG: - gStatuses3[gBankAttacker] &= ~STATUS3_UNDERGROUND; - break; - case MOVE_DIVE: - gStatuses3[gBankAttacker] &= ~STATUS3_UNDERWATER; - break; - } - - gBattlescriptCurrInstr++; -} - -static void atkC7_setminimize(void) -{ - if (gHitMarker & HITMARKER_OBEYS) - gStatuses3[gBankAttacker] |= STATUS3_MINIMIZED; - - gBattlescriptCurrInstr++; -} - -static void atkC8_sethail(void) -{ - if (gBattleWeather & WEATHER_HAIL_ANY) - { - gBattleMoveFlags |= MOVESTATUS_MISSED; - gBattleCommunication[MULTISTRING_CHOOSER] = 2; - } - else - { - gBattleWeather = WEATHER_HAIL; - gBattleCommunication[MULTISTRING_CHOOSER] = 5; - gWishFutureKnock.weatherDuration = 5; - } - - gBattlescriptCurrInstr++; -} - -static void atkC9_jumpifattackandspecialattackcannotfall(void) // memento -{ - if (gBattleMons[gBankTarget].statStages[STAT_STAGE_ATK] == 0 - && gBattleMons[gBankTarget].statStages[STAT_STAGE_SPATK] == 0 - && gBattleCommunication[6] != 1) - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - else - { - gActiveBank = gBankAttacker; - gBattleMoveDamage = gBattleMons[gActiveBank].hp; - EmitHealthBarUpdate(0, 0x7FFF); - MarkBufferBankForExecution(gActiveBank); - gBattlescriptCurrInstr += 5; - } -} - -static void atkCA_setforcedtarget(void) // follow me -{ - gSideTimers[GetBankSide(gBankAttacker)].followmeTimer = 1; - gSideTimers[GetBankSide(gBankAttacker)].followmeTarget = gBankAttacker; - gBattlescriptCurrInstr++; -} - -static void atkCB_setcharge(void) -{ - gStatuses3[gBankAttacker] |= STATUS3_CHARGED_UP; - gDisableStructs[gBankAttacker].chargeTimer1 = 2; - gDisableStructs[gBankAttacker].chargeTimer2 = 2; - gBattlescriptCurrInstr++; -} - -static void atkCC_callterrainattack(void) // nature power -{ - gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); - gCurrentMove = sNaturePowerMoves[gBattleTerrain]; - gBankTarget = GetMoveTarget(gCurrentMove, 0); - BattleScriptPush(gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]); - gBattlescriptCurrInstr++; -} - -static void atkCD_cureifburnedparalysedorpoisoned(void) // refresh -{ - if (gBattleMons[gBankAttacker].status1 & (STATUS_POISON | STATUS_BURN | STATUS_PARALYSIS | STATUS_TOXIC_POISON)) - { - gBattleMons[gBankAttacker].status1 = 0; - gBattlescriptCurrInstr += 5; - gActiveBank = gBankAttacker; - EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); - MarkBufferBankForExecution(gActiveBank); - } - else - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } -} - -static void atkCE_settorment(void) -{ - if (gBattleMons[gBankTarget].status2 & STATUS2_TORMENT) - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - else - { - gBattleMons[gBankTarget].status2 |= STATUS2_TORMENT; - gBattlescriptCurrInstr += 5; - } -} - -static void atkCF_jumpifnodamage(void) -{ - if (gProtectStructs[gBankAttacker].physicalDmg || gProtectStructs[gBankAttacker].specialDmg) - gBattlescriptCurrInstr += 5; - else - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); -} - -static void atkD0_settaunt(void) -{ - if (gDisableStructs[gBankTarget].tauntTimer1 == 0) - { - gDisableStructs[gBankTarget].tauntTimer1 = 2; - gDisableStructs[gBankTarget].tauntTimer2 = 2; - gBattlescriptCurrInstr += 5; - } - else - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } -} - -static void atkD1_set_helpinghand(void) -{ - gBankTarget = GetBankByIdentity(GetBankIdentity(gBankAttacker) ^ BIT_MON); - - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE - && !(gAbsentBankFlags & gBitTable[gBankTarget]) - && !gProtectStructs[gBankAttacker].helpingHand - && !gProtectStructs[gBankTarget].helpingHand) - { - gProtectStructs[gBankTarget].helpingHand = 1; - gBattlescriptCurrInstr += 5; - } - else - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } -} - -static void atkD2_swap_items(void) // trick -{ - // opponent can't swap items with player in regular battles - if (gBattleTypeFlags & BATTLE_TYPE_x4000000 - || (GetBankSide(gBankAttacker) == SIDE_OPPONENT - && !(gBattleTypeFlags & (BATTLE_TYPE_LINK - | BATTLE_TYPE_EREADER_TRAINER - | BATTLE_TYPE_FRONTIER - | BATTLE_TYPE_SECRET_BASE - | BATTLE_TYPE_x2000000)))) - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - else - { - u8 sideAttacker = GetBankSide(gBankAttacker); - u8 sideTarget = GetBankSide(gBankTarget); - - // you can't swap items if they were knocked off in regular battles - if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK - | BATTLE_TYPE_EREADER_TRAINER - | BATTLE_TYPE_FRONTIER - | BATTLE_TYPE_SECRET_BASE - | BATTLE_TYPE_x2000000)) - && (gWishFutureKnock.knockedOffPokes[sideAttacker] & gBitTable[gBattlePartyID[gBankAttacker]] - || gWishFutureKnock.knockedOffPokes[sideTarget] & gBitTable[gBattlePartyID[gBankTarget]])) - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - // can't swap if two pokemon don't have an item - // or if either of them is an enigma berry or a mail - else if ((gBattleMons[gBankAttacker].item == 0 && gBattleMons[gBankTarget].item == 0) - || gBattleMons[gBankAttacker].item == ITEM_ENIGMA_BERRY - || gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY - || IS_ITEM_MAIL(gBattleMons[gBankAttacker].item) - || IS_ITEM_MAIL(gBattleMons[gBankTarget].item)) - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - // check if ability prevents swapping - else if (gBattleMons[gBankTarget].ability == ABILITY_STICKY_HOLD) - { - gBattlescriptCurrInstr = BattleScript_StickyHoldActivates; - gLastUsedAbility = gBattleMons[gBankTarget].ability; - RecordAbilityBattle(gBankTarget, gLastUsedAbility); - } - // took a while, but all checks passed and items can be safely swapped - else - { - u16 oldItemAtk, *newItemAtk; - - newItemAtk = &gBattleStruct->changedItems[gBankAttacker]; - oldItemAtk = gBattleMons[gBankAttacker].item; - *newItemAtk = gBattleMons[gBankTarget].item; - - gBattleMons[gBankAttacker].item = 0; - gBattleMons[gBankTarget].item = oldItemAtk; - - gActiveBank = gBankAttacker; - EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, newItemAtk); - MarkBufferBankForExecution(gBankAttacker); - - gActiveBank = gBankTarget; - EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gBankTarget].item); - MarkBufferBankForExecution(gBankTarget); - - *(u8*)((u8*)(&gBattleStruct->choicedMove[gBankTarget]) + 0) = 0; - *(u8*)((u8*)(&gBattleStruct->choicedMove[gBankTarget]) + 1) = 0; - - *(u8*)((u8*)(&gBattleStruct->choicedMove[gBankAttacker]) + 0) = 0; - *(u8*)((u8*)(&gBattleStruct->choicedMove[gBankAttacker]) + 1) = 0; - - gBattlescriptCurrInstr += 5; - - PREPARE_ITEM_BUFFER(gBattleTextBuff1, *newItemAtk) - PREPARE_ITEM_BUFFER(gBattleTextBuff2, oldItemAtk) - - if (oldItemAtk != 0 && *newItemAtk != 0) - gBattleCommunication[MULTISTRING_CHOOSER] = 2; // attacker's item -> <- target's item - else if (oldItemAtk == 0 && *newItemAtk != 0) - gBattleCommunication[MULTISTRING_CHOOSER] = 0; // nothing -> <- target's item - else - gBattleCommunication[MULTISTRING_CHOOSER] = 1; // attacker's item -> <- nothing - } - } -} - -static void atkD3_copy_ability(void) // role play -{ - if (gBattleMons[gBankTarget].ability != 0 - && gBattleMons[gBankTarget].ability != ABILITY_WONDER_GUARD) - { - gBattleMons[gBankAttacker].ability = gBattleMons[gBankTarget].ability; - gLastUsedAbility = gBattleMons[gBankTarget].ability; - gBattlescriptCurrInstr += 5; - } - else - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } -} - -static void atkD4_wish_effect(void) -{ - switch (gBattlescriptCurrInstr[1]) - { - case 0: // use wish - if (gWishFutureKnock.wishCounter[gBankAttacker] == 0) - { - gWishFutureKnock.wishCounter[gBankAttacker] = 2; - gWishFutureKnock.wishUserID[gBankAttacker] = gBattlePartyID[gBankAttacker]; - gBattlescriptCurrInstr += 6; - } - else - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); - } - break; - case 1: // heal effect - PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBankTarget, gWishFutureKnock.wishUserID[gBankTarget]) - - gBattleMoveDamage = gBattleMons[gBankTarget].maxHP / 2; - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - gBattleMoveDamage *= -1; - - if (gBattleMons[gBankTarget].hp == gBattleMons[gBankTarget].maxHP) - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); - else - gBattlescriptCurrInstr += 6; - - break; - } -} - -static void atkD5_setroots(void) // ingrain -{ - if (gStatuses3[gBankAttacker] & STATUS3_ROOTED) - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - else - { - gStatuses3[gBankAttacker] |= STATUS3_ROOTED; - gBattlescriptCurrInstr += 5; - } -} - -static void atkD6_doubledamagedealtifdamaged(void) -{ - if ((gProtectStructs[gBankAttacker].physicalDmg - && gProtectStructs[gBankAttacker].physicalBank == gBankTarget) - || (gProtectStructs[gBankAttacker].specialDmg - && gProtectStructs[gBankAttacker].specialBank == gBankTarget)) - { - gBattleScripting.dmgMultiplier = 2; - } - - gBattlescriptCurrInstr++; -} - -static void atkD7_setyawn(void) -{ - if (gStatuses3[gBankTarget] & STATUS3_YAWN - || gBattleMons[gBankTarget].status1 & STATUS_ANY) - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - else - { - gStatuses3[gBankTarget] |= 0x1000; - gBattlescriptCurrInstr += 5; - } -} - -static void atkD8_setdamagetohealthdifference(void) -{ - if (gBattleMons[gBankTarget].hp <= gBattleMons[gBankAttacker].hp) - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - else - { - gBattleMoveDamage = gBattleMons[gBankTarget].hp - gBattleMons[gBankAttacker].hp; - gBattlescriptCurrInstr += 5; - } -} - -static void atkD9_scaledamagebyhealthratio(void) -{ - if (gDynamicBasePower == 0) - { - u8 power = gBattleMoves[gCurrentMove].power; - gDynamicBasePower = gBattleMons[gBankAttacker].hp * power / gBattleMons[gBankAttacker].maxHP; - if (gDynamicBasePower == 0) - gDynamicBasePower = 1; - } - gBattlescriptCurrInstr++; -} - -static void atkDA_abilityswap(void) // skill swap -{ - if ((gBattleMons[gBankAttacker].ability == 0 - && gBattleMons[gBankTarget].ability == 0) - || gBattleMons[gBankAttacker].ability == ABILITY_WONDER_GUARD - || gBattleMons[gBankTarget].ability == ABILITY_WONDER_GUARD - || gBattleMoveFlags & MOVESTATUS_NOEFFECT) - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - else - { - u8 abilityAtk = gBattleMons[gBankAttacker].ability; - gBattleMons[gBankAttacker].ability = gBattleMons[gBankTarget].ability; - gBattleMons[gBankTarget].ability = abilityAtk; - - gBattlescriptCurrInstr += 5; - } -} - -static void atkDB_imprisoneffect(void) -{ - if ((gStatuses3[gBankAttacker] & STATUS3_IMPRISONED_OTHERS)) - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - else - { - u8 bank, sideAttacker; - - sideAttacker = GetBankSide(gBankAttacker); - PressurePPLoseOnUsingImprision(gBankAttacker); - for (bank = 0; bank < gNoOfAllBanks; bank++) - { - if (sideAttacker != GetBankSide(bank)) - { - s32 attackerMoveId; - for (attackerMoveId = 0; attackerMoveId < 4; attackerMoveId++) - { - s32 i; - for (i = 0; i < 4; i++) - { - if (gBattleMons[gBankAttacker].moves[attackerMoveId] == gBattleMons[bank].moves[i] - && gBattleMons[gBankAttacker].moves[attackerMoveId] != MOVE_NONE) - break; - } - if (i != 4) - break; - } - if (attackerMoveId != 4) - { - gStatuses3[gBankAttacker] |= STATUS3_IMPRISONED_OTHERS; - gBattlescriptCurrInstr += 5; - break; - } - } - } - if (bank == gNoOfAllBanks) // In Generation 3 games, Imprison fails if the user doesn't share any moves with any of the foes - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } -} - -static void atkDC_setgrudge(void) -{ - if (gStatuses3[gBankAttacker] & STATUS3_GRUDGE) - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - else - { - gStatuses3[gBankAttacker] |= STATUS3_GRUDGE; - gBattlescriptCurrInstr += 5; - } -} - -static void atkDD_weightdamagecalculation(void) -{ - s32 i; - for (i = 0; sWeightToDamageTable[i] != 0xFFFF; i += 2) - { - if (sWeightToDamageTable[i] > GetPokedexHeightWeight(SpeciesToNationalPokedexNum(gBattleMons[gBankTarget].species), 1)) - break; - } - - if (sWeightToDamageTable[i] != 0xFFFF) - gDynamicBasePower = sWeightToDamageTable[i + 1]; - else - gDynamicBasePower = 120; - - gBattlescriptCurrInstr++; -} - -static void atkDE_asistattackselect(void) -{ - s32 chooseableMovesNo = 0; - struct Pokemon* party; - s32 monId, moveId; - u16* movesArray = gBattleStruct->assistPossibleMoves; - - if (GET_BANK_SIDE(gBankAttacker) != SIDE_PLAYER) - party = gEnemyParty; - else - party = gPlayerParty; - - for (monId = 0; monId < 6; monId++) - { - if (monId == gBattlePartyID[gBankAttacker]) - continue; - if (GetMonData(&party[monId], MON_DATA_SPECIES2) == SPECIES_NONE) - continue; - if (GetMonData(&party[monId], MON_DATA_SPECIES2) == SPECIES_EGG) - continue; - - for (moveId = 0; moveId < 4; moveId++) - { - s32 i = 0; - u16 move = GetMonData(&party[monId], MON_DATA_MOVE1 + moveId); - - if (IsInvalidForSleepTalkOrAssist(move)) - continue; - - for (; sMovesForbiddenToCopy[i] != ASSIST_FORBIDDEN_END && move != sMovesForbiddenToCopy[i]; i++); - - if (sMovesForbiddenToCopy[i] != ASSIST_FORBIDDEN_END) - continue; - if (move == MOVE_NONE) - continue; - - movesArray[chooseableMovesNo] = move; - chooseableMovesNo++; - } - } - if (chooseableMovesNo) - { - gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); - gRandomMove = movesArray[((Random() & 0xFF) * chooseableMovesNo) >> 8]; - gBankTarget = GetMoveTarget(gRandomMove, 0); - gBattlescriptCurrInstr += 5; - } - else - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } -} - -static void atkDF_setmagiccoat(void) -{ - gBankTarget = gBankAttacker; - gSpecialStatuses[gBankAttacker].flag20 = 1; - if (gCurrentMoveTurn == gNoOfAllBanks - 1) // moves last turn - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - else - { - gProtectStructs[gBankAttacker].bounceMove = 1; - gBattlescriptCurrInstr += 5; - } -} - -static void atkE0_setstealstatchange(void) // snatch -{ - gSpecialStatuses[gBankAttacker].flag20 = 1; - if (gCurrentMoveTurn == gNoOfAllBanks - 1) // moves last turn - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - else - { - gProtectStructs[gBankAttacker].stealMove = 1; - gBattlescriptCurrInstr += 5; - } -} - -static void atkE1_intimidate_string_loader(void) -{ - u8 side; - - gBattleScripting.bank = gBattleStruct->intimidateBank; - side = GetBankSide(gBattleScripting.bank); - - PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gBattleMons[gBattleScripting.bank].ability) - - for (;gBankTarget < gNoOfAllBanks; gBankTarget++) - { - if (GetBankSide(gBankTarget) == side) - continue; - if (!(gAbsentBankFlags & gBitTable[gBankTarget])) - break; - } - - if (gBankTarget >= gNoOfAllBanks) - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - else - gBattlescriptCurrInstr += 5; -} - -static void atkE2_switchout_abilities(void) -{ - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - - switch (gBattleMons[gActiveBank].ability) - { - case ABILITY_NATURAL_CURE: - gBattleMons[gActiveBank].status1 = 0; - EmitSetMonData(0, REQUEST_STATUS_BATTLE, gBitTable[*(gBattleStruct->field_58 + gActiveBank)], 4, &gBattleMons[gActiveBank].status1); - MarkBufferBankForExecution(gActiveBank); - break; - } - - gBattlescriptCurrInstr += 2; -} - -static void atkE3_jumpifhasnohp(void) -{ - gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); - - if (gBattleMons[gActiveBank].hp == 0) - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); - else - gBattlescriptCurrInstr += 6; -} - -static void atkE4_getsecretpowereffect(void) -{ - switch (gBattleTerrain) - { - case BATTLE_TERRAIN_GRASS: - gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_POISON; - break; - case BATTLE_TERRAIN_LONG_GRASS: - gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_SLEEP; - break; - case BATTLE_TERRAIN_SAND: - gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_ACC_MINUS_1; - break; - case BATTLE_TERRAIN_UNDERWATER: - gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_DEF_MINUS_1; - break; - case BATTLE_TERRAIN_WATER: - gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_ATK_MINUS_1; - break; - case BATTLE_TERRAIN_POND: - gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_SPD_MINUS_1; - break; - case BATTLE_TERRAIN_ROCK: - gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_CONFUSION; - break; - case BATTLE_TERRAIN_CAVE: - gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_FLINCH; - break; - default: - gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_PARALYSIS; - break; - } - gBattlescriptCurrInstr++; -} - -static void atkE5_pickup(void) -{ - if (!InBattlePike()) - { - s32 i; - u16 species, heldItem; - u8 ability; - - if (InBattlePyramid()) - { - for (i = 0; i < 6; i++) - { - species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2); - heldItem = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM); - - if (GetMonData(&gPlayerParty[i], MON_DATA_ALT_ABILITY)) - ability = gBaseStats[species].ability2; - else - ability = gBaseStats[species].ability1; - - if (ability == ABILITY_PICKUP - && species != 0 - && species != SPECIES_EGG - && heldItem == ITEM_NONE - && (Random() % 10) == 0) - { - heldItem = GetBattlePyramidPickupItemId(); - SetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM, &heldItem); - } - } - } - else - { - for (i = 0; i < 6; i++) - { - species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2); - heldItem = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM); - - if (GetMonData(&gPlayerParty[i], MON_DATA_ALT_ABILITY)) - ability = gBaseStats[species].ability2; - else - ability = gBaseStats[species].ability1; - - if (ability == ABILITY_PICKUP - && species != 0 - && species != SPECIES_EGG - && heldItem == ITEM_NONE - && (Random() % 10) == 0) - { - s32 j; - s32 rand = Random() % 100; - u8 lvlDivBy10 = (GetMonData(&gPlayerParty[i], MON_DATA_LEVEL) - 1) / 10; - if (lvlDivBy10 > 9) - lvlDivBy10 = 9; - - for (j = 0; j < 9; j++) - { - if (sPickupProbabilities[j] > rand) - { - SetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM, &sPickupItems[lvlDivBy10 + j]); - break; - } - else if (rand == 99 || rand == 98) - { - SetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM, &sRarePickupItems[lvlDivBy10 + (99 - rand)]); - break; - } - } - } - } - } - } - - gBattlescriptCurrInstr++; -} - -static void atkE6_castform_change_animation(void) -{ - gActiveBank = gBattleScripting.bank; - - if (gBattleMons[gActiveBank].status2 & STATUS2_SUBSTITUTE) - *(&gBattleStruct->formToChangeInto) |= 0x80; - - EmitBattleAnimation(0, B_ANIM_CASTFORM_CHANGE, gBattleStruct->formToChangeInto); - MarkBufferBankForExecution(gActiveBank); - - gBattlescriptCurrInstr++; -} - -static void atkE7_castform_data_change(void) -{ - u8 form; - - gBattlescriptCurrInstr++; - form = CastformDataTypeChange(gBattleScripting.bank); - if (form) - { - BattleScriptPushCursorAndCallback(BattleScript_CastformChange); - *(&gBattleStruct->formToChangeInto) = form - 1; - } -} - -static void atkE8_settypebasedhalvers(void) // water and mud sport -{ - bool8 worked = FALSE; - - if (gBattleMoves[gCurrentMove].effect == EFFECT_MUD_SPORT) - { - if (!(gStatuses3[gBankAttacker] & STATUS3_MUDSPORT)) - { - gStatuses3[gBankAttacker] |= STATUS3_MUDSPORT; - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - worked = TRUE; - } - } - else // water sport - { - if (!(gStatuses3[gBankAttacker] & STATUS3_WATERSPORT)) - { - gStatuses3[gBankAttacker] |= STATUS3_WATERSPORT; - gBattleCommunication[MULTISTRING_CHOOSER] = 1; - worked = TRUE; - } - } - - if (worked) - gBattlescriptCurrInstr += 5; - else - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); -} - -static void atkE9_setweatherballtype(void) -{ - if (WEATHER_HAS_EFFECT) - { - if (gBattleWeather & WEATHER_ANY) - gBattleScripting.dmgMultiplier = 2; - if (gBattleWeather & WEATHER_RAIN_ANY) - *(&gBattleStruct->dynamicMoveType) = TYPE_WATER | 0x80; - else if (gBattleWeather & WEATHER_SANDSTORM_ANY) - *(&gBattleStruct->dynamicMoveType) = TYPE_ROCK | 0x80; - else if (gBattleWeather & WEATHER_SUN_ANY) - *(&gBattleStruct->dynamicMoveType) = TYPE_FIRE | 0x80; - else if (gBattleWeather & WEATHER_HAIL_ANY) - *(&gBattleStruct->dynamicMoveType) = TYPE_ICE | 0x80; - else - *(&gBattleStruct->dynamicMoveType) = TYPE_NORMAL | 0x80; - } - - gBattlescriptCurrInstr++; -} - -static void atkEA_recycleitem(void) -{ - u16 *usedHeldItem; - - gActiveBank = gBankAttacker; - usedHeldItem = &gBattleStruct->usedHeldItems[gActiveBank]; - if (*usedHeldItem != 0 && gBattleMons[gActiveBank].item == 0) - { - gLastUsedItem = *usedHeldItem; - *usedHeldItem = 0; - gBattleMons[gActiveBank].item = gLastUsedItem; - - EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gActiveBank].item); - MarkBufferBankForExecution(gActiveBank); - - gBattlescriptCurrInstr += 5; - } - else - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } -} - -static void atkEB_settypetoterrain(void) -{ - if (gBattleMons[gBankAttacker].type1 != sTerrainToType[gBattleTerrain] - && gBattleMons[gBankAttacker].type2 != sTerrainToType[gBattleTerrain]) - { - gBattleMons[gBankAttacker].type1 = sTerrainToType[gBattleTerrain]; - gBattleMons[gBankAttacker].type2 = sTerrainToType[gBattleTerrain]; - - PREPARE_TYPE_BUFFER(gBattleTextBuff1, sTerrainToType[gBattleTerrain]) - - gBattlescriptCurrInstr += 5; - } - else - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } -} - -static void atkEC_pursuit_sth(void) -{ - gActiveBank = GetBankByIdentity(GetBankIdentity(gBankAttacker) ^ BIT_MON); - - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE - && !(gAbsentBankFlags & gBitTable[gActiveBank]) - && gActionForBanks[gActiveBank] == 0 - && gChosenMovesByBanks[gActiveBank] == MOVE_PURSUIT) - { - gUnknown_0202407A[gActiveBank] = 11; - gCurrentMove = MOVE_PURSUIT; - gBattlescriptCurrInstr += 5; - gBattleScripting.animTurn = 1; - gBattleScripting.field_20 = gBankAttacker; - gBankAttacker = gActiveBank; - } - else - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } -} - -static void atkED_802B4B4(void) -{ - gEffectBank = gBankAttacker; - - if (gBankAttacker == gBankTarget) - gBankAttacker = gBankTarget = gBattleScripting.bank; - else - gBankTarget = gBattleScripting.bank; - - gBattleScripting.bank = gEffectBank; - gBattlescriptCurrInstr++; -} - -static void atkEE_removelightscreenreflect(void) // brick break -{ - u8 opposingSide = GetBankSide(gBankAttacker) ^ BIT_SIDE; - - if (gSideTimers[opposingSide].reflectTimer || gSideTimers[opposingSide].lightscreenTimer) - { - gSideAffecting[opposingSide] &= ~(SIDE_STATUS_REFLECT); - gSideAffecting[opposingSide] &= ~(SIDE_STATUS_LIGHTSCREEN); - gSideTimers[opposingSide].reflectTimer = 0; - gSideTimers[opposingSide].lightscreenTimer = 0; - gBattleScripting.animTurn = 1; - gBattleScripting.animTargetsHit = 1; - } - else - { - gBattleScripting.animTurn = 0; - gBattleScripting.animTargetsHit = 0; - } - - gBattlescriptCurrInstr++; -} - -static void atkEF_pokeball_catch_calculation(void) -{ - u8 ballMultiplier = 0; - - if (gBattleExecBuffer) - return; - - gActiveBank = gBankAttacker; - gBankTarget = gBankAttacker ^ BIT_SIDE; - - if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) - { - EmitBallThrow(0, BALL_TRAINER_BLOCK); - MarkBufferBankForExecution(gActiveBank); - gBattlescriptCurrInstr = BattleScript_TrainerBallBlock; - } - else if (gBattleTypeFlags & BATTLE_TYPE_WALLY_TUTORIAL) - { - EmitBallThrow(0, BALL_3_SHAKES_SUCCESS); - MarkBufferBankForExecution(gActiveBank); - gBattlescriptCurrInstr = BattleScript_WallyBallThrow; - } - else - { - u32 odds; - u8 catchRate; - - if (gLastUsedItem == ITEM_SAFARI_BALL) - catchRate = gBattleStruct->field_7C * 1275 / 100; - else - catchRate = gBaseStats[gBattleMons[gBankTarget].species].catchRate; - - if (gLastUsedItem > ITEM_SAFARI_BALL) - { - switch (gLastUsedItem) - { - case ITEM_NET_BALL: - if (gBattleMons[gBankTarget].type1 == TYPE_WATER - || gBattleMons[gBankTarget].type2 == TYPE_WATER - || gBattleMons[gBankTarget].type1 == TYPE_BUG - || gBattleMons[gBankTarget].type2 == TYPE_BUG) - ballMultiplier = 30; - else - ballMultiplier = 10; - break; - case ITEM_DIVE_BALL: - if (sav1_map_get_light_level() == 5) - ballMultiplier = 35; - else - ballMultiplier = 10; - break; - case ITEM_NEST_BALL: - if (gBattleMons[gBankTarget].level <= 39) - { - ballMultiplier = 40 - gBattleMons[gBankTarget].level; - if (ballMultiplier <= 9) - ballMultiplier = 10; - } - else - { - ballMultiplier = 10; - } - break; - case ITEM_REPEAT_BALL: - if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gBankTarget].species), FLAG_GET_CAUGHT)) - ballMultiplier = 30; - else - ballMultiplier = 10; - break; - case ITEM_TIMER_BALL: - ballMultiplier = gBattleResults.battleTurnCounter + 10; - if (ballMultiplier > 40) - ballMultiplier = 40; - break; - case ITEM_LUXURY_BALL: - case ITEM_PREMIER_BALL: - ballMultiplier = 10; - break; - } - } - else - ballMultiplier = sBallCatchBonuses[gLastUsedItem - 2]; - - odds = (catchRate * ballMultiplier / 10) - * (gBattleMons[gBankTarget].maxHP * 3 - gBattleMons[gBankTarget].hp * 2) - / (3 * gBattleMons[gBankTarget].maxHP); - - if (gBattleMons[gBankTarget].status1 & (STATUS_SLEEP | STATUS_FREEZE)) - odds *= 2; - if (gBattleMons[gBankTarget].status1 & (STATUS_POISON | STATUS_BURN | STATUS_PARALYSIS | STATUS_TOXIC_POISON)) - odds = (odds * 15) / 10; - - if (gLastUsedItem != ITEM_SAFARI_BALL) - { - if (gLastUsedItem == ITEM_MASTER_BALL) - { - gBattleResults.unk5_1 = 1; - } - else - { - if (gBattleResults.catchAttempts[gLastUsedItem - ITEM_ULTRA_BALL] < 0xFF) - gBattleResults.catchAttempts[gLastUsedItem - ITEM_ULTRA_BALL]++; - } - } - - if (odds > 254) // mon caught - { - EmitBallThrow(0, BALL_3_SHAKES_SUCCESS); - MarkBufferBankForExecution(gActiveBank); - gBattlescriptCurrInstr = BattleScript_SuccessBallThrow; - SetMonData(&gEnemyParty[gBattlePartyID[gBankTarget]], MON_DATA_POKEBALL, &gLastUsedItem); - - if (CalculatePlayerPartyCount() == 6) - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - else - gBattleCommunication[MULTISTRING_CHOOSER] = 1; - } - else // mon may be caught, calculate shakes - { - u8 shakes; - - odds = Sqrt(Sqrt(16711680 / odds)); - odds = 1048560 / odds; - - for (shakes = 0; shakes < 4 && Random() < odds; shakes++); - - if (gLastUsedItem == ITEM_MASTER_BALL) - shakes = BALL_3_SHAKES_SUCCESS; // why calculate the shakes before that check? - - EmitBallThrow(0, shakes); - MarkBufferBankForExecution(gActiveBank); - - if (shakes == BALL_3_SHAKES_SUCCESS) // mon caught, copy of the code above - { - gBattlescriptCurrInstr = BattleScript_SuccessBallThrow; - SetMonData(&gEnemyParty[gBattlePartyID[gBankTarget]], MON_DATA_POKEBALL, &gLastUsedItem); - - if (CalculatePlayerPartyCount() == 6) - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - else - gBattleCommunication[MULTISTRING_CHOOSER] = 1; - } - else // not caught - { - gBattleCommunication[MULTISTRING_CHOOSER] = shakes; - gBattlescriptCurrInstr = BattleScript_ShakeBallThrow; - } - } - } -} - -static void atkF0_give_caught_mon(void) -{ - if (GiveMonToPlayer(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]]) != MON_GIVEN_TO_PARTY) - { - if (!sub_813B21C()) - { - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - StringCopy(gStringVar1, GetBoxNamePtr(VarGet(VAR_STORAGE_UNKNOWN))); - GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_NICKNAME, gStringVar2); - } - else - { - StringCopy(gStringVar1, GetBoxNamePtr(VarGet(VAR_STORAGE_UNKNOWN))); - GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_NICKNAME, gStringVar2); - StringCopy(gStringVar3, GetBoxNamePtr(get_unknown_box_id())); - gBattleCommunication[MULTISTRING_CHOOSER] = 2; - } - - if (FlagGet(SYS_PC_LANETTE)) - gBattleCommunication[MULTISTRING_CHOOSER]++; - } - - gBattleResults.caughtMonSpecies = GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_SPECIES, NULL); - GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_NICKNAME, gBattleResults.caughtMonNick); - gBattleResults.caughtMonBall = GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_POKEBALL, NULL); - - gBattlescriptCurrInstr++; -} - -static void atkF1_set_caught_mon_dex_flags(void) -{ - u16 species = GetMonData(&gEnemyParty[0], MON_DATA_SPECIES, NULL); - u32 personality = GetMonData(&gEnemyParty[0], MON_DATA_PERSONALITY, NULL); - - if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_GET_CAUGHT)) - { - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - else - { - HandleSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_SET_CAUGHT, personality); - gBattlescriptCurrInstr += 5; - } -} - -static void atkF2_display_dex_info(void) -{ - u16 species = GetMonData(&gEnemyParty[0], MON_DATA_SPECIES, NULL); - - switch (gBattleCommunication[0]) - { - case 0: - BeginNormalPaletteFade(-1, 0, 0, 0x10, 0); - gBattleCommunication[0]++; - break; - case 1: - if (!gPaletteFade.active) - { - FreeAllWindowBuffers(); - gBattleCommunication[TASK_ID] = CreateDexDisplayMonDataTask(SpeciesToNationalPokedexNum(species), - gBattleMons[gBankTarget].otId, - gBattleMons[gBankTarget].personality); - gBattleCommunication[0]++; - } - break; - case 2: - if (!gPaletteFade.active - && gMain.callback2 == BattleMainCB2 - && !gTasks[gBattleCommunication[TASK_ID]].isActive) - { - SetVBlankCallback(VBlankCB_Battle); - gBattleCommunication[0]++; - } - break; - case 3: - c2_berry_program_update_menu(); - sub_8035AA4(); - gBattle_BG3_X = 0x100; - gBattleCommunication[0]++; - break; - case 4: - if (!IsDma3ManagerBusyWithBgCopy()) - { - BeginNormalPaletteFade(0xFFFF, 0, 0x10, 0, 0); - ShowBg(0); - ShowBg(3); - gBattleCommunication[0]++; - } - break; - case 5: - if (!gPaletteFade.active) - gBattlescriptCurrInstr++; - break; - } -} - -void sub_8056A3C(u8 xStart, u8 yStart, u8 xEnd, u8 yEnd, u8 flags) -{ - s32 destY, destX; - u16 var = 0; - - for (destY = yStart; destY <= yEnd; destY++) - { - for (destX = xStart; destX <= xEnd; destX++) - { - if (destY == yStart) - { - if (destX == xStart) - var = 0x1022; - else if (destX == xEnd) - var = 0x1024; - else - var = 0x1023; - } - else if (destY == yEnd) - { - if (destX == xStart) - var = 0x1028; - else if (destX == xEnd) - var = 0x102A; - else - var = 0x1029; - } - else - { - if (destX == xStart) - var = 0x1025; - else if (destX == xEnd) - var = 0x1027; - else - var = 0x1026; - } - - if (flags & 1) - var = 0; - - if (flags & 0x80) - CopyToBgTilemapBufferRect_ChangePalette(1, &var, destX, destY, 1, 1, 0x11); - else - CopyToBgTilemapBufferRect_ChangePalette(0, &var, destX, destY, 1, 1, 0x11); - } - } -} - -void BattleCreateCursorAt(u8 cursorPosition) -{ - u16 src[2]; - src[0] = 1; - src[1] = 2; - - CopyToBgTilemapBufferRect_ChangePalette(0, src, 0x19, 9 + (2 * cursorPosition), 1, 2, 0x11); - CopyBgTilemapBufferToVram(0); -} - -void BattleDestroyCursorAt(u8 cursorPosition) -{ - u16 src[2]; - src[0] = 0x1016; - src[1] = 0x1016; - - CopyToBgTilemapBufferRect_ChangePalette(0, src, 0x19, 9 + (2 * cursorPosition), 1, 2, 0x11); - CopyBgTilemapBufferToVram(0); -} - -static void atkF3_nickname_caught_poke(void) -{ - switch (gBattleCommunication[MULTIUSE_STATE]) - { - case 0: - sub_8056A3C(0x18, 8, 0x1D, 0xD, 0); - sub_814F9EC(gText_BattleYesNoChoice, 0xC); - gBattleCommunication[MULTIUSE_STATE]++; - gBattleCommunication[CURSOR_POSITION] = 0; - BattleCreateCursorAt(0); - break; - case 1: - if (gMain.newKeys & DPAD_UP && gBattleCommunication[CURSOR_POSITION] != 0) - { - PlaySE(SE_SELECT); - BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); - gBattleCommunication[CURSOR_POSITION] = 0; - BattleCreateCursorAt(0); - } - if (gMain.newKeys & DPAD_DOWN && gBattleCommunication[CURSOR_POSITION] == 0) - { - PlaySE(SE_SELECT); - BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); - gBattleCommunication[CURSOR_POSITION] = 1; - BattleCreateCursorAt(1); - } - if (gMain.newKeys & A_BUTTON) - { - PlaySE(SE_SELECT); - if (gBattleCommunication[CURSOR_POSITION] == 0) - { - gBattleCommunication[MULTIUSE_STATE]++; - BeginFastPaletteFade(3); - } - else - { - gBattleCommunication[MULTIUSE_STATE] = 4; - } - } - else if (gMain.newKeys & B_BUTTON) - { - PlaySE(SE_SELECT); - gBattleCommunication[MULTIUSE_STATE] = 4; - } - break; - case 2: - if (!gPaletteFade.active) - { - GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_NICKNAME, gBattleStruct->caughtMonNick); - FreeAllWindowBuffers(); - - DoNamingScreen(NAMING_SCREEN_CAUGHT_MON, gBattleStruct->caughtMonNick, - GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_SPECIES), - GetMonGender(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]]), - GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_PERSONALITY, NULL), - BattleMainCB2); - - gBattleCommunication[MULTIUSE_STATE]++; - } - break; - case 3: - if (gMain.callback2 == BattleMainCB2 && !gPaletteFade.active ) - { - SetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_NICKNAME, gBattleStruct->caughtMonNick); - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - } - break; - case 4: - if (CalculatePlayerPartyCount() == 6) - gBattlescriptCurrInstr += 5; - else - gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); - break; - } -} - -static void atkF4_subattackerhpbydmg(void) -{ - gBattleMons[gBankAttacker].hp -= gBattleMoveDamage; - gBattlescriptCurrInstr++; -} - -static void atkF5_removeattackerstatus1(void) -{ - gBattleMons[gBankAttacker].status1 = 0; - gBattlescriptCurrInstr++; -} - -static void atkF6_802BF48(void) -{ - gFightStateTracker = 0xC; -} - -static void atkF7_802BF54(void) -{ - gFightStateTracker = 0xC; - gCurrentMoveTurn = gNoOfAllBanks; -} - -static void atkF8_trainer_slide_back(void) -{ - gActiveBank = GetBankByIdentity(gBattlescriptCurrInstr[1]); - EmitTrainerSlideBack(0); - MarkBufferBankForExecution(gActiveBank); - - gBattlescriptCurrInstr += 2; -} diff --git a/src/battle_ai.c b/src/battle_ai.c deleted file mode 100644 index 8590b0f03..000000000 --- a/src/battle_ai.c +++ /dev/null @@ -1,2922 +0,0 @@ -#include "global.h" -#include "battle_ai.h" -#include "pokemon.h" -#include "battle.h" -#include "species.h" -#include "abilities.h" -#include "rng.h" -#include "item.h" -#include "battle_move_effects.h" - -#define AIScriptRead32(ptr) ((ptr)[0] | (ptr)[1] << 8 | (ptr)[2] << 16 | (ptr)[3] << 24) -#define AIScriptRead16(ptr) ((ptr)[0] | (ptr)[1] << 8) -#define AIScriptRead8(ptr) ((ptr)[0]) -#define AIScriptReadPtr(ptr) (u8*) AIScriptRead32(ptr) - -#define AI_ACTION_DONE 0x0001 -#define AI_ACTION_FLEE 0x0002 -#define AI_ACTION_WATCH 0x0004 -#define AI_ACTION_DO_NOT_ATTACK 0x0008 -#define AI_ACTION_UNK5 0x0010 -#define AI_ACTION_UNK6 0x0020 -#define AI_ACTION_UNK7 0x0040 -#define AI_ACTION_UNK8 0x0080 - -#define AI_THINKING_STRUCT ((struct AI_ThinkingStruct *)(gBattleResources->ai)) -#define BATTLE_HISTORY ((struct BattleHistory *)(gBattleResources->battleHistory)) - -enum -{ - AI_TARGET, - AI_USER, - AI_TARGET_PARTNER, - AI_USER_PARTNER -}; - -// AI states -enum -{ - AIState_SettingUp, - AIState_Processing, - AIState_FinishedProcessing, - AIState_DoNotProcess -}; - -/* -gAIScriptPtr is a pointer to the next battle AI cmd command to read. -when a command finishes processing, gAIScriptPtr is incremented by -the number of bytes that the current command had reserved for arguments -in order to read the next command correctly. refer to battle_ai_scripts.s for the -AI scripts. -*/ - -extern u32 gBattleTypeFlags; -extern u8 gActiveBank; -extern struct BattlePokemon gBattleMons[4]; -extern u16 gCurrentMove; -extern u8 gBankTarget; -extern u8 gAbsentBankFlags; -extern u16 gLastUsedMovesByBanks[4]; -extern u16 gTrainerBattleOpponent_A; -extern u16 gTrainerBattleOpponent_B; -extern u32 gStatuses3[4]; -extern u16 gSideAffecting[2]; -extern u16 gBattlePartyID[4]; -extern u16 gDynamicBasePower; -extern u8 gBattleMoveFlags; -extern s32 gBattleMoveDamage; -extern u8 gCritMultiplier; -extern u16 gBattleWeather; - -extern const struct BattleMove gBattleMoves[]; -extern const struct BaseStats gBaseStats[]; -extern const u32 gBitTable[]; -extern u8 * const gBattleAI_ScriptsTable[]; - -extern u8 b_first_side(u8, u8, u8); -extern void AI_CalcDmg(u8, u8); - -extern u8 CheckMoveLimitations(); -extern u32 GetAiScriptsInRecordedBattle(); -extern u32 GetAiScriptsInBattleFactory(); - -static u8 BattleAI_ChooseMoveOrAction_Singles(void); -static u8 BattleAI_ChooseMoveOrAction_Doubles(void); -static void RecordLastUsedMoveByTarget(void); -static void BattleAI_DoAIProcessing(void); -static void AIStackPushVar(const u8 *); -static bool8 AIStackPop(void); - -static void BattleAICmd_if_random_less_than(void); -static void BattleAICmd_if_random_greater_than(void); -static void BattleAICmd_if_random_equal(void); -static void BattleAICmd_if_random_not_equal(void); -static void BattleAICmd_score(void); -static void BattleAICmd_if_hp_less_than(void); -static void BattleAICmd_if_hp_more_than(void); -static void BattleAICmd_if_hp_equal(void); -static void BattleAICmd_if_hp_not_equal(void); -static void BattleAICmd_if_status(void); -static void BattleAICmd_if_not_status(void); -static void BattleAICmd_if_status2(void); -static void BattleAICmd_if_not_status2(void); -static void BattleAICmd_if_status3(void); -static void BattleAICmd_if_not_status3(void); -static void BattleAICmd_if_side_affecting(void); -static void BattleAICmd_if_not_side_affecting(void); -static void BattleAICmd_if_less_than(void); -static void BattleAICmd_if_more_than(void); -static void BattleAICmd_if_equal(void); -static void BattleAICmd_if_not_equal(void); -static void BattleAICmd_if_less_than_32(void); -static void BattleAICmd_if_more_than_32(void); -static void BattleAICmd_if_equal_32(void); -static void BattleAICmd_if_not_equal_32(void); -static void BattleAICmd_if_move(void); -static void BattleAICmd_if_not_move(void); -static void BattleAICmd_if_in_bytes(void); -static void BattleAICmd_if_not_in_bytes(void); -static void BattleAICmd_if_in_words(void); -static void BattleAICmd_if_not_in_words(void); -static void BattleAICmd_if_user_can_damage(void); -static void BattleAICmd_if_user_cant_damage(void); -static void BattleAICmd_get_turn_count(void); -static void BattleAICmd_get_type(void); -static void BattleAICmd_get_last_used_bank_move_power(void); -static void BattleAICmd_is_most_powerful_move(void); -static void BattleAICmd_get_last_used_bank_move(void); -static void BattleAICmd_if_arg_equal(void); -static void BattleAICmd_if_arg_not_equal(void); -static void BattleAICmd_if_would_go_first(void); -static void BattleAICmd_if_would_not_go_first(void); -static void BattleAICmd_nullsub_2A(void); -static void BattleAICmd_nullsub_2B(void); -static void BattleAICmd_count_alive_pokemon(void); -static void BattleAICmd_get_considered_move(void); -static void BattleAICmd_get_considered_move_effect(void); -static void BattleAICmd_get_ability(void); -static void BattleAICmd_get_highest_type_effectiveness(void); -static void BattleAICmd_if_type_effectiveness(void); -static void BattleAICmd_nullsub_32(void); -static void BattleAICmd_nullsub_33(void); -static void BattleAICmd_if_status_in_party(void); -static void BattleAICmd_if_status_not_in_party(void); -static void BattleAICmd_get_weather(void); -static void BattleAICmd_if_effect(void); -static void BattleAICmd_if_not_effect(void); -static void BattleAICmd_if_stat_level_less_than(void); -static void BattleAICmd_if_stat_level_more_than(void); -static void BattleAICmd_if_stat_level_equal(void); -static void BattleAICmd_if_stat_level_not_equal(void); -static void BattleAICmd_if_can_faint(void); -static void BattleAICmd_if_cant_faint(void); -static void BattleAICmd_if_has_move(void); -static void BattleAICmd_if_dont_have_move(void); -static void BattleAICmd_if_move_effect(void); -static void BattleAICmd_if_not_move_effect(void); -static void BattleAICmd_if_any_move_disabled_or_encored(void); -static void BattleAICmd_if_curr_move_disabled_or_encored(void); -static void BattleAICmd_flee(void); -static void BattleAICmd_if_random_100(void); -static void BattleAICmd_watch(void); -static void BattleAICmd_get_hold_effect(void); -static void BattleAICmd_get_gender(void); -static void BattleAICmd_is_first_turn(void); -static void BattleAICmd_get_stockpile_count(void); -static void BattleAICmd_is_double_battle(void); -static void BattleAICmd_get_used_held_item(void); -static void BattleAICmd_get_move_type_from_result(void); -static void BattleAICmd_get_move_power_from_result(void); -static void BattleAICmd_get_move_effect_from_result(void); -static void BattleAICmd_get_protect_count(void); -static void BattleAICmd_nullsub_52(void); -static void BattleAICmd_nullsub_53(void); -static void BattleAICmd_nullsub_54(void); -static void BattleAICmd_nullsub_55(void); -static void BattleAICmd_nullsub_56(void); -static void BattleAICmd_nullsub_57(void); -static void BattleAICmd_call(void); -static void BattleAICmd_jump(void); -static void BattleAICmd_end(void); -static void BattleAICmd_if_level_cond(void); -static void BattleAICmd_if_target_taunted(void); -static void BattleAICmd_if_target_not_taunted(void); -static void BattleAICmd_check_ability(void); -static void BattleAICmd_is_of_type(void); -static void BattleAICmd_if_target_is_ally(void); -static void BattleAICmd_if_flash_fired(void); -static void BattleAICmd_if_holds_item(void); - -// ewram - -EWRAM_DATA const u8 *gAIScriptPtr = NULL; -EWRAM_DATA static u8 sBank_AI = 0; - -// const rom data - -typedef void (*BattleAICmdFunc)(void); - -static const BattleAICmdFunc sBattleAICmdTable[] = -{ - BattleAICmd_if_random_less_than, // 0x0 - BattleAICmd_if_random_greater_than, // 0x1 - BattleAICmd_if_random_equal, // 0x2 - BattleAICmd_if_random_not_equal, // 0x3 - BattleAICmd_score, // 0x4 - BattleAICmd_if_hp_less_than, // 0x5 - BattleAICmd_if_hp_more_than, // 0x6 - BattleAICmd_if_hp_equal, // 0x7 - BattleAICmd_if_hp_not_equal, // 0x8 - BattleAICmd_if_status, // 0x9 - BattleAICmd_if_not_status, // 0xA - BattleAICmd_if_status2, // 0xB - BattleAICmd_if_not_status2, // 0xC - BattleAICmd_if_status3, // 0xD - BattleAICmd_if_not_status3, // 0xE - BattleAICmd_if_side_affecting, // 0xF - BattleAICmd_if_not_side_affecting, // 0x10 - BattleAICmd_if_less_than, // 0x11 - BattleAICmd_if_more_than, // 0x12 - BattleAICmd_if_equal, // 0x13 - BattleAICmd_if_not_equal, // 0x14 - BattleAICmd_if_less_than_32, // 0x15 - BattleAICmd_if_more_than_32, // 0x16 - BattleAICmd_if_equal_32, // 0x17 - BattleAICmd_if_not_equal_32, // 0x18 - BattleAICmd_if_move, // 0x19 - BattleAICmd_if_not_move, // 0x1A - BattleAICmd_if_in_bytes, // 0x1B - BattleAICmd_if_not_in_bytes, // 0x1C - BattleAICmd_if_in_words, // 0x1D - BattleAICmd_if_not_in_words, // 0x1E - BattleAICmd_if_user_can_damage, // 0x1F - BattleAICmd_if_user_cant_damage, // 0x20 - BattleAICmd_get_turn_count, // 0x21 - BattleAICmd_get_type, // 0x22 - BattleAICmd_get_last_used_bank_move_power, // 0x23 - BattleAICmd_is_most_powerful_move, // 0x24 - BattleAICmd_get_last_used_bank_move, // 0x25 - BattleAICmd_if_arg_equal, // 0x26 - BattleAICmd_if_arg_not_equal, // 0x27 - BattleAICmd_if_would_go_first, // 0x28 - BattleAICmd_if_would_not_go_first, // 0x29 - BattleAICmd_nullsub_2A, // 0x2A - BattleAICmd_nullsub_2B, // 0x2B - BattleAICmd_count_alive_pokemon, // 0x2C - BattleAICmd_get_considered_move, // 0x2D - BattleAICmd_get_considered_move_effect, // 0x2E - BattleAICmd_get_ability, // 0x2F - BattleAICmd_get_highest_type_effectiveness, // 0x30 - BattleAICmd_if_type_effectiveness, // 0x31 - BattleAICmd_nullsub_32, // 0x32 - BattleAICmd_nullsub_33, // 0x33 - BattleAICmd_if_status_in_party, // 0x34 - BattleAICmd_if_status_not_in_party, // 0x35 - BattleAICmd_get_weather, // 0x36 - BattleAICmd_if_effect, // 0x37 - BattleAICmd_if_not_effect, // 0x38 - BattleAICmd_if_stat_level_less_than, // 0x39 - BattleAICmd_if_stat_level_more_than, // 0x3A - BattleAICmd_if_stat_level_equal, // 0x3B - BattleAICmd_if_stat_level_not_equal, // 0x3C - BattleAICmd_if_can_faint, // 0x3D - BattleAICmd_if_cant_faint, // 0x3E - BattleAICmd_if_has_move, // 0x3F - BattleAICmd_if_dont_have_move, // 0x40 - BattleAICmd_if_move_effect, // 0x41 - BattleAICmd_if_not_move_effect, // 0x42 - BattleAICmd_if_any_move_disabled_or_encored, // 0x43 - BattleAICmd_if_curr_move_disabled_or_encored, // 0x44 - BattleAICmd_flee, // 0x45 - BattleAICmd_if_random_100, // 0x46 - BattleAICmd_watch, // 0x47 - BattleAICmd_get_hold_effect, // 0x48 - BattleAICmd_get_gender, // 0x49 - BattleAICmd_is_first_turn, // 0x4A - BattleAICmd_get_stockpile_count, // 0x4B - BattleAICmd_is_double_battle, // 0x4C - BattleAICmd_get_used_held_item, // 0x4D - BattleAICmd_get_move_type_from_result, // 0x4E - BattleAICmd_get_move_power_from_result, // 0x4F - BattleAICmd_get_move_effect_from_result, // 0x50 - BattleAICmd_get_protect_count, // 0x51 - BattleAICmd_nullsub_52, // 0x52 - BattleAICmd_nullsub_53, // 0x53 - BattleAICmd_nullsub_54, // 0x54 - BattleAICmd_nullsub_55, // 0x55 - BattleAICmd_nullsub_56, // 0x56 - BattleAICmd_nullsub_57, // 0x57 - BattleAICmd_call, // 0x58 - BattleAICmd_jump, // 0x59 - BattleAICmd_end, // 0x5A - BattleAICmd_if_level_cond, // 0x5B - BattleAICmd_if_target_taunted, // 0x5C - BattleAICmd_if_target_not_taunted, // 0x5D - BattleAICmd_if_target_is_ally, // 0x5E - BattleAICmd_is_of_type, // 0x5F - BattleAICmd_check_ability, // 0x60 - BattleAICmd_if_flash_fired, // 0x61 - BattleAICmd_if_holds_item, // 0x62 -}; - -static const u16 sDiscouragedPowerfulMoveEffects[] = -{ - EFFECT_EXPLOSION, - EFFECT_DREAM_EATER, - EFFECT_RAZOR_WIND, - EFFECT_SKY_ATTACK, - EFFECT_RECHARGE, - EFFECT_SKULL_BASH, - EFFECT_SOLARBEAM, - EFFECT_SPIT_UP, - EFFECT_FOCUS_PUNCH, - EFFECT_SUPERPOWER, - EFFECT_ERUPTION, - EFFECT_OVERHEAT, - 0xFFFF -}; - -void BattleAI_HandleItemUseBeforeAISetup(u8 defaultScoreMoves) -{ - s32 i; - u8 *data = (u8 *)gBattleResources->battleHistory; - - for (i = 0; i < sizeof(struct BattleHistory); i++) - data[i] = 0; - // items are allowed to use in ONLY trainer battles - if ((gBattleTypeFlags & - (BATTLE_TYPE_LINK | BATTLE_TYPE_SAFARI | BATTLE_TYPE_BATTLE_TOWER | - BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_TRAINER | BATTLE_TYPE_FRONTIER - | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_x2000000 | BATTLE_TYPE_SECRET_BASE)) - == BATTLE_TYPE_TRAINER) - { - for (i = 0; i < 4; i++) - { - if (gTrainers[gTrainerBattleOpponent_A].items[i] != 0) - { - gBattleResources->battleHistory->TrainerItems[gBattleResources->battleHistory->itemsNo] = gTrainers[gTrainerBattleOpponent_A].items[i]; - gBattleResources->battleHistory->itemsNo++; - } - } - } - - BattleAI_SetupAIData(defaultScoreMoves); -} - -void BattleAI_SetupAIData(u8 defaultScoreMoves) -{ - s32 i; - u8 *data = (u8 *)AI_THINKING_STRUCT; - u8 moveLimitations; - - // clear AI data. - for (i = 0; i < sizeof(struct AI_ThinkingStruct); i++) - data[i] = 0; - - // conditional score reset, unlike Ruby. - for (i = 0; i < 4; i++) - { - if (defaultScoreMoves & 1) - AI_THINKING_STRUCT->score[i] = 100; - else - AI_THINKING_STRUCT->score[i] = 0; - defaultScoreMoves >>= 1; - } - - moveLimitations = CheckMoveLimitations(gActiveBank, 0, 0xFF); - - // ignore moves that aren't possible to use - for (i = 0; i < 4; i++) - { - if (gBitTable[i] & moveLimitations) - AI_THINKING_STRUCT->score[i] = 0; - - AI_THINKING_STRUCT->simulatedRNG[i] = 100 - (Random() % 16); - } - gBattleResources->AI_ScriptsStack->size = 0; - sBank_AI = gActiveBank; - // decide a random target bank in doubles - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) - { - gBankTarget = (Random() & 2) + (GetBankSide(gActiveBank) ^ 1); - if (gAbsentBankFlags & gBitTable[gBankTarget]) - gBankTarget ^= 2; - } - // in singles there's only one choice - else - gBankTarget = sBank_AI ^ 1; - - if (gBattleTypeFlags & BATTLE_TYPE_RECORDED) - AI_THINKING_STRUCT->aiFlags = GetAiScriptsInRecordedBattle(); - else if (gBattleTypeFlags & BATTLE_TYPE_SAFARI) - AI_THINKING_STRUCT->aiFlags = 0x40000000; - else if (gBattleTypeFlags & BATTLE_TYPE_ROAMER) - AI_THINKING_STRUCT->aiFlags = 0x20000000; - else if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE) - AI_THINKING_STRUCT->aiFlags = 0x80000000; - else if (gBattleTypeFlags & BATTLE_TYPE_FACTORY) - AI_THINKING_STRUCT->aiFlags = GetAiScriptsInBattleFactory(); - else if (gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_x4000000 | BATTLE_TYPE_SECRET_BASE)) - AI_THINKING_STRUCT->aiFlags = 7; // the smartest possible set - else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) - AI_THINKING_STRUCT->aiFlags = gTrainers[gTrainerBattleOpponent_A].aiFlags | gTrainers[gTrainerBattleOpponent_B].aiFlags; - else - AI_THINKING_STRUCT->aiFlags = gTrainers[gTrainerBattleOpponent_A].aiFlags; - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) - AI_THINKING_STRUCT->aiFlags |= 0x80; // act smart in doubles and don't attack your partner -} - -u8 BattleAI_ChooseMoveOrAction(void) -{ - u16 savedCurrentMove = gCurrentMove; - u8 ret; - - if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) - ret = BattleAI_ChooseMoveOrAction_Singles(); - else - ret = BattleAI_ChooseMoveOrAction_Doubles(); - - gCurrentMove = savedCurrentMove; - return ret; -} - -static u8 BattleAI_ChooseMoveOrAction_Singles(void) -{ - u8 currentMoveArray[4]; - u8 consideredMoveArray[4]; - u8 numOfBestMoves; - s32 i; - - RecordLastUsedMoveByTarget(); - - while (AI_THINKING_STRUCT->aiFlags != 0) - { - if (AI_THINKING_STRUCT->aiFlags & 1) - { - AI_THINKING_STRUCT->aiState = AIState_SettingUp; - BattleAI_DoAIProcessing(); - } - AI_THINKING_STRUCT->aiFlags >>= 1; - AI_THINKING_STRUCT->aiLogicId++; - AI_THINKING_STRUCT->movesetIndex = 0; - } - - // special flags for safari - if (AI_THINKING_STRUCT->aiAction & AI_ACTION_FLEE) - return 4; - if (AI_THINKING_STRUCT->aiAction & AI_ACTION_WATCH) - return 5; - - numOfBestMoves = 1; - currentMoveArray[0] = AI_THINKING_STRUCT->score[0]; - consideredMoveArray[0] = 0; - - for (i = 1; i < 4; i++) - { - if (gBattleMons[sBank_AI].moves[i] != 0) // emerald adds an extra move ID check for some reason. - { - // in ruby, the order of these if statements are reversed. - if (currentMoveArray[0] == AI_THINKING_STRUCT->score[i]) - { - currentMoveArray[numOfBestMoves] = AI_THINKING_STRUCT->score[i]; - consideredMoveArray[numOfBestMoves++] = i; - } - if (currentMoveArray[0] < AI_THINKING_STRUCT->score[i]) - { - numOfBestMoves = 1; - currentMoveArray[0] = AI_THINKING_STRUCT->score[i]; - consideredMoveArray[0] = i; - } - } - } - return consideredMoveArray[Random() % numOfBestMoves]; -} - -#ifdef NONMATCHING -static u8 BattleAI_ChooseMoveOrAction_Doubles(void) -{ - s32 i; - s32 j; - s32 scriptsToRun; - s16 mostMovePoints; - s16 bestMovePointsForTarget[4]; - s8 mostViableTargetsArray[4]; - u8 actionOrMoveIndex[4]; - u8 mostViableMovesScores[4]; - u8 mostViableMovesIndices[4]; - s32 mostViableTargetsNo; - s32 mostViableMovesNo; - - for (i = 0; i < 4; i++) //08130D14 - { - if (i == sBank_AI || gBattleMons[i].hp == 0) - { - //_08130D2E - actionOrMoveIndex[i] = -1; - bestMovePointsForTarget[i] = -1; - } - //_08130D48 - else - { - if (gBattleTypeFlags & BATTLE_TYPE_PALACE) - BattleAI_SetupAIData(gBattleStruct->field_92 >> 4); - else - BattleAI_SetupAIData(0xF); - //_08130D76 - gBankTarget = i; - if ((i & 1) != (sBank_AI & 1)) - RecordLastUsedMoveByTarget(); - //_08130D90 - AI_THINKING_STRUCT->aiLogicId = 0; - AI_THINKING_STRUCT->movesetIndex = 0; - scriptsToRun = AI_THINKING_STRUCT->aiFlags; - while (scriptsToRun != 0) - { - if (scriptsToRun & 1) - { - AI_THINKING_STRUCT->aiState = AIState_SettingUp; - BattleAI_DoAIProcessing(); - } - scriptsToRun >>= 1; - AI_THINKING_STRUCT->aiLogicId++; - AI_THINKING_STRUCT->movesetIndex = 0; - } - //_08130DD8 - if (AI_THINKING_STRUCT->aiAction & AI_ACTION_FLEE) - actionOrMoveIndex[i] = 4; - else if (AI_THINKING_STRUCT->aiAction & AI_ACTION_WATCH) - actionOrMoveIndex[i] = 5; - else - { - //_08130E10 - mostViableMovesScores[0] = AI_THINKING_STRUCT->score[0]; - mostViableMovesIndices[0] = 0; - mostViableMovesNo = 1; - for (j = 1; j < 4; j++) - { - if (gBattleMons[sBank_AI].moves[j] != 0) - { - if (mostViableMovesScores[0] == AI_THINKING_STRUCT->score[j]) - { - mostViableMovesScores[mostViableMovesNo] = AI_THINKING_STRUCT->score[j]; - mostViableMovesIndices[mostViableMovesNo] = j; - mostViableMovesNo++; - } - if (mostViableMovesScores[0] < AI_THINKING_STRUCT->score[j]) - { - mostViableMovesScores[0] = AI_THINKING_STRUCT->score[j]; - mostViableMovesIndices[0] = j; - mostViableMovesNo = 1; - } - } - //_08130E72 - } - actionOrMoveIndex[i] = mostViableMovesIndices[Random() % mostViableMovesNo]; - bestMovePointsForTarget[i] = mostViableMovesScores[0]; - - // don't use a move against ally if it has less than 100 pts - if (i == (sBank_AI ^ 2) && bestMovePointsForTarget[i] < 100) - bestMovePointsForTarget[i] = -1; - } - } - //_08130EAE - } - - //08130EC4 - mostMovePoints = bestMovePointsForTarget[0]; - mostViableTargetsArray[0] = 0; - mostViableTargetsNo = 1; - for (i = 1; i < 4; i++) - { - //_08130EDA - if (mostMovePoints == bestMovePointsForTarget[i]) - { - mostViableTargetsArray[mostViableTargetsNo] = i; - mostViableTargetsNo++; - } - //_08130EEE - if (mostMovePoints < bestMovePointsForTarget[i]) - { - mostMovePoints = bestMovePointsForTarget[i]; - mostViableTargetsArray[0] = i; - mostViableTargetsNo = 1; - } - } - gBankTarget = mostViableTargetsArray[Random() % mostViableTargetsNo]; - return actionOrMoveIndex[gBankTarget]; -} -#else -__attribute__((naked)) -static u8 BattleAI_ChooseMoveOrAction_Doubles(void) -{ - asm(".syntax unified\n\ - push {r4-r7,lr}\n\ - mov r7, r10\n\ - mov r6, r9\n\ - mov r5, r8\n\ - push {r5-r7}\n\ - sub sp, 0x24\n\ - movs r0, 0\n\ - mov r8, r0\n\ - mov r1, sp\n\ - adds r1, 0xC\n\ - str r1, [sp, 0x1C]\n\ - mov r2, sp\n\ - adds r2, 0x8\n\ - str r2, [sp, 0x18]\n\ - str r1, [sp, 0x20]\n\ - mov r10, sp\n\ -_08130D14:\n\ - ldr r0, =sBank_AI\n\ - ldrb r0, [r0]\n\ - cmp r8, r0\n\ - beq _08130D2E\n\ - movs r0, 0x58\n\ - mov r7, r8\n\ - muls r7, r0\n\ - adds r0, r7, 0\n\ - ldr r1, =gBattleMons\n\ - adds r0, r1\n\ - ldrh r0, [r0, 0x28]\n\ - cmp r0, 0\n\ - bne _08130D48\n\ -_08130D2E:\n\ - movs r0, 0xFF\n\ - ldr r2, [sp, 0x20]\n\ - strb r0, [r2]\n\ - ldr r0, =0x0000ffff\n\ - mov r7, r10\n\ - strh r0, [r7]\n\ - b _08130EAE\n\ - .pool\n\ -_08130D48:\n\ - ldr r0, =gBattleTypeFlags\n\ - ldr r0, [r0]\n\ - movs r1, 0x80\n\ - lsls r1, 10\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _08130D70\n\ - ldr r0, =gBattleStruct\n\ - ldr r0, [r0]\n\ - adds r0, 0x92\n\ - ldrb r0, [r0]\n\ - lsrs r0, 4\n\ - bl BattleAI_SetupAIData\n\ - b _08130D76\n\ - .pool\n\ -_08130D70:\n\ - movs r0, 0xF\n\ - bl BattleAI_SetupAIData\n\ -_08130D76:\n\ - ldr r0, =gBankTarget\n\ - mov r1, r8\n\ - strb r1, [r0]\n\ - movs r1, 0x1\n\ - mov r2, r8\n\ - ands r2, r1\n\ - ldr r0, =sBank_AI\n\ - ldrb r0, [r0]\n\ - ands r1, r0\n\ - cmp r2, r1\n\ - beq _08130D90\n\ - bl RecordLastUsedMoveByTarget\n\ -_08130D90:\n\ - ldr r2, =gBattleResources\n\ - ldr r0, [r2]\n\ - ldr r0, [r0, 0x14]\n\ - movs r1, 0\n\ - strb r1, [r0, 0x11]\n\ - ldr r0, [r2]\n\ - ldr r0, [r0, 0x14]\n\ - strb r1, [r0, 0x1]\n\ - ldr r0, [r2]\n\ - ldr r0, [r0, 0x14]\n\ - ldr r4, [r0, 0xC]\n\ - mov r9, r2\n\ - cmp r4, 0\n\ - beq _08130DD8\n\ - mov r5, r9\n\ - movs r6, 0\n\ -_08130DB0:\n\ - movs r0, 0x1\n\ - ands r0, r4\n\ - cmp r0, 0\n\ - beq _08130DC2\n\ - ldr r0, [r5]\n\ - ldr r0, [r0, 0x14]\n\ - strb r6, [r0]\n\ - bl BattleAI_DoAIProcessing\n\ -_08130DC2:\n\ - asrs r4, 1\n\ - ldr r0, [r5]\n\ - ldr r1, [r0, 0x14]\n\ - ldrb r0, [r1, 0x11]\n\ - adds r0, 0x1\n\ - strb r0, [r1, 0x11]\n\ - ldr r0, [r5]\n\ - ldr r0, [r0, 0x14]\n\ - strb r6, [r0, 0x1]\n\ - cmp r4, 0\n\ - bne _08130DB0\n\ -_08130DD8:\n\ - mov r2, r9\n\ - ldr r0, [r2]\n\ - ldr r3, [r0, 0x14]\n\ - ldrb r1, [r3, 0x10]\n\ - movs r0, 0x2\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _08130DFC\n\ - movs r0, 0x4\n\ - ldr r7, [sp, 0x20]\n\ - strb r0, [r7]\n\ - b _08130EAE\n\ - .pool\n\ -_08130DFC:\n\ - movs r0, 0x4\n\ - ands r0, r1\n\ - lsls r0, 24\n\ - lsrs r2, r0, 24\n\ - cmp r2, 0\n\ - beq _08130E10\n\ - movs r0, 0x5\n\ - ldr r1, [sp, 0x20]\n\ - strb r0, [r1]\n\ - b _08130EAE\n\ -_08130E10:\n\ - add r1, sp, 0x10\n\ - ldrb r0, [r3, 0x4]\n\ - strb r0, [r1]\n\ - add r0, sp, 0x14\n\ - strb r2, [r0]\n\ - movs r5, 0x1\n\ - movs r3, 0x1\n\ - adds r6, r1, 0\n\ - ldr r0, =sBank_AI\n\ - ldrb r1, [r0]\n\ - movs r0, 0x58\n\ - muls r0, r1\n\ - ldr r2, =gBattleMons + 0xC\n\ - adds r0, r2\n\ - adds r4, r0, 0x2\n\ - add r7, sp, 0x14\n\ -_08130E30:\n\ - ldrh r0, [r4]\n\ - cmp r0, 0\n\ - beq _08130E72\n\ - ldrb r1, [r6]\n\ - mov r2, r9\n\ - ldr r0, [r2]\n\ - ldr r0, [r0, 0x14]\n\ - adds r0, 0x4\n\ - adds r2, r0, r3\n\ - movs r0, 0\n\ - ldrsb r0, [r2, r0]\n\ - cmp r1, r0\n\ - bne _08130E56\n\ - adds r0, r6, r5\n\ - ldrb r1, [r2]\n\ - strb r1, [r0]\n\ - adds r0, r7, r5\n\ - strb r3, [r0]\n\ - adds r5, 0x1\n\ -_08130E56:\n\ - ldrb r1, [r6]\n\ - mov r2, r9\n\ - ldr r0, [r2]\n\ - ldr r0, [r0, 0x14]\n\ - adds r0, 0x4\n\ - adds r2, r0, r3\n\ - movs r0, 0\n\ - ldrsb r0, [r2, r0]\n\ - cmp r1, r0\n\ - bge _08130E72\n\ - ldrb r0, [r2]\n\ - strb r0, [r6]\n\ - strb r3, [r7]\n\ - movs r5, 0x1\n\ -_08130E72:\n\ - adds r4, 0x2\n\ - adds r3, 0x1\n\ - cmp r3, 0x3\n\ - ble _08130E30\n\ - bl Random\n\ - lsls r0, 16\n\ - lsrs r0, 16\n\ - adds r1, r5, 0\n\ - bl __modsi3\n\ - add r0, sp\n\ - adds r0, 0x14\n\ - ldrb r0, [r0]\n\ - ldr r7, [sp, 0x20]\n\ - strb r0, [r7]\n\ - ldrb r2, [r6]\n\ - mov r0, r10\n\ - strh r2, [r0]\n\ - ldr r0, =sBank_AI\n\ - ldrb r1, [r0]\n\ - movs r0, 0x2\n\ - eors r0, r1\n\ - cmp r8, r0\n\ - bne _08130EAE\n\ - cmp r2, 0x63\n\ - bgt _08130EAE\n\ - ldr r0, =0x0000ffff\n\ - mov r1, r10\n\ - strh r0, [r1]\n\ -_08130EAE:\n\ - ldr r2, [sp, 0x20]\n\ - adds r2, 0x1\n\ - str r2, [sp, 0x20]\n\ - movs r7, 0x2\n\ - add r10, r7\n\ - movs r0, 0x1\n\ - add r8, r0\n\ - mov r1, r8\n\ - cmp r1, 0x3\n\ - bgt _08130EC4\n\ - b _08130D14\n\ -_08130EC4:\n\ - mov r0, sp\n\ - ldrh r5, [r0]\n\ - movs r0, 0\n\ - ldr r2, [sp, 0x18]\n\ - strb r0, [r2]\n\ - movs r4, 0x1\n\ - mov r8, r4\n\ - ldr r6, =gBankTarget\n\ - ldr r3, [sp, 0x18]\n\ - mov r1, sp\n\ - adds r1, 0x2\n\ -_08130EDA:\n\ - lsls r0, r5, 16\n\ - asrs r2, r0, 16\n\ - movs r7, 0\n\ - ldrsh r0, [r1, r7]\n\ - cmp r2, r0\n\ - bne _08130EEE\n\ - adds r0, r3, r4\n\ - mov r7, r8\n\ - strb r7, [r0]\n\ - adds r4, 0x1\n\ -_08130EEE:\n\ - movs r7, 0\n\ - ldrsh r0, [r1, r7]\n\ - cmp r2, r0\n\ - bge _08130EFE\n\ - ldrh r5, [r1]\n\ - mov r0, r8\n\ - strb r0, [r3]\n\ - movs r4, 0x1\n\ -_08130EFE:\n\ - adds r1, 0x2\n\ - movs r2, 0x1\n\ - add r8, r2\n\ - mov r7, r8\n\ - cmp r7, 0x3\n\ - ble _08130EDA\n\ - bl Random\n\ - lsls r0, 16\n\ - lsrs r0, 16\n\ - adds r1, r4, 0\n\ - bl __modsi3\n\ - ldr r1, [sp, 0x18]\n\ - adds r0, r1, r0\n\ - ldrb r0, [r0]\n\ - strb r0, [r6]\n\ - ldrb r0, [r6]\n\ - ldr r2, [sp, 0x1C]\n\ - adds r0, r2, r0\n\ - ldrb r0, [r0]\n\ - add sp, 0x24\n\ - pop {r3-r5}\n\ - mov r8, r3\n\ - mov r9, r4\n\ - mov r10, r5\n\ - pop {r4-r7}\n\ - pop {r1}\n\ - bx r1\n\ - .pool\n\ - .syntax divided\n"); -} -#endif - -static void BattleAI_DoAIProcessing(void) -{ - while (AI_THINKING_STRUCT->aiState != AIState_FinishedProcessing) - { - switch (AI_THINKING_STRUCT->aiState) - { - case AIState_DoNotProcess: //Needed to match. - break; - case AIState_SettingUp: - gAIScriptPtr = gBattleAI_ScriptsTable[AI_THINKING_STRUCT->aiLogicId]; // set AI ptr to logic ID. - if (gBattleMons[sBank_AI].pp[AI_THINKING_STRUCT->movesetIndex] == 0) - { - AI_THINKING_STRUCT->moveConsidered = 0; - } - else - { - AI_THINKING_STRUCT->moveConsidered = gBattleMons[sBank_AI].moves[AI_THINKING_STRUCT->movesetIndex]; - } - AI_THINKING_STRUCT->aiState++; - break; - case AIState_Processing: - if (AI_THINKING_STRUCT->moveConsidered != 0) - sBattleAICmdTable[*gAIScriptPtr](); // run AI command. - else - { - AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] = 0; - AI_THINKING_STRUCT->aiAction |= AI_ACTION_DONE; - } - if (AI_THINKING_STRUCT->aiAction & AI_ACTION_DONE) - { - AI_THINKING_STRUCT->movesetIndex++; - - if (AI_THINKING_STRUCT->movesetIndex < 4 && !(AI_THINKING_STRUCT->aiAction & AI_ACTION_DO_NOT_ATTACK)) - AI_THINKING_STRUCT->aiState = AIState_SettingUp; - else - AI_THINKING_STRUCT->aiState++; - - AI_THINKING_STRUCT->aiAction &= ~(AI_ACTION_DONE); - } - break; - } - } -} - -static void RecordLastUsedMoveByTarget(void) -{ - s32 i; - - for (i = 0; i < 4; i++) - { - if (gBattleResources->battleHistory->usedMoves[gBankTarget].moves[i] == gLastUsedMovesByBanks[gBankTarget]) - break; - if (gBattleResources->battleHistory->usedMoves[gBankTarget].moves[i] != gLastUsedMovesByBanks[gBankTarget] //HACK: This redundant condition is a hack to make the asm match. - && gBattleResources->battleHistory->usedMoves[gBankTarget].moves[i] == 0) - { - gBattleResources->battleHistory->usedMoves[gBankTarget].moves[i] = gLastUsedMovesByBanks[gBankTarget]; - break; - } - } -} - -void ClearBankMoveHistory(u8 bank) -{ - s32 i; - - for (i = 0; i < 4; i++) - gBattleResources->battleHistory->usedMoves[bank].moves[i] = 0; -} - -void RecordAbilityBattle(u8 bank, u8 abilityId) -{ - gBattleResources->battleHistory->abilities[bank] = abilityId; -} - -void ClearBankAbilityHistory(u8 bank) -{ - gBattleResources->battleHistory->abilities[bank] = 0; -} - -void RecordItemEffectBattle(u8 bank, u8 itemEffect) -{ - gBattleResources->battleHistory->itemEffects[bank] = itemEffect; -} - -void ClearBankItemEffectHistory(u8 bank) -{ - gBattleResources->battleHistory->itemEffects[bank] = 0; -} - -static void BattleAICmd_if_random_less_than(void) -{ - u16 random = Random(); - - if (random % 256 < gAIScriptPtr[1]) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; -} - -static void BattleAICmd_if_random_greater_than(void) -{ - u16 random = Random(); - - if (random % 256 > gAIScriptPtr[1]) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; -} - -static void BattleAICmd_if_random_equal(void) -{ - u16 random = Random(); - - if (random % 256 == gAIScriptPtr[1]) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; -} - -static void BattleAICmd_if_random_not_equal(void) -{ - u16 random = Random(); - - if (random % 256 != gAIScriptPtr[1]) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; -} - -static void BattleAICmd_score(void) -{ - AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] += gAIScriptPtr[1]; // add the result to the array of the move consider's score. - - if (AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] < 0) // if the score is negative, flatten it to 0. - AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] = 0; - - gAIScriptPtr += 2; // AI return. -} - -static void BattleAICmd_if_hp_less_than(void) -{ - u16 index; - - if (gAIScriptPtr[1] == AI_USER) - index = sBank_AI; - else - index = gBankTarget; - - if ((u32)(100 * gBattleMons[index].hp / gBattleMons[index].maxHP) < gAIScriptPtr[2]) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); - else - gAIScriptPtr += 7; -} - -static void BattleAICmd_if_hp_more_than(void) -{ - u16 index; - - if (gAIScriptPtr[1] == AI_USER) - index = sBank_AI; - else - index = gBankTarget; - - if ((u32)(100 * gBattleMons[index].hp / gBattleMons[index].maxHP) > gAIScriptPtr[2]) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); - else - gAIScriptPtr += 7; -} - -static void BattleAICmd_if_hp_equal(void) -{ - u16 index; - - if (gAIScriptPtr[1] == AI_USER) - index = sBank_AI; - else - index = gBankTarget; - - if ((u32)(100 * gBattleMons[index].hp / gBattleMons[index].maxHP) == gAIScriptPtr[2]) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); - else - gAIScriptPtr += 7; -} - -static void BattleAICmd_if_hp_not_equal(void) -{ - u16 index; - - if (gAIScriptPtr[1] == AI_USER) - index = sBank_AI; - else - index = gBankTarget; - - if ((u32)(100 * gBattleMons[index].hp / gBattleMons[index].maxHP) != gAIScriptPtr[2]) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); - else - gAIScriptPtr += 7; -} - -static void BattleAICmd_if_status(void) -{ - u16 index; - u32 arg; - - if (gAIScriptPtr[1] == AI_USER) - index = sBank_AI; - else - index = gBankTarget; - - arg = AIScriptRead32(gAIScriptPtr + 2); - - if ((gBattleMons[index].status1 & arg) != 0) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); - else - gAIScriptPtr += 10; -} - -static void BattleAICmd_if_not_status(void) -{ - u16 index; - u32 arg; - - if (gAIScriptPtr[1] == AI_USER) - index = sBank_AI; - else - index = gBankTarget; - - arg = AIScriptRead32(gAIScriptPtr + 2); - - if ((gBattleMons[index].status1 & arg) == 0) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); - else - gAIScriptPtr += 10; -} - -static void BattleAICmd_if_status2(void) -{ - u16 index; - u32 arg; - - if (gAIScriptPtr[1] == AI_USER) - index = sBank_AI; - else - index = gBankTarget; - - arg = AIScriptRead32(gAIScriptPtr + 2); - - if ((gBattleMons[index].status2 & arg) != 0) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); - else - gAIScriptPtr += 10; -} - -static void BattleAICmd_if_not_status2(void) -{ - u16 index; - u32 arg; - - if (gAIScriptPtr[1] == AI_USER) - index = sBank_AI; - else - index = gBankTarget; - - arg = AIScriptRead32(gAIScriptPtr + 2); - - if ((gBattleMons[index].status2 & arg) == 0) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); - else - gAIScriptPtr += 10; -} - -static void BattleAICmd_if_status3(void) -{ - u16 index; - u32 arg; - - if (gAIScriptPtr[1] == AI_USER) - index = sBank_AI; - else - index = gBankTarget; - - arg = AIScriptRead32(gAIScriptPtr + 2); - - if ((gStatuses3[index] & arg) != 0) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); - else - gAIScriptPtr += 10; -} - -static void BattleAICmd_if_not_status3(void) -{ - u16 index; - u32 arg; - - if (gAIScriptPtr[1] == AI_USER) - index = sBank_AI; - else - index = gBankTarget; - - arg = AIScriptRead32(gAIScriptPtr + 2); - - if ((gStatuses3[index] & arg) == 0) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); - else - gAIScriptPtr += 10; -} - -static void BattleAICmd_if_side_affecting(void) -{ - u16 index; - u32 arg1, arg2; - - if (gAIScriptPtr[1] == AI_USER) - index = sBank_AI; - else - index = gBankTarget; - - arg1 = GetBankIdentity(index) & 1; - arg2 = AIScriptRead32(gAIScriptPtr + 2); - - if ((gSideAffecting[arg1] & arg2) != 0) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); - else - gAIScriptPtr += 10; -} - -static void BattleAICmd_if_not_side_affecting(void) -{ - u16 index; - u32 arg1, arg2; - - if (gAIScriptPtr[1] == AI_USER) - index = sBank_AI; - else - index = gBankTarget; - - arg1 = GetBankIdentity(index) & 1; - arg2 = AIScriptRead32(gAIScriptPtr + 2); - - if ((gSideAffecting[arg1] & arg2) == 0) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); - else - gAIScriptPtr += 10; -} - -static void BattleAICmd_if_less_than(void) -{ - if (AI_THINKING_STRUCT->funcResult < gAIScriptPtr[1]) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; -} - -static void BattleAICmd_if_more_than(void) -{ - if (AI_THINKING_STRUCT->funcResult > gAIScriptPtr[1]) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; -} - -static void BattleAICmd_if_equal(void) -{ - if (AI_THINKING_STRUCT->funcResult == gAIScriptPtr[1]) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; -} - -static void BattleAICmd_if_not_equal(void) -{ - if (AI_THINKING_STRUCT->funcResult != gAIScriptPtr[1]) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; -} - -static void BattleAICmd_if_less_than_32(void) -{ - u8 *temp = AIScriptReadPtr(gAIScriptPtr + 1); - - if (AI_THINKING_STRUCT->funcResult < *temp) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); - else - gAIScriptPtr += 9; -} - -static void BattleAICmd_if_more_than_32(void) -{ - u8 *temp = AIScriptReadPtr(gAIScriptPtr + 1); - - if (AI_THINKING_STRUCT->funcResult > *temp) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); - else - gAIScriptPtr += 9; -} - -static void BattleAICmd_if_equal_32(void) -{ - u8 *temp = AIScriptReadPtr(gAIScriptPtr + 1); - - if (AI_THINKING_STRUCT->funcResult == *temp) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); - else - gAIScriptPtr += 9; -} - -static void BattleAICmd_if_not_equal_32(void) -{ - u8 *temp = AIScriptReadPtr(gAIScriptPtr + 1); - - if (AI_THINKING_STRUCT->funcResult != *temp) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); - else - gAIScriptPtr += 9; -} - -static void BattleAICmd_if_move(void) -{ - u16 move = AIScriptRead16(gAIScriptPtr + 1); - - if (AI_THINKING_STRUCT->moveConsidered == move) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); - else - gAIScriptPtr += 7; -} - -static void BattleAICmd_if_not_move(void) -{ - u16 move = AIScriptRead16(gAIScriptPtr + 1); - - if (AI_THINKING_STRUCT->moveConsidered != move) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); - else - gAIScriptPtr += 7; -} - -static void BattleAICmd_if_in_bytes(void) -{ - u8 *ptr = AIScriptReadPtr(gAIScriptPtr + 1); - - while (*ptr != 0xFF) - { - if (AI_THINKING_STRUCT->funcResult == *ptr) - { - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); - return; - } - ptr++; - } - gAIScriptPtr += 9; -} - -static void BattleAICmd_if_not_in_bytes(void) -{ - u8 *ptr = AIScriptReadPtr(gAIScriptPtr + 1); - - while (*ptr != 0xFF) - { - if (AI_THINKING_STRUCT->funcResult == *ptr) - { - gAIScriptPtr += 9; - return; - } - ptr++; - } - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); -} - -static void BattleAICmd_if_in_words(void) -{ - u16 *ptr = (u16 *)AIScriptReadPtr(gAIScriptPtr + 1); - - while (*ptr != 0xFFFF) - { - if (AI_THINKING_STRUCT->funcResult == *ptr) - { - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); - return; - } - ptr++; - } - gAIScriptPtr += 9; -} - -static void BattleAICmd_if_not_in_words(void) -{ - u16 *ptr = (u16 *)AIScriptReadPtr(gAIScriptPtr + 1); - - while (*ptr != 0xFFFF) - { - if (AI_THINKING_STRUCT->funcResult == *ptr) - { - gAIScriptPtr += 9; - return; - } - ptr++; - } - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); -} - -static void BattleAICmd_if_user_can_damage(void) -{ - s32 i; - - for (i = 0; i < 4; i++) - { - if (gBattleMons[sBank_AI].moves[i] != 0 - && gBattleMoves[gBattleMons[sBank_AI].moves[i]].power != 0) - break; - } - if (i == 4) - gAIScriptPtr += 5; - else - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); -} - -static void BattleAICmd_if_user_cant_damage(void) -{ - s32 i; - - for (i = 0; i < 4; i++) - { - if (gBattleMons[sBank_AI].moves[i] != 0 - && gBattleMoves[gBattleMons[sBank_AI].moves[i]].power != 0) - break; - } - if (i != 4) - gAIScriptPtr += 5; - else - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); -} - -static void BattleAICmd_get_turn_count(void) -{ - AI_THINKING_STRUCT->funcResult = gBattleResults.battleTurnCounter; - gAIScriptPtr += 1; -} - -static void BattleAICmd_get_type(void) -{ - u8 typeVar = gAIScriptPtr[1]; - - switch (typeVar) - { - case 1: // player primary type - AI_THINKING_STRUCT->funcResult = gBattleMons[sBank_AI].type1; - break; - case 0: // enemy primary type - AI_THINKING_STRUCT->funcResult = gBattleMons[gBankTarget].type1; - break; - case 3: // player secondary type - AI_THINKING_STRUCT->funcResult = gBattleMons[sBank_AI].type2; - break; - case 2: // enemy secondary type - AI_THINKING_STRUCT->funcResult = gBattleMons[gBankTarget].type2; - break; - case 4: // type of move being pointed to - AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->moveConsidered].type; - break; - } - gAIScriptPtr += 2; -} - -static u8 BattleAI_GetWantedBank(u8 index) -{ - switch (index) - { - case AI_USER: - return sBank_AI; - case AI_TARGET: - default: - return gBankTarget; - case AI_USER_PARTNER: - return sBank_AI ^ 2; - case AI_TARGET_PARTNER: - return gBankTarget ^ 2; - } -} - -static void BattleAICmd_is_of_type(void) -{ - u8 bank = BattleAI_GetWantedBank(gAIScriptPtr[1]); - - if(gBattleMons[bank].type1 == gAIScriptPtr[2] || gBattleMons[bank].type2 == gAIScriptPtr[2]) - { - AI_THINKING_STRUCT->funcResult = 1; - } - else - { - AI_THINKING_STRUCT->funcResult = 0; - } - - gAIScriptPtr += 3; -} - -static void BattleAICmd_get_last_used_bank_move_power(void) -{ - AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power; - gAIScriptPtr += 1; -} - -__attribute__((naked)) // not even going to try. if it doesnt match in ruby, it wont match in emerald (yet). -static void BattleAICmd_is_most_powerful_move(void) -{ - asm(".syntax unified\n\ - push {r4-r7,lr}\n\ - mov r7, r10\n\ - mov r6, r9\n\ - mov r5, r8\n\ - push {r5-r7}\n\ - sub sp, 0x14\n\ - movs r3, 0\n\ - ldr r0, =sDiscouragedPowerfulMoveEffects\n\ - ldrh r1, [r0]\n\ - ldr r5, =0x0000ffff\n\ - ldr r6, =gBattleMoves\n\ - ldr r2, =gBattleResources\n\ - cmp r1, r5\n\ - beq _08131F86\n\ - ldr r0, [r2]\n\ - ldr r0, [r0, 0x14]\n\ - ldrh r1, [r0, 0x2]\n\ - lsls r0, r1, 1\n\ - adds r0, r1\n\ - lsls r0, 2\n\ - adds r0, r6\n\ - ldrb r4, [r0]\n\ - ldr r1, =sDiscouragedPowerfulMoveEffects\n\ -_08131F76:\n\ - ldrh r0, [r1]\n\ - cmp r4, r0\n\ - beq _08131F86\n\ - adds r1, 0x2\n\ - adds r3, 0x1\n\ - ldrh r0, [r1]\n\ - cmp r0, r5\n\ - bne _08131F76\n\ -_08131F86:\n\ - ldr r0, [r2]\n\ - ldr r0, [r0, 0x14]\n\ - ldrh r1, [r0, 0x2]\n\ - lsls r0, r1, 1\n\ - adds r0, r1\n\ - lsls r0, 2\n\ - adds r0, r6\n\ - ldrb r0, [r0, 0x1]\n\ - cmp r0, 0x1\n\ - bhi _08131F9C\n\ - b _08132126\n\ -_08131F9C:\n\ - lsls r0, r3, 1\n\ - ldr r1, =sDiscouragedPowerfulMoveEffects\n\ - adds r0, r1\n\ - ldrh r3, [r0]\n\ - ldr r0, =0x0000ffff\n\ - cmp r3, r0\n\ - beq _08131FAC\n\ - b _08132126\n\ -_08131FAC:\n\ - ldr r0, =gDynamicBasePower\n\ - movs r1, 0\n\ - strh r1, [r0]\n\ - ldr r0, =gBattleStruct\n\ - ldr r0, [r0]\n\ - strb r1, [r0, 0x13]\n\ - ldr r0, =gBattleScripting\n\ - movs r2, 0x1\n\ - strb r2, [r0, 0xE]\n\ - ldr r0, =gBattleMoveFlags\n\ - strb r1, [r0]\n\ - ldr r0, =gCritMultiplier\n\ - strb r2, [r0]\n\ - movs r6, 0\n\ - mov r9, r3\n\ - ldr r2, =sDiscouragedPowerfulMoveEffects\n\ - ldrh r2, [r2]\n\ - str r2, [sp, 0x10]\n\ -_08131FD0:\n\ - movs r3, 0\n\ - ldr r5, =gBattleMons\n\ - lsls r4, r6, 1\n\ - ldr r7, =sBank_AI\n\ - lsls r0, r6, 2\n\ - mov r8, r0\n\ - adds r1, r6, 0x1\n\ - mov r10, r1\n\ - ldr r2, [sp, 0x10]\n\ - cmp r2, r9\n\ - beq _08132014\n\ - ldr r2, =gBattleMoves\n\ - ldrb r1, [r7]\n\ - movs r0, 0x58\n\ - muls r0, r1\n\ - adds r0, r4, r0\n\ - adds r1, r5, 0\n\ - adds r1, 0xC\n\ - adds r0, r1\n\ - ldrh r1, [r0]\n\ - lsls r0, r1, 1\n\ - adds r0, r1\n\ - lsls r0, 2\n\ - adds r0, r2\n\ - ldrb r2, [r0]\n\ - ldr r1, =sDiscouragedPowerfulMoveEffects\n\ -_08132004:\n\ - ldrh r0, [r1]\n\ - cmp r2, r0\n\ - beq _08132014\n\ - adds r1, 0x2\n\ - adds r3, 0x1\n\ - ldrh r0, [r1]\n\ - cmp r0, r9\n\ - bne _08132004\n\ -_08132014:\n\ - ldrb r1, [r7]\n\ - movs r0, 0x58\n\ - muls r0, r1\n\ - adds r0, r4, r0\n\ - adds r1, r5, 0\n\ - adds r1, 0xC\n\ - adds r1, r0, r1\n\ - ldrh r0, [r1]\n\ - cmp r0, 0\n\ - beq _081320C0\n\ - lsls r0, r3, 1\n\ - ldr r2, =sDiscouragedPowerfulMoveEffects\n\ - adds r0, r2\n\ - ldrh r0, [r0]\n\ - cmp r0, r9\n\ - bne _081320C0\n\ - ldr r0, =gBattleMoves\n\ - ldrh r2, [r1]\n\ - lsls r1, r2, 1\n\ - adds r1, r2\n\ - lsls r1, 2\n\ - adds r1, r0\n\ - ldrb r0, [r1, 0x1]\n\ - cmp r0, 0x1\n\ - bls _081320C0\n\ - ldr r5, =gCurrentMove\n\ - strh r2, [r5]\n\ - ldrb r0, [r7]\n\ - ldr r4, =gBankTarget\n\ - ldrb r1, [r4]\n\ - bl AI_CalcDmg\n\ - ldrh r0, [r5]\n\ - ldrb r1, [r7]\n\ - ldrb r2, [r4]\n\ - bl TypeCalc\n\ - mov r4, sp\n\ - add r4, r8\n\ - ldr r2, =gBattleMoveDamage\n\ - ldr r0, =gBattleResources\n\ - ldr r0, [r0]\n\ - ldr r0, [r0, 0x14]\n\ - adds r0, 0x18\n\ - adds r0, r6\n\ - ldrb r1, [r0]\n\ - ldr r0, [r2]\n\ - muls r0, r1\n\ - movs r1, 0x64\n\ - bl __divsi3\n\ - str r0, [r4]\n\ - cmp r0, 0\n\ - bne _081320C8\n\ - movs r0, 0x1\n\ - str r0, [r4]\n\ - b _081320C8\n\ - .pool\n\ -_081320C0:\n\ - mov r1, sp\n\ - add r1, r8\n\ - movs r0, 0\n\ - str r0, [r1]\n\ -_081320C8:\n\ - mov r6, r10\n\ - cmp r6, 0x3\n\ - bgt _081320D0\n\ - b _08131FD0\n\ -_081320D0:\n\ - movs r6, 0\n\ - ldr r2, =gBattleResources\n\ - ldr r0, [r2]\n\ - ldr r0, [r0, 0x14]\n\ - ldrb r0, [r0, 0x1]\n\ - lsls r0, 2\n\ - add r0, sp\n\ - ldr r1, [sp]\n\ - ldr r0, [r0]\n\ - ldr r5, =gAIScriptPtr\n\ - cmp r1, r0\n\ - bgt _08132106\n\ - adds r4, r2, 0\n\ - mov r3, sp\n\ -_081320EC:\n\ - adds r3, 0x4\n\ - adds r6, 0x1\n\ - cmp r6, 0x3\n\ - bgt _08132106\n\ - ldr r0, [r4]\n\ - ldr r0, [r0, 0x14]\n\ - ldrb r0, [r0, 0x1]\n\ - lsls r0, 2\n\ - add r0, sp\n\ - ldr r1, [r3]\n\ - ldr r0, [r0]\n\ - cmp r1, r0\n\ - ble _081320EC\n\ -_08132106:\n\ - cmp r6, 0x4\n\ - bne _0813211C\n\ - ldr r0, [r2]\n\ - ldr r1, [r0, 0x14]\n\ - movs r0, 0x2\n\ - str r0, [r1, 0x8]\n\ - b _08132130\n\ - .pool\n\ -_0813211C:\n\ - ldr r0, [r2]\n\ - ldr r1, [r0, 0x14]\n\ - movs r0, 0x1\n\ - str r0, [r1, 0x8]\n\ - b _08132130\n\ -_08132126:\n\ - ldr r0, [r2]\n\ - ldr r1, [r0, 0x14]\n\ - movs r0, 0\n\ - str r0, [r1, 0x8]\n\ - ldr r5, =gAIScriptPtr\n\ -_08132130:\n\ - ldr r0, [r5]\n\ - adds r0, 0x1\n\ - str r0, [r5]\n\ - add sp, 0x14\n\ - pop {r3-r5}\n\ - mov r8, r3\n\ - mov r9, r4\n\ - mov r10, r5\n\ - pop {r4-r7}\n\ - pop {r0}\n\ - bx r0\n\ - .pool\n\ - .syntax divided"); -} - -static void BattleAICmd_get_last_used_bank_move(void) -{ - if (gAIScriptPtr[1] == AI_USER) - AI_THINKING_STRUCT->funcResult = gLastUsedMovesByBanks[sBank_AI]; - else - AI_THINKING_STRUCT->funcResult = gLastUsedMovesByBanks[gBankTarget]; - - gAIScriptPtr += 2; -} - -static void BattleAICmd_if_arg_equal(void) -{ - if (gAIScriptPtr[1] == AI_THINKING_STRUCT->funcResult) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; -} - -static void BattleAICmd_if_arg_not_equal(void) -{ - if (gAIScriptPtr[1] != AI_THINKING_STRUCT->funcResult) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; -} - -static void BattleAICmd_if_would_go_first(void) -{ - if (b_first_side(sBank_AI, gBankTarget, 1) == gAIScriptPtr[1]) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; -} - -static void BattleAICmd_if_would_not_go_first(void) -{ - if (b_first_side(sBank_AI, gBankTarget, 1) != gAIScriptPtr[1]) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; -} - -static void BattleAICmd_nullsub_2A(void) -{ -} - -static void BattleAICmd_nullsub_2B(void) -{ -} - -static void BattleAICmd_count_alive_pokemon(void) -{ - u8 index; - u8 bankOnField1, bankOnField2; - struct Pokemon *party; - int i; - - AI_THINKING_STRUCT->funcResult = 0; - - if (gAIScriptPtr[1] == AI_USER) - index = sBank_AI; - else - index = gBankTarget; - - if (GetBankSide(index) == 0) - party = gPlayerParty; - else - party = gEnemyParty; - - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) - { - u32 status; - bankOnField1 = gBattlePartyID[index]; - status = GetBankIdentity(index) ^ 2; - bankOnField2 = gBattlePartyID[GetBankByIdentity(status)]; - } - else // in singles there's only one bank by side - { - bankOnField1 = gBattlePartyID[index]; - bankOnField2 = gBattlePartyID[index]; - } - - for (i = 0; i < 6; i++) - { - if (i != bankOnField1 && i != bankOnField2 - && GetMonData(&party[i], MON_DATA_HP) != 0 - && GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_NONE - && GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_EGG) - { - AI_THINKING_STRUCT->funcResult++; - } - } - - gAIScriptPtr += 2; -} - -static void BattleAICmd_get_considered_move(void) -{ - AI_THINKING_STRUCT->funcResult = AI_THINKING_STRUCT->moveConsidered; - gAIScriptPtr += 1; -} - -static void BattleAICmd_get_considered_move_effect(void) -{ - AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->moveConsidered].effect; - gAIScriptPtr += 1; -} - -static void BattleAICmd_get_ability(void) -{ - u8 index; - - if (gAIScriptPtr[1] == AI_USER) - index = sBank_AI; - else - index = gBankTarget; - - if(gActiveBank != index) - { - if(BATTLE_HISTORY->abilities[index] != 0) - { - AI_THINKING_STRUCT->funcResult = BATTLE_HISTORY->abilities[index]; - gAIScriptPtr += 2; - return; - } - - // abilities that prevent fleeing. - if (gBattleMons[index].ability == ABILITY_SHADOW_TAG - || gBattleMons[index].ability == ABILITY_MAGNET_PULL - || gBattleMons[index].ability == ABILITY_ARENA_TRAP) - { - AI_THINKING_STRUCT->funcResult = gBattleMons[index].ability; - gAIScriptPtr += 2; - return; - } - - if (gBaseStats[gBattleMons[index].species].ability1 != ABILITY_NONE) - { - if (gBaseStats[gBattleMons[index].species].ability2 != ABILITY_NONE) - { - // AI has no knowledge of opponent, so it guesses which ability. - if (Random() & 1) - { - AI_THINKING_STRUCT->funcResult = gBaseStats[gBattleMons[index].species].ability1; - } - else - { - AI_THINKING_STRUCT->funcResult = gBaseStats[gBattleMons[index].species].ability2; - } - } - else - { - AI_THINKING_STRUCT->funcResult = gBaseStats[gBattleMons[index].species].ability1; // it's definitely ability 1. - } - } - else - { - AI_THINKING_STRUCT->funcResult = gBaseStats[gBattleMons[index].species].ability2; // AI cant actually reach this part since every mon has at least 1 ability. - } - } - else - { - // The AI knows its own ability. - AI_THINKING_STRUCT->funcResult = gBattleMons[index].ability; - } - gAIScriptPtr += 2; -} - -#ifdef NONMATCHING -static void BattleAICmd_check_ability(void) -{ - u8 bank = BattleAI_GetWantedBank(gAIScriptPtr[1]); - u8 ability = gAIScriptPtr[2]; - - if (gAIScriptPtr[1] == AI_TARGET || gAIScriptPtr[1] == AI_TARGET_PARTNER) - { - if (BATTLE_HISTORY->abilities[bank] != 0) - { - ability = BATTLE_HISTORY->abilities[bank]; - AI_THINKING_STRUCT->funcResult = ability; - } - // abilities that prevent fleeing. - else if (gBattleMons[bank].ability == ABILITY_SHADOW_TAG - || gBattleMons[bank].ability == ABILITY_MAGNET_PULL - || gBattleMons[bank].ability == ABILITY_ARENA_TRAP) - { - ability = gBattleMons[bank].ability; - } - else if (gBaseStats[gBattleMons[bank].species].ability1 != ABILITY_NONE) - { - if (gBaseStats[gBattleMons[bank].species].ability2 != ABILITY_NONE) - { - if (gBaseStats[gBattleMons[bank].species].ability1 != ability - && gBaseStats[gBattleMons[bank].species].ability2 != ability) - { - ability = gBaseStats[gBattleMons[bank].species].ability1; - } - else - ability = 0; - } - else - { - ability = gBaseStats[gBattleMons[bank].species].ability1; - } - } - else - { - ability = gBaseStats[gBattleMons[bank].species].ability2; // AI cant actually reach this part since every mon has at least 1 ability. - } - } - else - { - // The AI knows its own or partner's ability. - ability = gBattleMons[bank].ability; - } - if (ability == 0) - { - AI_THINKING_STRUCT->funcResult = 2; // unable to answer - } - else if (ability == gAIScriptPtr[2]) - { - AI_THINKING_STRUCT->funcResult = 1; // pokemon has the ability we wanted to check - } - else - { - AI_THINKING_STRUCT->funcResult = 0; // pokemon doesn't have the ability we wanted to check - } - gAIScriptPtr += 3; -} -#else -__attribute__((naked)) -static void BattleAICmd_check_ability(void) -{ - asm(".syntax unified\n\ - push {r4-r6,lr}\n\ - ldr r4, =gAIScriptPtr\n\ - ldr r0, [r4]\n\ - ldrb r0, [r0, 0x1]\n\ - bl BattleAI_GetWantedBank\n\ - lsls r0, 24\n\ - lsrs r5, r0, 24\n\ - ldr r0, [r4]\n\ - ldrb r3, [r0, 0x2]\n\ - ldrb r0, [r0, 0x1]\n\ - cmp r0, 0\n\ - beq _0813253A\n\ - cmp r0, 0x2\n\ - bne _081325BC\n\ -_0813253A:\n\ - ldr r0, =gBattleResources\n\ - ldr r4, [r0]\n\ - ldr r1, [r4, 0x18]\n\ - adds r1, 0x40\n\ - adds r2, r1, r5\n\ - ldrb r1, [r2]\n\ - adds r6, r0, 0\n\ - cmp r1, 0\n\ - beq _0813255C\n\ - adds r3, r1, 0\n\ - ldr r0, [r4, 0x14]\n\ - str r3, [r0, 0x8]\n\ - b _081325CA\n\ - .pool\n\ -_0813255C:\n\ - ldr r1, =gBattleMons\n\ - movs r0, 0x58\n\ - muls r0, r5\n\ - adds r4, r0, r1\n\ - adds r0, r4, 0\n\ - adds r0, 0x20\n\ - ldrb r0, [r0]\n\ - cmp r0, 0x17\n\ - beq _08132576\n\ - cmp r0, 0x2A\n\ - beq _08132576\n\ - cmp r0, 0x47\n\ - bne _08132588\n\ -_08132576:\n\ - movs r0, 0x58\n\ - muls r0, r5\n\ - adds r0, r1\n\ - adds r0, 0x20\n\ - ldrb r3, [r0]\n\ - b _081325CA\n\ - .pool\n\ -_08132588:\n\ - ldr r2, =gBaseStats\n\ - ldrh r1, [r4]\n\ - lsls r0, r1, 3\n\ - subs r0, r1\n\ - lsls r0, 2\n\ - adds r1, r0, r2\n\ - ldrb r4, [r1, 0x16]\n\ - cmp r4, 0\n\ - beq _081325B8\n\ - ldrb r2, [r1, 0x17]\n\ - cmp r2, 0\n\ - beq _081325B4\n\ - adds r0, r3, 0\n\ - cmp r4, r0\n\ - beq _081325CE\n\ - cmp r2, r0\n\ - beq _081325CE\n\ - adds r3, r4, 0\n\ - b _081325CA\n\ - .pool\n\ -_081325B4:\n\ - ldrb r3, [r1, 0x16]\n\ - b _081325CA\n\ -_081325B8:\n\ - ldrb r3, [r1, 0x17]\n\ - b _081325CA\n\ -_081325BC:\n\ - ldr r1, =gBattleMons\n\ - movs r0, 0x58\n\ - muls r0, r5\n\ - adds r0, r1\n\ - adds r0, 0x20\n\ - ldrb r3, [r0]\n\ - ldr r6, =gBattleResources\n\ -_081325CA:\n\ - cmp r3, 0\n\ - bne _081325E8\n\ -_081325CE:\n\ - ldr r0, [r6]\n\ - ldr r1, [r0, 0x14]\n\ - movs r0, 0x2\n\ - str r0, [r1, 0x8]\n\ - ldr r2, =gAIScriptPtr\n\ - b _08132608\n\ - .pool\n\ -_081325E8:\n\ - ldr r0, =gAIScriptPtr\n\ - ldr r1, [r0]\n\ - adds r2, r0, 0\n\ - ldrb r1, [r1, 0x2]\n\ - cmp r3, r1\n\ - bne _08132600\n\ - ldr r0, [r6]\n\ - ldr r1, [r0, 0x14]\n\ - movs r0, 0x1\n\ - b _08132606\n\ - .pool\n\ -_08132600:\n\ - ldr r0, [r6]\n\ - ldr r1, [r0, 0x14]\n\ - movs r0, 0\n\ -_08132606:\n\ - str r0, [r1, 0x8]\n\ -_08132608:\n\ - ldr r0, [r2]\n\ - adds r0, 0x3\n\ - str r0, [r2]\n\ - pop {r4-r6}\n\ - pop {r0}\n\ - bx r0\n\ - .pool\n\ - .syntax divided"); -} -#endif - -static void BattleAICmd_get_highest_type_effectiveness(void) -{ - s32 i; - u8* dynamicMoveType; - - gDynamicBasePower = 0; - dynamicMoveType = &gBattleStruct->dynamicMoveType; - *dynamicMoveType = 0; - gBattleScripting.dmgMultiplier = 1; - gBattleMoveFlags = 0; - gCritMultiplier = 1; - AI_THINKING_STRUCT->funcResult = 0; - - for (i = 0; i < 4; i++) - { - gBattleMoveDamage = 40; - gCurrentMove = gBattleMons[sBank_AI].moves[i]; - - if (gCurrentMove) - { - TypeCalc(gCurrentMove, sBank_AI, gBankTarget); - - // reduce by 1/3. - if (gBattleMoveDamage == 120) - gBattleMoveDamage = 80; - if (gBattleMoveDamage == 240) - gBattleMoveDamage = 160; - if (gBattleMoveDamage == 30) - gBattleMoveDamage = 20; - if (gBattleMoveDamage == 15) - gBattleMoveDamage = 10; - - if (gBattleMoveFlags & MOVESTATUS_NOTAFFECTED) - gBattleMoveDamage = 0; - - if (AI_THINKING_STRUCT->funcResult < gBattleMoveDamage) - AI_THINKING_STRUCT->funcResult = gBattleMoveDamage; - } - } - gAIScriptPtr += 1; -} - -static void BattleAICmd_if_type_effectiveness(void) -{ - u8 damageVar; - - gDynamicBasePower = 0; - gBattleStruct->dynamicMoveType = 0; - gBattleScripting.dmgMultiplier = 1; - gBattleMoveFlags = 0; - gCritMultiplier = 1; - - gBattleMoveDamage = 40; - gCurrentMove = AI_THINKING_STRUCT->moveConsidered; - - TypeCalc(gCurrentMove, sBank_AI, gBankTarget); - - if (gBattleMoveDamage == 120) - gBattleMoveDamage = 80; - if (gBattleMoveDamage == 240) - gBattleMoveDamage = 160; - if (gBattleMoveDamage == 30) - gBattleMoveDamage = 20; - if (gBattleMoveDamage == 15) - gBattleMoveDamage = 10; - - if (gBattleMoveFlags & MOVESTATUS_NOTAFFECTED) - gBattleMoveDamage = 0; - - // store gBattleMoveDamage in a u8 variable because gAIScriptPtr[1] is a u8. - damageVar = gBattleMoveDamage; - - if (damageVar == gAIScriptPtr[1]) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; -} - -static void BattleAICmd_nullsub_32(void) -{ -} - -static void BattleAICmd_nullsub_33(void) -{ -} - -static void BattleAICmd_if_status_in_party(void) -{ - struct Pokemon *party; - int i; - u32 statusToCompareTo; - u8 index; - - switch(gAIScriptPtr[1]) - { - case 1: - index = sBank_AI; - break; - default: - index = gBankTarget; - break; - } - - party = (GetBankSide(index) == 0) ? gPlayerParty : gEnemyParty; - - statusToCompareTo = AIScriptRead32(gAIScriptPtr + 2); - - for (i = 0; i < 6; i++) - { - u16 species = GetMonData(&party[i], MON_DATA_SPECIES); - u16 hp = GetMonData(&party[i], MON_DATA_HP); - u32 status = GetMonData(&party[i], MON_DATA_STATUS); - - if (species != SPECIES_NONE && species != SPECIES_EGG && hp != 0 && status == statusToCompareTo) - { - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); - return; - } - } - - gAIScriptPtr += 10; -} - -static void BattleAICmd_if_status_not_in_party(void) -{ - struct Pokemon *party; - int i; - u32 statusToCompareTo; - u8 index; - - switch(gAIScriptPtr[1]) - { - case 1: - index = sBank_AI; - break; - default: - index = gBankTarget; - break; - } - - party = (GetBankSide(index) == 0) ? gPlayerParty : gEnemyParty; - - statusToCompareTo = AIScriptRead32(gAIScriptPtr + 2); - - for (i = 0; i < 6; i++) - { - u16 species = GetMonData(&party[i], MON_DATA_SPECIES); - u16 hp = GetMonData(&party[i], MON_DATA_HP); - u32 status = GetMonData(&party[i], MON_DATA_STATUS); - - if (species != SPECIES_NONE && species != SPECIES_EGG && hp != 0 && status == statusToCompareTo) - { - gAIScriptPtr += 10; // still bugged in Emerald - } - } - - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); -} - -static void BattleAICmd_get_weather(void) -{ - if (gBattleWeather & WEATHER_RAIN_ANY) - AI_THINKING_STRUCT->funcResult = 1; - if (gBattleWeather & WEATHER_SANDSTORM_ANY) - AI_THINKING_STRUCT->funcResult = 2; - if (gBattleWeather & WEATHER_SUN_ANY) - AI_THINKING_STRUCT->funcResult = 0; - if (gBattleWeather & WEATHER_HAIL_ANY) - AI_THINKING_STRUCT->funcResult = 3; - - gAIScriptPtr += 1; -} - -static void BattleAICmd_if_effect(void) -{ - if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].effect == gAIScriptPtr[1]) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; -} - -static void BattleAICmd_if_not_effect(void) -{ - if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].effect != gAIScriptPtr[1]) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; -} - -static void BattleAICmd_if_stat_level_less_than(void) -{ - u32 bank; - - if (gAIScriptPtr[1] == AI_USER) - bank = sBank_AI; - else - bank = gBankTarget; - - if (gBattleMons[bank].statStages[gAIScriptPtr[2]] < gAIScriptPtr[3]) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); - else - gAIScriptPtr += 8; -} - -static void BattleAICmd_if_stat_level_more_than(void) -{ - u32 bank; - - if (gAIScriptPtr[1] == AI_USER) - bank = sBank_AI; - else - bank = gBankTarget; - - if (gBattleMons[bank].statStages[gAIScriptPtr[2]] > gAIScriptPtr[3]) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); - else - gAIScriptPtr += 8; -} - -static void BattleAICmd_if_stat_level_equal(void) -{ - u32 bank; - - if (gAIScriptPtr[1] == AI_USER) - bank = sBank_AI; - else - bank = gBankTarget; - - if (gBattleMons[bank].statStages[gAIScriptPtr[2]] == gAIScriptPtr[3]) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); - else - gAIScriptPtr += 8; -} - -static void BattleAICmd_if_stat_level_not_equal(void) -{ - u32 bank; - - if (gAIScriptPtr[1] == AI_USER) - bank = sBank_AI; - else - bank = gBankTarget; - - if (gBattleMons[bank].statStages[gAIScriptPtr[2]] != gAIScriptPtr[3]) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); - else - gAIScriptPtr += 8; -} - -static void BattleAICmd_if_can_faint(void) -{ - if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power < 2) - { - gAIScriptPtr += 5; - return; - } - - gDynamicBasePower = 0; - gBattleStruct->dynamicMoveType = 0; - gBattleScripting.dmgMultiplier = 1; - gBattleMoveFlags = 0; - gCritMultiplier = 1; - gCurrentMove = AI_THINKING_STRUCT->moveConsidered; - AI_CalcDmg(sBank_AI, gBankTarget); - TypeCalc(gCurrentMove, sBank_AI, gBankTarget); - - gBattleMoveDamage = gBattleMoveDamage * AI_THINKING_STRUCT->simulatedRNG[AI_THINKING_STRUCT->movesetIndex] / 100; - - // moves always do at least 1 damage. - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - - if (gBattleMons[gBankTarget].hp <= gBattleMoveDamage) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); - else - gAIScriptPtr += 5; -} - -static void BattleAICmd_if_cant_faint(void) -{ - if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power < 2) - { - gAIScriptPtr += 5; - return; - } - - gDynamicBasePower = 0; - gBattleStruct->dynamicMoveType = 0; - gBattleScripting.dmgMultiplier = 1; - gBattleMoveFlags = 0; - gCritMultiplier = 1; - gCurrentMove = AI_THINKING_STRUCT->moveConsidered; - AI_CalcDmg(sBank_AI, gBankTarget); - TypeCalc(gCurrentMove, sBank_AI, gBankTarget); - - gBattleMoveDamage = gBattleMoveDamage * AI_THINKING_STRUCT->simulatedRNG[AI_THINKING_STRUCT->movesetIndex] / 100; - - // this macro is missing the damage 0 = 1 assumption. - - if (gBattleMons[gBankTarget].hp > gBattleMoveDamage) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); - else - gAIScriptPtr += 5; -} - -static void BattleAICmd_if_has_move(void) -{ - int i; - u16 *temp_ptr = (u16 *)(gAIScriptPtr + 2); - - switch(gAIScriptPtr[1]) - { - case AI_USER: - for (i = 0; i < 4; i++) - { - if (gBattleMons[sBank_AI].moves[i] == *temp_ptr) - break; - } - if (i == 4) - { - gAIScriptPtr += 8; - return; - } - else - { - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); - return; - } - case AI_USER_PARTNER: - if (gBattleMons[sBank_AI ^ 2].hp == 0) - { - gAIScriptPtr += 8; - return; - } - else - { - for (i = 0; i < 4; i++) - { - if (gBattleMons[sBank_AI ^ 2].moves[i] == *temp_ptr) - break; - } - } - if (i == 4) - { - gAIScriptPtr += 8; - return; - } - else - { - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); - return; - } - case AI_TARGET: - case AI_TARGET_PARTNER: - for (i = 0; i < 4; i++) - { - if (BATTLE_HISTORY->usedMoves[gBankTarget].moves[i] == *temp_ptr) - break; - } - if (i == 4) - { - gAIScriptPtr += 8; - return; - } - else - { - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); - return; - } - } -} - -static void BattleAICmd_if_dont_have_move(void) -{ - int i; - u16 *temp_ptr = (u16 *)(gAIScriptPtr + 2); - - switch(gAIScriptPtr[1]) - { - case AI_USER: - case AI_USER_PARTNER: // UB: no separate check for user partner - for (i = 0; i < 4; i++) - { - if (gBattleMons[sBank_AI].moves[i] == *temp_ptr) - break; - } - if (i != 4) - { - gAIScriptPtr += 8; - return; - } - else - { - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); - return; - } - case AI_TARGET: - case AI_TARGET_PARTNER: - for (i = 0; i < 4; i++) - { - if (BATTLE_HISTORY->usedMoves[gBankTarget].moves[i] == *temp_ptr) - break; - } - if (i != 4) - { - gAIScriptPtr += 8; - return; - } - else - { - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); - return; - } - } -} - -static void BattleAICmd_if_move_effect(void) -{ - int i; - - switch (gAIScriptPtr[1]) - { - case AI_USER: - case AI_USER_PARTNER: - for (i = 0; i < 4; i++) - { - if(gBattleMons[sBank_AI].moves[i] != 0 && gBattleMoves[gBattleMons[sBank_AI].moves[i]].effect == gAIScriptPtr[2]) - break; - } - if (i == 4) - gAIScriptPtr += 7; - else - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); - break; - case AI_TARGET: - case AI_TARGET_PARTNER: - for (i = 0; i < 4; i++) - { - if (gBattleMons[sBank_AI].moves[i] != 0 && gBattleMoves[BATTLE_HISTORY->usedMoves[gBankTarget].moves[i]].effect == gAIScriptPtr[2]) - break; - } - if (i == 4) - gAIScriptPtr += 7; - else - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); - break; - } -} - -static void BattleAICmd_if_not_move_effect(void) -{ - int i; - - switch (gAIScriptPtr[1]) - { - case AI_USER: - case AI_USER_PARTNER: - for (i = 0; i < 4; i++) - { - if(gBattleMons[sBank_AI].moves[i] != 0 && gBattleMoves[gBattleMons[sBank_AI].moves[i]].effect == gAIScriptPtr[2]) - break; - } - if (i != 4) - gAIScriptPtr += 7; - else - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); - break; - case AI_TARGET: - case AI_TARGET_PARTNER: - for (i = 0; i < 4; i++) - { - if (BATTLE_HISTORY->usedMoves[gBankTarget].moves[i] && gBattleMoves[BATTLE_HISTORY->usedMoves[gBankTarget].moves[i]].effect == gAIScriptPtr[2]) - break; - } - if (i != 4) - gAIScriptPtr += 7; - else - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); - break; - } -} - -static void BattleAICmd_if_any_move_disabled_or_encored(void) -{ - u8 bank; - - if (gAIScriptPtr[1] == AI_USER) - bank = sBank_AI; - else - bank = gBankTarget; - - if (gAIScriptPtr[2] == 0) - { - if (gDisableStructs[bank].disabledMove == 0) - { - gAIScriptPtr += 7; - return; - } - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); - return; - } - else if (gAIScriptPtr[2] != 1) // ignore the macro if its not 0 or 1. - { - gAIScriptPtr += 7; - return; - } - else if (gDisableStructs[bank].encoredMove != 0) - { - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); - return; - } - gAIScriptPtr += 7; -} - -static void BattleAICmd_if_curr_move_disabled_or_encored(void) -{ - switch (gAIScriptPtr[1]) - { - case 0: - if (gDisableStructs[gActiveBank].disabledMove == AI_THINKING_STRUCT->moveConsidered) - { - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); - return; - } - gAIScriptPtr += 6; - return; - case 1: - if (gDisableStructs[gActiveBank].encoredMove == AI_THINKING_STRUCT->moveConsidered) - { - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); - return; - } - gAIScriptPtr += 6; - return; - default: - gAIScriptPtr += 6; - return; - } -} - -static void BattleAICmd_flee(void) -{ - AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_FLEE | AI_ACTION_DO_NOT_ATTACK); // what matters is UNK2 being enabled. -} - -static void BattleAICmd_if_random_100(void) -{ - u8 safariFleeRate = gBattleStruct->field_7B * 5; // safari flee rate, from 0-20 - - if ((u8)(Random() % 100) < safariFleeRate) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); - else - gAIScriptPtr += 5; -} - -static void BattleAICmd_watch(void) -{ - AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_WATCH | AI_ACTION_DO_NOT_ATTACK); // what matters is UNK3 being enabled. -} - -static void BattleAICmd_get_hold_effect(void) -{ - u8 bank; - u16 status; - - if (gAIScriptPtr[1] == AI_USER) - bank = sBank_AI; - else - bank = gBankTarget; - - if (gActiveBank != bank) - { - AI_THINKING_STRUCT->funcResult = ItemId_GetHoldEffect(BATTLE_HISTORY->itemEffects[bank]); - } - else - AI_THINKING_STRUCT->funcResult = ItemId_GetHoldEffect(gBattleMons[bank].item); - - gAIScriptPtr += 2; -} - -static void BattleAICmd_if_holds_item(void) -{ - u8 bank = BattleAI_GetWantedBank(gAIScriptPtr[1]); - u16 item; - u8 var1, var2; - - if ((bank & 1) == (sBank_AI & 1)) - item = gBattleMons[bank].item; - else - item = BATTLE_HISTORY->itemEffects[bank]; - - // UB: doesn't properly read an unaligned u16 - var2 = gAIScriptPtr[2]; - var1 = gAIScriptPtr[3]; - - if ((var1 | var2) == item) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); - else - gAIScriptPtr += 8; -} - -static void BattleAICmd_get_gender(void) -{ - u8 bank; - - if (gAIScriptPtr[1] == AI_USER) - bank = sBank_AI; - else - bank = gBankTarget; - - AI_THINKING_STRUCT->funcResult = GetGenderFromSpeciesAndPersonality(gBattleMons[bank].species, gBattleMons[bank].personality); - - gAIScriptPtr += 2; -} - -static void BattleAICmd_is_first_turn(void) -{ - u8 bank; - - if (gAIScriptPtr[1] == AI_USER) - bank = sBank_AI; - else - bank = gBankTarget; - - AI_THINKING_STRUCT->funcResult = gDisableStructs[bank].isFirstTurn; - - gAIScriptPtr += 2; -} - -static void BattleAICmd_get_stockpile_count(void) -{ - u8 bank; - - if (gAIScriptPtr[1] == AI_USER) - bank = sBank_AI; - else - bank = gBankTarget; - - AI_THINKING_STRUCT->funcResult = gDisableStructs[bank].stockpileCounter; - - gAIScriptPtr += 2; -} - -static void BattleAICmd_is_double_battle(void) -{ - AI_THINKING_STRUCT->funcResult = gBattleTypeFlags & BATTLE_TYPE_DOUBLE; - - gAIScriptPtr += 1; -} - -static void BattleAICmd_get_used_held_item(void) -{ - u8 bank; - - if (gAIScriptPtr[1] == AI_USER) - bank = sBank_AI; - else - bank = gBankTarget; - - // This is likely a leftover from Ruby's code and its ugly ewram access - #ifdef NONMATCHING - AI_THINKING_STRUCT->funcResult = gBattleStruct->usedHeldItems[bank]; - #else - AI_THINKING_STRUCT->funcResult = *(u8*)((u8*)(gBattleStruct) + 0xB8 + (bank * 2)); - #endif // NONMATCHING - - gAIScriptPtr += 2; -} - -static void BattleAICmd_get_move_type_from_result(void) -{ - AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->funcResult].type; - - gAIScriptPtr += 1; -} - -static void BattleAICmd_get_move_power_from_result(void) -{ - AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->funcResult].power; - - gAIScriptPtr += 1; -} - -static void BattleAICmd_get_move_effect_from_result(void) -{ - AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->funcResult].effect; - - gAIScriptPtr += 1; -} - -static void BattleAICmd_get_protect_count(void) -{ - u8 bank; - - if (gAIScriptPtr[1] == AI_USER) - bank = sBank_AI; - else - bank = gBankTarget; - - AI_THINKING_STRUCT->funcResult = gDisableStructs[bank].protectUses; - - gAIScriptPtr += 2; -} - -static void BattleAICmd_nullsub_52(void) -{ -} - -static void BattleAICmd_nullsub_53(void) -{ -} - -static void BattleAICmd_nullsub_54(void) -{ -} - -static void BattleAICmd_nullsub_55(void) -{ -} - -static void BattleAICmd_nullsub_56(void) -{ -} - -static void BattleAICmd_nullsub_57(void) -{ -} - -static void BattleAICmd_call(void) -{ - AIStackPushVar(gAIScriptPtr + 5); - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); -} - -static void BattleAICmd_jump(void) -{ - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); -} - -static void BattleAICmd_end(void) -{ - if (AIStackPop() == 0) - AI_THINKING_STRUCT->aiAction |= AI_ACTION_DONE; -} - -static void BattleAICmd_if_level_cond(void) -{ - switch (gAIScriptPtr[1]) - { - case 0: // greater than - if (gBattleMons[sBank_AI].level > gBattleMons[gBankTarget].level) - { - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); - return; - } - gAIScriptPtr += 6; - return; - case 1: // less than - if (gBattleMons[sBank_AI].level < gBattleMons[gBankTarget].level) - { - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); - return; - } - gAIScriptPtr += 6; - return; - case 2: // equal - if (gBattleMons[sBank_AI].level == gBattleMons[gBankTarget].level) - { - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); - return; - } - gAIScriptPtr += 6; - return; - } -} - -static void BattleAICmd_if_target_taunted(void) -{ - if (gDisableStructs[gBankTarget].tauntTimer1 != 0) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); - else - gAIScriptPtr += 5; -} - -static void BattleAICmd_if_target_not_taunted(void) -{ - if (gDisableStructs[gBankTarget].tauntTimer1 == 0) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); - else - gAIScriptPtr += 5; -} - -static void BattleAICmd_if_target_is_ally(void) -{ - if((sBank_AI & 1) == (gBankTarget & 1)) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); - else - gAIScriptPtr += 5; -} - -static void BattleAICmd_if_flash_fired(void) -{ - u8 index = BattleAI_GetWantedBank(gAIScriptPtr[1]); - - if(gBattleResources->flags->flags[index] & UNKNOWN_FLAG_FLASH_FIRE) - gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); - else - gAIScriptPtr += 6; -} - -static void AIStackPushVar(const u8 *var) -{ - gBattleResources->AI_ScriptsStack->ptr[gBattleResources->AI_ScriptsStack->size++] = var; -} - -static void AIStackPushVar_cursor(void) -{ - gBattleResources->AI_ScriptsStack->ptr[gBattleResources->AI_ScriptsStack->size++] = gAIScriptPtr; -} - -static bool8 AIStackPop(void) -{ - if (gBattleResources->AI_ScriptsStack->size != 0) - { - --gBattleResources->AI_ScriptsStack->size; - gAIScriptPtr = gBattleResources->AI_ScriptsStack->ptr[gBattleResources->AI_ScriptsStack->size]; - return TRUE; - } - else - return FALSE; -} diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c new file mode 100644 index 000000000..dae43f13c --- /dev/null +++ b/src/battle_ai_script_commands.c @@ -0,0 +1,2922 @@ +#include "global.h" +#include "battle_ai_script_commands.h" +#include "pokemon.h" +#include "battle.h" +#include "species.h" +#include "abilities.h" +#include "rng.h" +#include "item.h" +#include "battle_move_effects.h" + +#define AIScriptRead32(ptr) ((ptr)[0] | (ptr)[1] << 8 | (ptr)[2] << 16 | (ptr)[3] << 24) +#define AIScriptRead16(ptr) ((ptr)[0] | (ptr)[1] << 8) +#define AIScriptRead8(ptr) ((ptr)[0]) +#define AIScriptReadPtr(ptr) (u8*) AIScriptRead32(ptr) + +#define AI_ACTION_DONE 0x0001 +#define AI_ACTION_FLEE 0x0002 +#define AI_ACTION_WATCH 0x0004 +#define AI_ACTION_DO_NOT_ATTACK 0x0008 +#define AI_ACTION_UNK5 0x0010 +#define AI_ACTION_UNK6 0x0020 +#define AI_ACTION_UNK7 0x0040 +#define AI_ACTION_UNK8 0x0080 + +#define AI_THINKING_STRUCT ((struct AI_ThinkingStruct *)(gBattleResources->ai)) +#define BATTLE_HISTORY ((struct BattleHistory *)(gBattleResources->battleHistory)) + +enum +{ + AI_TARGET, + AI_USER, + AI_TARGET_PARTNER, + AI_USER_PARTNER +}; + +// AI states +enum +{ + AIState_SettingUp, + AIState_Processing, + AIState_FinishedProcessing, + AIState_DoNotProcess +}; + +/* +gAIScriptPtr is a pointer to the next battle AI cmd command to read. +when a command finishes processing, gAIScriptPtr is incremented by +the number of bytes that the current command had reserved for arguments +in order to read the next command correctly. refer to battle_ai_scripts.s for the +AI scripts. +*/ + +extern u32 gBattleTypeFlags; +extern u8 gActiveBank; +extern struct BattlePokemon gBattleMons[4]; +extern u16 gCurrentMove; +extern u8 gBankTarget; +extern u8 gAbsentBankFlags; +extern u16 gLastUsedMovesByBanks[4]; +extern u16 gTrainerBattleOpponent_A; +extern u16 gTrainerBattleOpponent_B; +extern u32 gStatuses3[4]; +extern u16 gSideAffecting[2]; +extern u16 gBattlePartyID[4]; +extern u16 gDynamicBasePower; +extern u8 gBattleMoveFlags; +extern s32 gBattleMoveDamage; +extern u8 gCritMultiplier; +extern u16 gBattleWeather; + +extern const struct BattleMove gBattleMoves[]; +extern const struct BaseStats gBaseStats[]; +extern const u32 gBitTable[]; +extern u8 * const gBattleAI_ScriptsTable[]; + +extern u8 b_first_side(u8, u8, u8); +extern void AI_CalcDmg(u8, u8); + +extern u8 CheckMoveLimitations(); +extern u32 GetAiScriptsInRecordedBattle(); +extern u32 GetAiScriptsInBattleFactory(); + +static u8 BattleAI_ChooseMoveOrAction_Singles(void); +static u8 BattleAI_ChooseMoveOrAction_Doubles(void); +static void RecordLastUsedMoveByTarget(void); +static void BattleAI_DoAIProcessing(void); +static void AIStackPushVar(const u8 *); +static bool8 AIStackPop(void); + +static void BattleAICmd_if_random_less_than(void); +static void BattleAICmd_if_random_greater_than(void); +static void BattleAICmd_if_random_equal(void); +static void BattleAICmd_if_random_not_equal(void); +static void BattleAICmd_score(void); +static void BattleAICmd_if_hp_less_than(void); +static void BattleAICmd_if_hp_more_than(void); +static void BattleAICmd_if_hp_equal(void); +static void BattleAICmd_if_hp_not_equal(void); +static void BattleAICmd_if_status(void); +static void BattleAICmd_if_not_status(void); +static void BattleAICmd_if_status2(void); +static void BattleAICmd_if_not_status2(void); +static void BattleAICmd_if_status3(void); +static void BattleAICmd_if_not_status3(void); +static void BattleAICmd_if_side_affecting(void); +static void BattleAICmd_if_not_side_affecting(void); +static void BattleAICmd_if_less_than(void); +static void BattleAICmd_if_more_than(void); +static void BattleAICmd_if_equal(void); +static void BattleAICmd_if_not_equal(void); +static void BattleAICmd_if_less_than_32(void); +static void BattleAICmd_if_more_than_32(void); +static void BattleAICmd_if_equal_32(void); +static void BattleAICmd_if_not_equal_32(void); +static void BattleAICmd_if_move(void); +static void BattleAICmd_if_not_move(void); +static void BattleAICmd_if_in_bytes(void); +static void BattleAICmd_if_not_in_bytes(void); +static void BattleAICmd_if_in_words(void); +static void BattleAICmd_if_not_in_words(void); +static void BattleAICmd_if_user_can_damage(void); +static void BattleAICmd_if_user_cant_damage(void); +static void BattleAICmd_get_turn_count(void); +static void BattleAICmd_get_type(void); +static void BattleAICmd_get_last_used_bank_move_power(void); +static void BattleAICmd_is_most_powerful_move(void); +static void BattleAICmd_get_last_used_bank_move(void); +static void BattleAICmd_if_arg_equal(void); +static void BattleAICmd_if_arg_not_equal(void); +static void BattleAICmd_if_would_go_first(void); +static void BattleAICmd_if_would_not_go_first(void); +static void BattleAICmd_nullsub_2A(void); +static void BattleAICmd_nullsub_2B(void); +static void BattleAICmd_count_alive_pokemon(void); +static void BattleAICmd_get_considered_move(void); +static void BattleAICmd_get_considered_move_effect(void); +static void BattleAICmd_get_ability(void); +static void BattleAICmd_get_highest_type_effectiveness(void); +static void BattleAICmd_if_type_effectiveness(void); +static void BattleAICmd_nullsub_32(void); +static void BattleAICmd_nullsub_33(void); +static void BattleAICmd_if_status_in_party(void); +static void BattleAICmd_if_status_not_in_party(void); +static void BattleAICmd_get_weather(void); +static void BattleAICmd_if_effect(void); +static void BattleAICmd_if_not_effect(void); +static void BattleAICmd_if_stat_level_less_than(void); +static void BattleAICmd_if_stat_level_more_than(void); +static void BattleAICmd_if_stat_level_equal(void); +static void BattleAICmd_if_stat_level_not_equal(void); +static void BattleAICmd_if_can_faint(void); +static void BattleAICmd_if_cant_faint(void); +static void BattleAICmd_if_has_move(void); +static void BattleAICmd_if_dont_have_move(void); +static void BattleAICmd_if_move_effect(void); +static void BattleAICmd_if_not_move_effect(void); +static void BattleAICmd_if_any_move_disabled_or_encored(void); +static void BattleAICmd_if_curr_move_disabled_or_encored(void); +static void BattleAICmd_flee(void); +static void BattleAICmd_if_random_100(void); +static void BattleAICmd_watch(void); +static void BattleAICmd_get_hold_effect(void); +static void BattleAICmd_get_gender(void); +static void BattleAICmd_is_first_turn(void); +static void BattleAICmd_get_stockpile_count(void); +static void BattleAICmd_is_double_battle(void); +static void BattleAICmd_get_used_held_item(void); +static void BattleAICmd_get_move_type_from_result(void); +static void BattleAICmd_get_move_power_from_result(void); +static void BattleAICmd_get_move_effect_from_result(void); +static void BattleAICmd_get_protect_count(void); +static void BattleAICmd_nullsub_52(void); +static void BattleAICmd_nullsub_53(void); +static void BattleAICmd_nullsub_54(void); +static void BattleAICmd_nullsub_55(void); +static void BattleAICmd_nullsub_56(void); +static void BattleAICmd_nullsub_57(void); +static void BattleAICmd_call(void); +static void BattleAICmd_jump(void); +static void BattleAICmd_end(void); +static void BattleAICmd_if_level_cond(void); +static void BattleAICmd_if_target_taunted(void); +static void BattleAICmd_if_target_not_taunted(void); +static void BattleAICmd_check_ability(void); +static void BattleAICmd_is_of_type(void); +static void BattleAICmd_if_target_is_ally(void); +static void BattleAICmd_if_flash_fired(void); +static void BattleAICmd_if_holds_item(void); + +// ewram + +EWRAM_DATA const u8 *gAIScriptPtr = NULL; +EWRAM_DATA static u8 sBank_AI = 0; + +// const rom data + +typedef void (*BattleAICmdFunc)(void); + +static const BattleAICmdFunc sBattleAICmdTable[] = +{ + BattleAICmd_if_random_less_than, // 0x0 + BattleAICmd_if_random_greater_than, // 0x1 + BattleAICmd_if_random_equal, // 0x2 + BattleAICmd_if_random_not_equal, // 0x3 + BattleAICmd_score, // 0x4 + BattleAICmd_if_hp_less_than, // 0x5 + BattleAICmd_if_hp_more_than, // 0x6 + BattleAICmd_if_hp_equal, // 0x7 + BattleAICmd_if_hp_not_equal, // 0x8 + BattleAICmd_if_status, // 0x9 + BattleAICmd_if_not_status, // 0xA + BattleAICmd_if_status2, // 0xB + BattleAICmd_if_not_status2, // 0xC + BattleAICmd_if_status3, // 0xD + BattleAICmd_if_not_status3, // 0xE + BattleAICmd_if_side_affecting, // 0xF + BattleAICmd_if_not_side_affecting, // 0x10 + BattleAICmd_if_less_than, // 0x11 + BattleAICmd_if_more_than, // 0x12 + BattleAICmd_if_equal, // 0x13 + BattleAICmd_if_not_equal, // 0x14 + BattleAICmd_if_less_than_32, // 0x15 + BattleAICmd_if_more_than_32, // 0x16 + BattleAICmd_if_equal_32, // 0x17 + BattleAICmd_if_not_equal_32, // 0x18 + BattleAICmd_if_move, // 0x19 + BattleAICmd_if_not_move, // 0x1A + BattleAICmd_if_in_bytes, // 0x1B + BattleAICmd_if_not_in_bytes, // 0x1C + BattleAICmd_if_in_words, // 0x1D + BattleAICmd_if_not_in_words, // 0x1E + BattleAICmd_if_user_can_damage, // 0x1F + BattleAICmd_if_user_cant_damage, // 0x20 + BattleAICmd_get_turn_count, // 0x21 + BattleAICmd_get_type, // 0x22 + BattleAICmd_get_last_used_bank_move_power, // 0x23 + BattleAICmd_is_most_powerful_move, // 0x24 + BattleAICmd_get_last_used_bank_move, // 0x25 + BattleAICmd_if_arg_equal, // 0x26 + BattleAICmd_if_arg_not_equal, // 0x27 + BattleAICmd_if_would_go_first, // 0x28 + BattleAICmd_if_would_not_go_first, // 0x29 + BattleAICmd_nullsub_2A, // 0x2A + BattleAICmd_nullsub_2B, // 0x2B + BattleAICmd_count_alive_pokemon, // 0x2C + BattleAICmd_get_considered_move, // 0x2D + BattleAICmd_get_considered_move_effect, // 0x2E + BattleAICmd_get_ability, // 0x2F + BattleAICmd_get_highest_type_effectiveness, // 0x30 + BattleAICmd_if_type_effectiveness, // 0x31 + BattleAICmd_nullsub_32, // 0x32 + BattleAICmd_nullsub_33, // 0x33 + BattleAICmd_if_status_in_party, // 0x34 + BattleAICmd_if_status_not_in_party, // 0x35 + BattleAICmd_get_weather, // 0x36 + BattleAICmd_if_effect, // 0x37 + BattleAICmd_if_not_effect, // 0x38 + BattleAICmd_if_stat_level_less_than, // 0x39 + BattleAICmd_if_stat_level_more_than, // 0x3A + BattleAICmd_if_stat_level_equal, // 0x3B + BattleAICmd_if_stat_level_not_equal, // 0x3C + BattleAICmd_if_can_faint, // 0x3D + BattleAICmd_if_cant_faint, // 0x3E + BattleAICmd_if_has_move, // 0x3F + BattleAICmd_if_dont_have_move, // 0x40 + BattleAICmd_if_move_effect, // 0x41 + BattleAICmd_if_not_move_effect, // 0x42 + BattleAICmd_if_any_move_disabled_or_encored, // 0x43 + BattleAICmd_if_curr_move_disabled_or_encored, // 0x44 + BattleAICmd_flee, // 0x45 + BattleAICmd_if_random_100, // 0x46 + BattleAICmd_watch, // 0x47 + BattleAICmd_get_hold_effect, // 0x48 + BattleAICmd_get_gender, // 0x49 + BattleAICmd_is_first_turn, // 0x4A + BattleAICmd_get_stockpile_count, // 0x4B + BattleAICmd_is_double_battle, // 0x4C + BattleAICmd_get_used_held_item, // 0x4D + BattleAICmd_get_move_type_from_result, // 0x4E + BattleAICmd_get_move_power_from_result, // 0x4F + BattleAICmd_get_move_effect_from_result, // 0x50 + BattleAICmd_get_protect_count, // 0x51 + BattleAICmd_nullsub_52, // 0x52 + BattleAICmd_nullsub_53, // 0x53 + BattleAICmd_nullsub_54, // 0x54 + BattleAICmd_nullsub_55, // 0x55 + BattleAICmd_nullsub_56, // 0x56 + BattleAICmd_nullsub_57, // 0x57 + BattleAICmd_call, // 0x58 + BattleAICmd_jump, // 0x59 + BattleAICmd_end, // 0x5A + BattleAICmd_if_level_cond, // 0x5B + BattleAICmd_if_target_taunted, // 0x5C + BattleAICmd_if_target_not_taunted, // 0x5D + BattleAICmd_if_target_is_ally, // 0x5E + BattleAICmd_is_of_type, // 0x5F + BattleAICmd_check_ability, // 0x60 + BattleAICmd_if_flash_fired, // 0x61 + BattleAICmd_if_holds_item, // 0x62 +}; + +static const u16 sDiscouragedPowerfulMoveEffects[] = +{ + EFFECT_EXPLOSION, + EFFECT_DREAM_EATER, + EFFECT_RAZOR_WIND, + EFFECT_SKY_ATTACK, + EFFECT_RECHARGE, + EFFECT_SKULL_BASH, + EFFECT_SOLARBEAM, + EFFECT_SPIT_UP, + EFFECT_FOCUS_PUNCH, + EFFECT_SUPERPOWER, + EFFECT_ERUPTION, + EFFECT_OVERHEAT, + 0xFFFF +}; + +void BattleAI_HandleItemUseBeforeAISetup(u8 defaultScoreMoves) +{ + s32 i; + u8 *data = (u8 *)gBattleResources->battleHistory; + + for (i = 0; i < sizeof(struct BattleHistory); i++) + data[i] = 0; + // items are allowed to use in ONLY trainer battles + if ((gBattleTypeFlags & + (BATTLE_TYPE_LINK | BATTLE_TYPE_SAFARI | BATTLE_TYPE_BATTLE_TOWER | + BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_TRAINER | BATTLE_TYPE_FRONTIER + | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_x2000000 | BATTLE_TYPE_SECRET_BASE)) + == BATTLE_TYPE_TRAINER) + { + for (i = 0; i < 4; i++) + { + if (gTrainers[gTrainerBattleOpponent_A].items[i] != 0) + { + gBattleResources->battleHistory->TrainerItems[gBattleResources->battleHistory->itemsNo] = gTrainers[gTrainerBattleOpponent_A].items[i]; + gBattleResources->battleHistory->itemsNo++; + } + } + } + + BattleAI_SetupAIData(defaultScoreMoves); +} + +void BattleAI_SetupAIData(u8 defaultScoreMoves) +{ + s32 i; + u8 *data = (u8 *)AI_THINKING_STRUCT; + u8 moveLimitations; + + // clear AI data. + for (i = 0; i < sizeof(struct AI_ThinkingStruct); i++) + data[i] = 0; + + // conditional score reset, unlike Ruby. + for (i = 0; i < 4; i++) + { + if (defaultScoreMoves & 1) + AI_THINKING_STRUCT->score[i] = 100; + else + AI_THINKING_STRUCT->score[i] = 0; + defaultScoreMoves >>= 1; + } + + moveLimitations = CheckMoveLimitations(gActiveBank, 0, 0xFF); + + // ignore moves that aren't possible to use + for (i = 0; i < 4; i++) + { + if (gBitTable[i] & moveLimitations) + AI_THINKING_STRUCT->score[i] = 0; + + AI_THINKING_STRUCT->simulatedRNG[i] = 100 - (Random() % 16); + } + gBattleResources->AI_ScriptsStack->size = 0; + sBank_AI = gActiveBank; + // decide a random target bank in doubles + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + gBankTarget = (Random() & 2) + (GetBankSide(gActiveBank) ^ 1); + if (gAbsentBankFlags & gBitTable[gBankTarget]) + gBankTarget ^= 2; + } + // in singles there's only one choice + else + gBankTarget = sBank_AI ^ 1; + + if (gBattleTypeFlags & BATTLE_TYPE_RECORDED) + AI_THINKING_STRUCT->aiFlags = GetAiScriptsInRecordedBattle(); + else if (gBattleTypeFlags & BATTLE_TYPE_SAFARI) + AI_THINKING_STRUCT->aiFlags = 0x40000000; + else if (gBattleTypeFlags & BATTLE_TYPE_ROAMER) + AI_THINKING_STRUCT->aiFlags = 0x20000000; + else if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE) + AI_THINKING_STRUCT->aiFlags = 0x80000000; + else if (gBattleTypeFlags & BATTLE_TYPE_FACTORY) + AI_THINKING_STRUCT->aiFlags = GetAiScriptsInBattleFactory(); + else if (gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_x4000000 | BATTLE_TYPE_SECRET_BASE)) + AI_THINKING_STRUCT->aiFlags = 7; // the smartest possible set + else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + AI_THINKING_STRUCT->aiFlags = gTrainers[gTrainerBattleOpponent_A].aiFlags | gTrainers[gTrainerBattleOpponent_B].aiFlags; + else + AI_THINKING_STRUCT->aiFlags = gTrainers[gTrainerBattleOpponent_A].aiFlags; + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + AI_THINKING_STRUCT->aiFlags |= 0x80; // act smart in doubles and don't attack your partner +} + +u8 BattleAI_ChooseMoveOrAction(void) +{ + u16 savedCurrentMove = gCurrentMove; + u8 ret; + + if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + ret = BattleAI_ChooseMoveOrAction_Singles(); + else + ret = BattleAI_ChooseMoveOrAction_Doubles(); + + gCurrentMove = savedCurrentMove; + return ret; +} + +static u8 BattleAI_ChooseMoveOrAction_Singles(void) +{ + u8 currentMoveArray[4]; + u8 consideredMoveArray[4]; + u8 numOfBestMoves; + s32 i; + + RecordLastUsedMoveByTarget(); + + while (AI_THINKING_STRUCT->aiFlags != 0) + { + if (AI_THINKING_STRUCT->aiFlags & 1) + { + AI_THINKING_STRUCT->aiState = AIState_SettingUp; + BattleAI_DoAIProcessing(); + } + AI_THINKING_STRUCT->aiFlags >>= 1; + AI_THINKING_STRUCT->aiLogicId++; + AI_THINKING_STRUCT->movesetIndex = 0; + } + + // special flags for safari + if (AI_THINKING_STRUCT->aiAction & AI_ACTION_FLEE) + return 4; + if (AI_THINKING_STRUCT->aiAction & AI_ACTION_WATCH) + return 5; + + numOfBestMoves = 1; + currentMoveArray[0] = AI_THINKING_STRUCT->score[0]; + consideredMoveArray[0] = 0; + + for (i = 1; i < 4; i++) + { + if (gBattleMons[sBank_AI].moves[i] != 0) // emerald adds an extra move ID check for some reason. + { + // in ruby, the order of these if statements are reversed. + if (currentMoveArray[0] == AI_THINKING_STRUCT->score[i]) + { + currentMoveArray[numOfBestMoves] = AI_THINKING_STRUCT->score[i]; + consideredMoveArray[numOfBestMoves++] = i; + } + if (currentMoveArray[0] < AI_THINKING_STRUCT->score[i]) + { + numOfBestMoves = 1; + currentMoveArray[0] = AI_THINKING_STRUCT->score[i]; + consideredMoveArray[0] = i; + } + } + } + return consideredMoveArray[Random() % numOfBestMoves]; +} + +#ifdef NONMATCHING +static u8 BattleAI_ChooseMoveOrAction_Doubles(void) +{ + s32 i; + s32 j; + s32 scriptsToRun; + s16 mostMovePoints; + s16 bestMovePointsForTarget[4]; + s8 mostViableTargetsArray[4]; + u8 actionOrMoveIndex[4]; + u8 mostViableMovesScores[4]; + u8 mostViableMovesIndices[4]; + s32 mostViableTargetsNo; + s32 mostViableMovesNo; + + for (i = 0; i < 4; i++) //08130D14 + { + if (i == sBank_AI || gBattleMons[i].hp == 0) + { + //_08130D2E + actionOrMoveIndex[i] = -1; + bestMovePointsForTarget[i] = -1; + } + //_08130D48 + else + { + if (gBattleTypeFlags & BATTLE_TYPE_PALACE) + BattleAI_SetupAIData(gBattleStruct->field_92 >> 4); + else + BattleAI_SetupAIData(0xF); + //_08130D76 + gBankTarget = i; + if ((i & 1) != (sBank_AI & 1)) + RecordLastUsedMoveByTarget(); + //_08130D90 + AI_THINKING_STRUCT->aiLogicId = 0; + AI_THINKING_STRUCT->movesetIndex = 0; + scriptsToRun = AI_THINKING_STRUCT->aiFlags; + while (scriptsToRun != 0) + { + if (scriptsToRun & 1) + { + AI_THINKING_STRUCT->aiState = AIState_SettingUp; + BattleAI_DoAIProcessing(); + } + scriptsToRun >>= 1; + AI_THINKING_STRUCT->aiLogicId++; + AI_THINKING_STRUCT->movesetIndex = 0; + } + //_08130DD8 + if (AI_THINKING_STRUCT->aiAction & AI_ACTION_FLEE) + actionOrMoveIndex[i] = 4; + else if (AI_THINKING_STRUCT->aiAction & AI_ACTION_WATCH) + actionOrMoveIndex[i] = 5; + else + { + //_08130E10 + mostViableMovesScores[0] = AI_THINKING_STRUCT->score[0]; + mostViableMovesIndices[0] = 0; + mostViableMovesNo = 1; + for (j = 1; j < 4; j++) + { + if (gBattleMons[sBank_AI].moves[j] != 0) + { + if (mostViableMovesScores[0] == AI_THINKING_STRUCT->score[j]) + { + mostViableMovesScores[mostViableMovesNo] = AI_THINKING_STRUCT->score[j]; + mostViableMovesIndices[mostViableMovesNo] = j; + mostViableMovesNo++; + } + if (mostViableMovesScores[0] < AI_THINKING_STRUCT->score[j]) + { + mostViableMovesScores[0] = AI_THINKING_STRUCT->score[j]; + mostViableMovesIndices[0] = j; + mostViableMovesNo = 1; + } + } + //_08130E72 + } + actionOrMoveIndex[i] = mostViableMovesIndices[Random() % mostViableMovesNo]; + bestMovePointsForTarget[i] = mostViableMovesScores[0]; + + // don't use a move against ally if it has less than 100 pts + if (i == (sBank_AI ^ 2) && bestMovePointsForTarget[i] < 100) + bestMovePointsForTarget[i] = -1; + } + } + //_08130EAE + } + + //08130EC4 + mostMovePoints = bestMovePointsForTarget[0]; + mostViableTargetsArray[0] = 0; + mostViableTargetsNo = 1; + for (i = 1; i < 4; i++) + { + //_08130EDA + if (mostMovePoints == bestMovePointsForTarget[i]) + { + mostViableTargetsArray[mostViableTargetsNo] = i; + mostViableTargetsNo++; + } + //_08130EEE + if (mostMovePoints < bestMovePointsForTarget[i]) + { + mostMovePoints = bestMovePointsForTarget[i]; + mostViableTargetsArray[0] = i; + mostViableTargetsNo = 1; + } + } + gBankTarget = mostViableTargetsArray[Random() % mostViableTargetsNo]; + return actionOrMoveIndex[gBankTarget]; +} +#else +__attribute__((naked)) +static u8 BattleAI_ChooseMoveOrAction_Doubles(void) +{ + asm(".syntax unified\n\ + push {r4-r7,lr}\n\ + mov r7, r10\n\ + mov r6, r9\n\ + mov r5, r8\n\ + push {r5-r7}\n\ + sub sp, 0x24\n\ + movs r0, 0\n\ + mov r8, r0\n\ + mov r1, sp\n\ + adds r1, 0xC\n\ + str r1, [sp, 0x1C]\n\ + mov r2, sp\n\ + adds r2, 0x8\n\ + str r2, [sp, 0x18]\n\ + str r1, [sp, 0x20]\n\ + mov r10, sp\n\ +_08130D14:\n\ + ldr r0, =sBank_AI\n\ + ldrb r0, [r0]\n\ + cmp r8, r0\n\ + beq _08130D2E\n\ + movs r0, 0x58\n\ + mov r7, r8\n\ + muls r7, r0\n\ + adds r0, r7, 0\n\ + ldr r1, =gBattleMons\n\ + adds r0, r1\n\ + ldrh r0, [r0, 0x28]\n\ + cmp r0, 0\n\ + bne _08130D48\n\ +_08130D2E:\n\ + movs r0, 0xFF\n\ + ldr r2, [sp, 0x20]\n\ + strb r0, [r2]\n\ + ldr r0, =0x0000ffff\n\ + mov r7, r10\n\ + strh r0, [r7]\n\ + b _08130EAE\n\ + .pool\n\ +_08130D48:\n\ + ldr r0, =gBattleTypeFlags\n\ + ldr r0, [r0]\n\ + movs r1, 0x80\n\ + lsls r1, 10\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _08130D70\n\ + ldr r0, =gBattleStruct\n\ + ldr r0, [r0]\n\ + adds r0, 0x92\n\ + ldrb r0, [r0]\n\ + lsrs r0, 4\n\ + bl BattleAI_SetupAIData\n\ + b _08130D76\n\ + .pool\n\ +_08130D70:\n\ + movs r0, 0xF\n\ + bl BattleAI_SetupAIData\n\ +_08130D76:\n\ + ldr r0, =gBankTarget\n\ + mov r1, r8\n\ + strb r1, [r0]\n\ + movs r1, 0x1\n\ + mov r2, r8\n\ + ands r2, r1\n\ + ldr r0, =sBank_AI\n\ + ldrb r0, [r0]\n\ + ands r1, r0\n\ + cmp r2, r1\n\ + beq _08130D90\n\ + bl RecordLastUsedMoveByTarget\n\ +_08130D90:\n\ + ldr r2, =gBattleResources\n\ + ldr r0, [r2]\n\ + ldr r0, [r0, 0x14]\n\ + movs r1, 0\n\ + strb r1, [r0, 0x11]\n\ + ldr r0, [r2]\n\ + ldr r0, [r0, 0x14]\n\ + strb r1, [r0, 0x1]\n\ + ldr r0, [r2]\n\ + ldr r0, [r0, 0x14]\n\ + ldr r4, [r0, 0xC]\n\ + mov r9, r2\n\ + cmp r4, 0\n\ + beq _08130DD8\n\ + mov r5, r9\n\ + movs r6, 0\n\ +_08130DB0:\n\ + movs r0, 0x1\n\ + ands r0, r4\n\ + cmp r0, 0\n\ + beq _08130DC2\n\ + ldr r0, [r5]\n\ + ldr r0, [r0, 0x14]\n\ + strb r6, [r0]\n\ + bl BattleAI_DoAIProcessing\n\ +_08130DC2:\n\ + asrs r4, 1\n\ + ldr r0, [r5]\n\ + ldr r1, [r0, 0x14]\n\ + ldrb r0, [r1, 0x11]\n\ + adds r0, 0x1\n\ + strb r0, [r1, 0x11]\n\ + ldr r0, [r5]\n\ + ldr r0, [r0, 0x14]\n\ + strb r6, [r0, 0x1]\n\ + cmp r4, 0\n\ + bne _08130DB0\n\ +_08130DD8:\n\ + mov r2, r9\n\ + ldr r0, [r2]\n\ + ldr r3, [r0, 0x14]\n\ + ldrb r1, [r3, 0x10]\n\ + movs r0, 0x2\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _08130DFC\n\ + movs r0, 0x4\n\ + ldr r7, [sp, 0x20]\n\ + strb r0, [r7]\n\ + b _08130EAE\n\ + .pool\n\ +_08130DFC:\n\ + movs r0, 0x4\n\ + ands r0, r1\n\ + lsls r0, 24\n\ + lsrs r2, r0, 24\n\ + cmp r2, 0\n\ + beq _08130E10\n\ + movs r0, 0x5\n\ + ldr r1, [sp, 0x20]\n\ + strb r0, [r1]\n\ + b _08130EAE\n\ +_08130E10:\n\ + add r1, sp, 0x10\n\ + ldrb r0, [r3, 0x4]\n\ + strb r0, [r1]\n\ + add r0, sp, 0x14\n\ + strb r2, [r0]\n\ + movs r5, 0x1\n\ + movs r3, 0x1\n\ + adds r6, r1, 0\n\ + ldr r0, =sBank_AI\n\ + ldrb r1, [r0]\n\ + movs r0, 0x58\n\ + muls r0, r1\n\ + ldr r2, =gBattleMons + 0xC\n\ + adds r0, r2\n\ + adds r4, r0, 0x2\n\ + add r7, sp, 0x14\n\ +_08130E30:\n\ + ldrh r0, [r4]\n\ + cmp r0, 0\n\ + beq _08130E72\n\ + ldrb r1, [r6]\n\ + mov r2, r9\n\ + ldr r0, [r2]\n\ + ldr r0, [r0, 0x14]\n\ + adds r0, 0x4\n\ + adds r2, r0, r3\n\ + movs r0, 0\n\ + ldrsb r0, [r2, r0]\n\ + cmp r1, r0\n\ + bne _08130E56\n\ + adds r0, r6, r5\n\ + ldrb r1, [r2]\n\ + strb r1, [r0]\n\ + adds r0, r7, r5\n\ + strb r3, [r0]\n\ + adds r5, 0x1\n\ +_08130E56:\n\ + ldrb r1, [r6]\n\ + mov r2, r9\n\ + ldr r0, [r2]\n\ + ldr r0, [r0, 0x14]\n\ + adds r0, 0x4\n\ + adds r2, r0, r3\n\ + movs r0, 0\n\ + ldrsb r0, [r2, r0]\n\ + cmp r1, r0\n\ + bge _08130E72\n\ + ldrb r0, [r2]\n\ + strb r0, [r6]\n\ + strb r3, [r7]\n\ + movs r5, 0x1\n\ +_08130E72:\n\ + adds r4, 0x2\n\ + adds r3, 0x1\n\ + cmp r3, 0x3\n\ + ble _08130E30\n\ + bl Random\n\ + lsls r0, 16\n\ + lsrs r0, 16\n\ + adds r1, r5, 0\n\ + bl __modsi3\n\ + add r0, sp\n\ + adds r0, 0x14\n\ + ldrb r0, [r0]\n\ + ldr r7, [sp, 0x20]\n\ + strb r0, [r7]\n\ + ldrb r2, [r6]\n\ + mov r0, r10\n\ + strh r2, [r0]\n\ + ldr r0, =sBank_AI\n\ + ldrb r1, [r0]\n\ + movs r0, 0x2\n\ + eors r0, r1\n\ + cmp r8, r0\n\ + bne _08130EAE\n\ + cmp r2, 0x63\n\ + bgt _08130EAE\n\ + ldr r0, =0x0000ffff\n\ + mov r1, r10\n\ + strh r0, [r1]\n\ +_08130EAE:\n\ + ldr r2, [sp, 0x20]\n\ + adds r2, 0x1\n\ + str r2, [sp, 0x20]\n\ + movs r7, 0x2\n\ + add r10, r7\n\ + movs r0, 0x1\n\ + add r8, r0\n\ + mov r1, r8\n\ + cmp r1, 0x3\n\ + bgt _08130EC4\n\ + b _08130D14\n\ +_08130EC4:\n\ + mov r0, sp\n\ + ldrh r5, [r0]\n\ + movs r0, 0\n\ + ldr r2, [sp, 0x18]\n\ + strb r0, [r2]\n\ + movs r4, 0x1\n\ + mov r8, r4\n\ + ldr r6, =gBankTarget\n\ + ldr r3, [sp, 0x18]\n\ + mov r1, sp\n\ + adds r1, 0x2\n\ +_08130EDA:\n\ + lsls r0, r5, 16\n\ + asrs r2, r0, 16\n\ + movs r7, 0\n\ + ldrsh r0, [r1, r7]\n\ + cmp r2, r0\n\ + bne _08130EEE\n\ + adds r0, r3, r4\n\ + mov r7, r8\n\ + strb r7, [r0]\n\ + adds r4, 0x1\n\ +_08130EEE:\n\ + movs r7, 0\n\ + ldrsh r0, [r1, r7]\n\ + cmp r2, r0\n\ + bge _08130EFE\n\ + ldrh r5, [r1]\n\ + mov r0, r8\n\ + strb r0, [r3]\n\ + movs r4, 0x1\n\ +_08130EFE:\n\ + adds r1, 0x2\n\ + movs r2, 0x1\n\ + add r8, r2\n\ + mov r7, r8\n\ + cmp r7, 0x3\n\ + ble _08130EDA\n\ + bl Random\n\ + lsls r0, 16\n\ + lsrs r0, 16\n\ + adds r1, r4, 0\n\ + bl __modsi3\n\ + ldr r1, [sp, 0x18]\n\ + adds r0, r1, r0\n\ + ldrb r0, [r0]\n\ + strb r0, [r6]\n\ + ldrb r0, [r6]\n\ + ldr r2, [sp, 0x1C]\n\ + adds r0, r2, r0\n\ + ldrb r0, [r0]\n\ + add sp, 0x24\n\ + pop {r3-r5}\n\ + mov r8, r3\n\ + mov r9, r4\n\ + mov r10, r5\n\ + pop {r4-r7}\n\ + pop {r1}\n\ + bx r1\n\ + .pool\n\ + .syntax divided\n"); +} +#endif + +static void BattleAI_DoAIProcessing(void) +{ + while (AI_THINKING_STRUCT->aiState != AIState_FinishedProcessing) + { + switch (AI_THINKING_STRUCT->aiState) + { + case AIState_DoNotProcess: //Needed to match. + break; + case AIState_SettingUp: + gAIScriptPtr = gBattleAI_ScriptsTable[AI_THINKING_STRUCT->aiLogicId]; // set AI ptr to logic ID. + if (gBattleMons[sBank_AI].pp[AI_THINKING_STRUCT->movesetIndex] == 0) + { + AI_THINKING_STRUCT->moveConsidered = 0; + } + else + { + AI_THINKING_STRUCT->moveConsidered = gBattleMons[sBank_AI].moves[AI_THINKING_STRUCT->movesetIndex]; + } + AI_THINKING_STRUCT->aiState++; + break; + case AIState_Processing: + if (AI_THINKING_STRUCT->moveConsidered != 0) + sBattleAICmdTable[*gAIScriptPtr](); // run AI command. + else + { + AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] = 0; + AI_THINKING_STRUCT->aiAction |= AI_ACTION_DONE; + } + if (AI_THINKING_STRUCT->aiAction & AI_ACTION_DONE) + { + AI_THINKING_STRUCT->movesetIndex++; + + if (AI_THINKING_STRUCT->movesetIndex < 4 && !(AI_THINKING_STRUCT->aiAction & AI_ACTION_DO_NOT_ATTACK)) + AI_THINKING_STRUCT->aiState = AIState_SettingUp; + else + AI_THINKING_STRUCT->aiState++; + + AI_THINKING_STRUCT->aiAction &= ~(AI_ACTION_DONE); + } + break; + } + } +} + +static void RecordLastUsedMoveByTarget(void) +{ + s32 i; + + for (i = 0; i < 4; i++) + { + if (gBattleResources->battleHistory->usedMoves[gBankTarget].moves[i] == gLastUsedMovesByBanks[gBankTarget]) + break; + if (gBattleResources->battleHistory->usedMoves[gBankTarget].moves[i] != gLastUsedMovesByBanks[gBankTarget] //HACK: This redundant condition is a hack to make the asm match. + && gBattleResources->battleHistory->usedMoves[gBankTarget].moves[i] == 0) + { + gBattleResources->battleHistory->usedMoves[gBankTarget].moves[i] = gLastUsedMovesByBanks[gBankTarget]; + break; + } + } +} + +void ClearBankMoveHistory(u8 bank) +{ + s32 i; + + for (i = 0; i < 4; i++) + gBattleResources->battleHistory->usedMoves[bank].moves[i] = 0; +} + +void RecordAbilityBattle(u8 bank, u8 abilityId) +{ + gBattleResources->battleHistory->abilities[bank] = abilityId; +} + +void ClearBankAbilityHistory(u8 bank) +{ + gBattleResources->battleHistory->abilities[bank] = 0; +} + +void RecordItemEffectBattle(u8 bank, u8 itemEffect) +{ + gBattleResources->battleHistory->itemEffects[bank] = itemEffect; +} + +void ClearBankItemEffectHistory(u8 bank) +{ + gBattleResources->battleHistory->itemEffects[bank] = 0; +} + +static void BattleAICmd_if_random_less_than(void) +{ + u16 random = Random(); + + if (random % 256 < gAIScriptPtr[1]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_if_random_greater_than(void) +{ + u16 random = Random(); + + if (random % 256 > gAIScriptPtr[1]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_if_random_equal(void) +{ + u16 random = Random(); + + if (random % 256 == gAIScriptPtr[1]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_if_random_not_equal(void) +{ + u16 random = Random(); + + if (random % 256 != gAIScriptPtr[1]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_score(void) +{ + AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] += gAIScriptPtr[1]; // add the result to the array of the move consider's score. + + if (AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] < 0) // if the score is negative, flatten it to 0. + AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] = 0; + + gAIScriptPtr += 2; // AI return. +} + +static void BattleAICmd_if_hp_less_than(void) +{ + u16 index; + + if (gAIScriptPtr[1] == AI_USER) + index = sBank_AI; + else + index = gBankTarget; + + if ((u32)(100 * gBattleMons[index].hp / gBattleMons[index].maxHP) < gAIScriptPtr[2]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); + else + gAIScriptPtr += 7; +} + +static void BattleAICmd_if_hp_more_than(void) +{ + u16 index; + + if (gAIScriptPtr[1] == AI_USER) + index = sBank_AI; + else + index = gBankTarget; + + if ((u32)(100 * gBattleMons[index].hp / gBattleMons[index].maxHP) > gAIScriptPtr[2]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); + else + gAIScriptPtr += 7; +} + +static void BattleAICmd_if_hp_equal(void) +{ + u16 index; + + if (gAIScriptPtr[1] == AI_USER) + index = sBank_AI; + else + index = gBankTarget; + + if ((u32)(100 * gBattleMons[index].hp / gBattleMons[index].maxHP) == gAIScriptPtr[2]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); + else + gAIScriptPtr += 7; +} + +static void BattleAICmd_if_hp_not_equal(void) +{ + u16 index; + + if (gAIScriptPtr[1] == AI_USER) + index = sBank_AI; + else + index = gBankTarget; + + if ((u32)(100 * gBattleMons[index].hp / gBattleMons[index].maxHP) != gAIScriptPtr[2]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); + else + gAIScriptPtr += 7; +} + +static void BattleAICmd_if_status(void) +{ + u16 index; + u32 arg; + + if (gAIScriptPtr[1] == AI_USER) + index = sBank_AI; + else + index = gBankTarget; + + arg = AIScriptRead32(gAIScriptPtr + 2); + + if ((gBattleMons[index].status1 & arg) != 0) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); + else + gAIScriptPtr += 10; +} + +static void BattleAICmd_if_not_status(void) +{ + u16 index; + u32 arg; + + if (gAIScriptPtr[1] == AI_USER) + index = sBank_AI; + else + index = gBankTarget; + + arg = AIScriptRead32(gAIScriptPtr + 2); + + if ((gBattleMons[index].status1 & arg) == 0) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); + else + gAIScriptPtr += 10; +} + +static void BattleAICmd_if_status2(void) +{ + u16 index; + u32 arg; + + if (gAIScriptPtr[1] == AI_USER) + index = sBank_AI; + else + index = gBankTarget; + + arg = AIScriptRead32(gAIScriptPtr + 2); + + if ((gBattleMons[index].status2 & arg) != 0) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); + else + gAIScriptPtr += 10; +} + +static void BattleAICmd_if_not_status2(void) +{ + u16 index; + u32 arg; + + if (gAIScriptPtr[1] == AI_USER) + index = sBank_AI; + else + index = gBankTarget; + + arg = AIScriptRead32(gAIScriptPtr + 2); + + if ((gBattleMons[index].status2 & arg) == 0) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); + else + gAIScriptPtr += 10; +} + +static void BattleAICmd_if_status3(void) +{ + u16 index; + u32 arg; + + if (gAIScriptPtr[1] == AI_USER) + index = sBank_AI; + else + index = gBankTarget; + + arg = AIScriptRead32(gAIScriptPtr + 2); + + if ((gStatuses3[index] & arg) != 0) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); + else + gAIScriptPtr += 10; +} + +static void BattleAICmd_if_not_status3(void) +{ + u16 index; + u32 arg; + + if (gAIScriptPtr[1] == AI_USER) + index = sBank_AI; + else + index = gBankTarget; + + arg = AIScriptRead32(gAIScriptPtr + 2); + + if ((gStatuses3[index] & arg) == 0) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); + else + gAIScriptPtr += 10; +} + +static void BattleAICmd_if_side_affecting(void) +{ + u16 index; + u32 arg1, arg2; + + if (gAIScriptPtr[1] == AI_USER) + index = sBank_AI; + else + index = gBankTarget; + + arg1 = GetBankIdentity(index) & 1; + arg2 = AIScriptRead32(gAIScriptPtr + 2); + + if ((gSideAffecting[arg1] & arg2) != 0) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); + else + gAIScriptPtr += 10; +} + +static void BattleAICmd_if_not_side_affecting(void) +{ + u16 index; + u32 arg1, arg2; + + if (gAIScriptPtr[1] == AI_USER) + index = sBank_AI; + else + index = gBankTarget; + + arg1 = GetBankIdentity(index) & 1; + arg2 = AIScriptRead32(gAIScriptPtr + 2); + + if ((gSideAffecting[arg1] & arg2) == 0) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); + else + gAIScriptPtr += 10; +} + +static void BattleAICmd_if_less_than(void) +{ + if (AI_THINKING_STRUCT->funcResult < gAIScriptPtr[1]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_if_more_than(void) +{ + if (AI_THINKING_STRUCT->funcResult > gAIScriptPtr[1]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_if_equal(void) +{ + if (AI_THINKING_STRUCT->funcResult == gAIScriptPtr[1]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_if_not_equal(void) +{ + if (AI_THINKING_STRUCT->funcResult != gAIScriptPtr[1]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_if_less_than_32(void) +{ + u8 *temp = AIScriptReadPtr(gAIScriptPtr + 1); + + if (AI_THINKING_STRUCT->funcResult < *temp) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); + else + gAIScriptPtr += 9; +} + +static void BattleAICmd_if_more_than_32(void) +{ + u8 *temp = AIScriptReadPtr(gAIScriptPtr + 1); + + if (AI_THINKING_STRUCT->funcResult > *temp) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); + else + gAIScriptPtr += 9; +} + +static void BattleAICmd_if_equal_32(void) +{ + u8 *temp = AIScriptReadPtr(gAIScriptPtr + 1); + + if (AI_THINKING_STRUCT->funcResult == *temp) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); + else + gAIScriptPtr += 9; +} + +static void BattleAICmd_if_not_equal_32(void) +{ + u8 *temp = AIScriptReadPtr(gAIScriptPtr + 1); + + if (AI_THINKING_STRUCT->funcResult != *temp) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); + else + gAIScriptPtr += 9; +} + +static void BattleAICmd_if_move(void) +{ + u16 move = AIScriptRead16(gAIScriptPtr + 1); + + if (AI_THINKING_STRUCT->moveConsidered == move) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); + else + gAIScriptPtr += 7; +} + +static void BattleAICmd_if_not_move(void) +{ + u16 move = AIScriptRead16(gAIScriptPtr + 1); + + if (AI_THINKING_STRUCT->moveConsidered != move) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); + else + gAIScriptPtr += 7; +} + +static void BattleAICmd_if_in_bytes(void) +{ + u8 *ptr = AIScriptReadPtr(gAIScriptPtr + 1); + + while (*ptr != 0xFF) + { + if (AI_THINKING_STRUCT->funcResult == *ptr) + { + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); + return; + } + ptr++; + } + gAIScriptPtr += 9; +} + +static void BattleAICmd_if_not_in_bytes(void) +{ + u8 *ptr = AIScriptReadPtr(gAIScriptPtr + 1); + + while (*ptr != 0xFF) + { + if (AI_THINKING_STRUCT->funcResult == *ptr) + { + gAIScriptPtr += 9; + return; + } + ptr++; + } + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); +} + +static void BattleAICmd_if_in_words(void) +{ + u16 *ptr = (u16 *)AIScriptReadPtr(gAIScriptPtr + 1); + + while (*ptr != 0xFFFF) + { + if (AI_THINKING_STRUCT->funcResult == *ptr) + { + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); + return; + } + ptr++; + } + gAIScriptPtr += 9; +} + +static void BattleAICmd_if_not_in_words(void) +{ + u16 *ptr = (u16 *)AIScriptReadPtr(gAIScriptPtr + 1); + + while (*ptr != 0xFFFF) + { + if (AI_THINKING_STRUCT->funcResult == *ptr) + { + gAIScriptPtr += 9; + return; + } + ptr++; + } + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); +} + +static void BattleAICmd_if_user_can_damage(void) +{ + s32 i; + + for (i = 0; i < 4; i++) + { + if (gBattleMons[sBank_AI].moves[i] != 0 + && gBattleMoves[gBattleMons[sBank_AI].moves[i]].power != 0) + break; + } + if (i == 4) + gAIScriptPtr += 5; + else + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); +} + +static void BattleAICmd_if_user_cant_damage(void) +{ + s32 i; + + for (i = 0; i < 4; i++) + { + if (gBattleMons[sBank_AI].moves[i] != 0 + && gBattleMoves[gBattleMons[sBank_AI].moves[i]].power != 0) + break; + } + if (i != 4) + gAIScriptPtr += 5; + else + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); +} + +static void BattleAICmd_get_turn_count(void) +{ + AI_THINKING_STRUCT->funcResult = gBattleResults.battleTurnCounter; + gAIScriptPtr += 1; +} + +static void BattleAICmd_get_type(void) +{ + u8 typeVar = gAIScriptPtr[1]; + + switch (typeVar) + { + case 1: // player primary type + AI_THINKING_STRUCT->funcResult = gBattleMons[sBank_AI].type1; + break; + case 0: // enemy primary type + AI_THINKING_STRUCT->funcResult = gBattleMons[gBankTarget].type1; + break; + case 3: // player secondary type + AI_THINKING_STRUCT->funcResult = gBattleMons[sBank_AI].type2; + break; + case 2: // enemy secondary type + AI_THINKING_STRUCT->funcResult = gBattleMons[gBankTarget].type2; + break; + case 4: // type of move being pointed to + AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->moveConsidered].type; + break; + } + gAIScriptPtr += 2; +} + +static u8 BattleAI_GetWantedBank(u8 index) +{ + switch (index) + { + case AI_USER: + return sBank_AI; + case AI_TARGET: + default: + return gBankTarget; + case AI_USER_PARTNER: + return sBank_AI ^ 2; + case AI_TARGET_PARTNER: + return gBankTarget ^ 2; + } +} + +static void BattleAICmd_is_of_type(void) +{ + u8 bank = BattleAI_GetWantedBank(gAIScriptPtr[1]); + + if(gBattleMons[bank].type1 == gAIScriptPtr[2] || gBattleMons[bank].type2 == gAIScriptPtr[2]) + { + AI_THINKING_STRUCT->funcResult = 1; + } + else + { + AI_THINKING_STRUCT->funcResult = 0; + } + + gAIScriptPtr += 3; +} + +static void BattleAICmd_get_last_used_bank_move_power(void) +{ + AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power; + gAIScriptPtr += 1; +} + +__attribute__((naked)) // not even going to try. if it doesnt match in ruby, it wont match in emerald (yet). +static void BattleAICmd_is_most_powerful_move(void) +{ + asm(".syntax unified\n\ + push {r4-r7,lr}\n\ + mov r7, r10\n\ + mov r6, r9\n\ + mov r5, r8\n\ + push {r5-r7}\n\ + sub sp, 0x14\n\ + movs r3, 0\n\ + ldr r0, =sDiscouragedPowerfulMoveEffects\n\ + ldrh r1, [r0]\n\ + ldr r5, =0x0000ffff\n\ + ldr r6, =gBattleMoves\n\ + ldr r2, =gBattleResources\n\ + cmp r1, r5\n\ + beq _08131F86\n\ + ldr r0, [r2]\n\ + ldr r0, [r0, 0x14]\n\ + ldrh r1, [r0, 0x2]\n\ + lsls r0, r1, 1\n\ + adds r0, r1\n\ + lsls r0, 2\n\ + adds r0, r6\n\ + ldrb r4, [r0]\n\ + ldr r1, =sDiscouragedPowerfulMoveEffects\n\ +_08131F76:\n\ + ldrh r0, [r1]\n\ + cmp r4, r0\n\ + beq _08131F86\n\ + adds r1, 0x2\n\ + adds r3, 0x1\n\ + ldrh r0, [r1]\n\ + cmp r0, r5\n\ + bne _08131F76\n\ +_08131F86:\n\ + ldr r0, [r2]\n\ + ldr r0, [r0, 0x14]\n\ + ldrh r1, [r0, 0x2]\n\ + lsls r0, r1, 1\n\ + adds r0, r1\n\ + lsls r0, 2\n\ + adds r0, r6\n\ + ldrb r0, [r0, 0x1]\n\ + cmp r0, 0x1\n\ + bhi _08131F9C\n\ + b _08132126\n\ +_08131F9C:\n\ + lsls r0, r3, 1\n\ + ldr r1, =sDiscouragedPowerfulMoveEffects\n\ + adds r0, r1\n\ + ldrh r3, [r0]\n\ + ldr r0, =0x0000ffff\n\ + cmp r3, r0\n\ + beq _08131FAC\n\ + b _08132126\n\ +_08131FAC:\n\ + ldr r0, =gDynamicBasePower\n\ + movs r1, 0\n\ + strh r1, [r0]\n\ + ldr r0, =gBattleStruct\n\ + ldr r0, [r0]\n\ + strb r1, [r0, 0x13]\n\ + ldr r0, =gBattleScripting\n\ + movs r2, 0x1\n\ + strb r2, [r0, 0xE]\n\ + ldr r0, =gBattleMoveFlags\n\ + strb r1, [r0]\n\ + ldr r0, =gCritMultiplier\n\ + strb r2, [r0]\n\ + movs r6, 0\n\ + mov r9, r3\n\ + ldr r2, =sDiscouragedPowerfulMoveEffects\n\ + ldrh r2, [r2]\n\ + str r2, [sp, 0x10]\n\ +_08131FD0:\n\ + movs r3, 0\n\ + ldr r5, =gBattleMons\n\ + lsls r4, r6, 1\n\ + ldr r7, =sBank_AI\n\ + lsls r0, r6, 2\n\ + mov r8, r0\n\ + adds r1, r6, 0x1\n\ + mov r10, r1\n\ + ldr r2, [sp, 0x10]\n\ + cmp r2, r9\n\ + beq _08132014\n\ + ldr r2, =gBattleMoves\n\ + ldrb r1, [r7]\n\ + movs r0, 0x58\n\ + muls r0, r1\n\ + adds r0, r4, r0\n\ + adds r1, r5, 0\n\ + adds r1, 0xC\n\ + adds r0, r1\n\ + ldrh r1, [r0]\n\ + lsls r0, r1, 1\n\ + adds r0, r1\n\ + lsls r0, 2\n\ + adds r0, r2\n\ + ldrb r2, [r0]\n\ + ldr r1, =sDiscouragedPowerfulMoveEffects\n\ +_08132004:\n\ + ldrh r0, [r1]\n\ + cmp r2, r0\n\ + beq _08132014\n\ + adds r1, 0x2\n\ + adds r3, 0x1\n\ + ldrh r0, [r1]\n\ + cmp r0, r9\n\ + bne _08132004\n\ +_08132014:\n\ + ldrb r1, [r7]\n\ + movs r0, 0x58\n\ + muls r0, r1\n\ + adds r0, r4, r0\n\ + adds r1, r5, 0\n\ + adds r1, 0xC\n\ + adds r1, r0, r1\n\ + ldrh r0, [r1]\n\ + cmp r0, 0\n\ + beq _081320C0\n\ + lsls r0, r3, 1\n\ + ldr r2, =sDiscouragedPowerfulMoveEffects\n\ + adds r0, r2\n\ + ldrh r0, [r0]\n\ + cmp r0, r9\n\ + bne _081320C0\n\ + ldr r0, =gBattleMoves\n\ + ldrh r2, [r1]\n\ + lsls r1, r2, 1\n\ + adds r1, r2\n\ + lsls r1, 2\n\ + adds r1, r0\n\ + ldrb r0, [r1, 0x1]\n\ + cmp r0, 0x1\n\ + bls _081320C0\n\ + ldr r5, =gCurrentMove\n\ + strh r2, [r5]\n\ + ldrb r0, [r7]\n\ + ldr r4, =gBankTarget\n\ + ldrb r1, [r4]\n\ + bl AI_CalcDmg\n\ + ldrh r0, [r5]\n\ + ldrb r1, [r7]\n\ + ldrb r2, [r4]\n\ + bl TypeCalc\n\ + mov r4, sp\n\ + add r4, r8\n\ + ldr r2, =gBattleMoveDamage\n\ + ldr r0, =gBattleResources\n\ + ldr r0, [r0]\n\ + ldr r0, [r0, 0x14]\n\ + adds r0, 0x18\n\ + adds r0, r6\n\ + ldrb r1, [r0]\n\ + ldr r0, [r2]\n\ + muls r0, r1\n\ + movs r1, 0x64\n\ + bl __divsi3\n\ + str r0, [r4]\n\ + cmp r0, 0\n\ + bne _081320C8\n\ + movs r0, 0x1\n\ + str r0, [r4]\n\ + b _081320C8\n\ + .pool\n\ +_081320C0:\n\ + mov r1, sp\n\ + add r1, r8\n\ + movs r0, 0\n\ + str r0, [r1]\n\ +_081320C8:\n\ + mov r6, r10\n\ + cmp r6, 0x3\n\ + bgt _081320D0\n\ + b _08131FD0\n\ +_081320D0:\n\ + movs r6, 0\n\ + ldr r2, =gBattleResources\n\ + ldr r0, [r2]\n\ + ldr r0, [r0, 0x14]\n\ + ldrb r0, [r0, 0x1]\n\ + lsls r0, 2\n\ + add r0, sp\n\ + ldr r1, [sp]\n\ + ldr r0, [r0]\n\ + ldr r5, =gAIScriptPtr\n\ + cmp r1, r0\n\ + bgt _08132106\n\ + adds r4, r2, 0\n\ + mov r3, sp\n\ +_081320EC:\n\ + adds r3, 0x4\n\ + adds r6, 0x1\n\ + cmp r6, 0x3\n\ + bgt _08132106\n\ + ldr r0, [r4]\n\ + ldr r0, [r0, 0x14]\n\ + ldrb r0, [r0, 0x1]\n\ + lsls r0, 2\n\ + add r0, sp\n\ + ldr r1, [r3]\n\ + ldr r0, [r0]\n\ + cmp r1, r0\n\ + ble _081320EC\n\ +_08132106:\n\ + cmp r6, 0x4\n\ + bne _0813211C\n\ + ldr r0, [r2]\n\ + ldr r1, [r0, 0x14]\n\ + movs r0, 0x2\n\ + str r0, [r1, 0x8]\n\ + b _08132130\n\ + .pool\n\ +_0813211C:\n\ + ldr r0, [r2]\n\ + ldr r1, [r0, 0x14]\n\ + movs r0, 0x1\n\ + str r0, [r1, 0x8]\n\ + b _08132130\n\ +_08132126:\n\ + ldr r0, [r2]\n\ + ldr r1, [r0, 0x14]\n\ + movs r0, 0\n\ + str r0, [r1, 0x8]\n\ + ldr r5, =gAIScriptPtr\n\ +_08132130:\n\ + ldr r0, [r5]\n\ + adds r0, 0x1\n\ + str r0, [r5]\n\ + add sp, 0x14\n\ + pop {r3-r5}\n\ + mov r8, r3\n\ + mov r9, r4\n\ + mov r10, r5\n\ + pop {r4-r7}\n\ + pop {r0}\n\ + bx r0\n\ + .pool\n\ + .syntax divided"); +} + +static void BattleAICmd_get_last_used_bank_move(void) +{ + if (gAIScriptPtr[1] == AI_USER) + AI_THINKING_STRUCT->funcResult = gLastUsedMovesByBanks[sBank_AI]; + else + AI_THINKING_STRUCT->funcResult = gLastUsedMovesByBanks[gBankTarget]; + + gAIScriptPtr += 2; +} + +static void BattleAICmd_if_arg_equal(void) +{ + if (gAIScriptPtr[1] == AI_THINKING_STRUCT->funcResult) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_if_arg_not_equal(void) +{ + if (gAIScriptPtr[1] != AI_THINKING_STRUCT->funcResult) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_if_would_go_first(void) +{ + if (b_first_side(sBank_AI, gBankTarget, 1) == gAIScriptPtr[1]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_if_would_not_go_first(void) +{ + if (b_first_side(sBank_AI, gBankTarget, 1) != gAIScriptPtr[1]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_nullsub_2A(void) +{ +} + +static void BattleAICmd_nullsub_2B(void) +{ +} + +static void BattleAICmd_count_alive_pokemon(void) +{ + u8 index; + u8 bankOnField1, bankOnField2; + struct Pokemon *party; + int i; + + AI_THINKING_STRUCT->funcResult = 0; + + if (gAIScriptPtr[1] == AI_USER) + index = sBank_AI; + else + index = gBankTarget; + + if (GetBankSide(index) == 0) + party = gPlayerParty; + else + party = gEnemyParty; + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + u32 status; + bankOnField1 = gBattlePartyID[index]; + status = GetBankIdentity(index) ^ 2; + bankOnField2 = gBattlePartyID[GetBankByIdentity(status)]; + } + else // in singles there's only one bank by side + { + bankOnField1 = gBattlePartyID[index]; + bankOnField2 = gBattlePartyID[index]; + } + + for (i = 0; i < 6; i++) + { + if (i != bankOnField1 && i != bankOnField2 + && GetMonData(&party[i], MON_DATA_HP) != 0 + && GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_NONE + && GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_EGG) + { + AI_THINKING_STRUCT->funcResult++; + } + } + + gAIScriptPtr += 2; +} + +static void BattleAICmd_get_considered_move(void) +{ + AI_THINKING_STRUCT->funcResult = AI_THINKING_STRUCT->moveConsidered; + gAIScriptPtr += 1; +} + +static void BattleAICmd_get_considered_move_effect(void) +{ + AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->moveConsidered].effect; + gAIScriptPtr += 1; +} + +static void BattleAICmd_get_ability(void) +{ + u8 index; + + if (gAIScriptPtr[1] == AI_USER) + index = sBank_AI; + else + index = gBankTarget; + + if(gActiveBank != index) + { + if(BATTLE_HISTORY->abilities[index] != 0) + { + AI_THINKING_STRUCT->funcResult = BATTLE_HISTORY->abilities[index]; + gAIScriptPtr += 2; + return; + } + + // abilities that prevent fleeing. + if (gBattleMons[index].ability == ABILITY_SHADOW_TAG + || gBattleMons[index].ability == ABILITY_MAGNET_PULL + || gBattleMons[index].ability == ABILITY_ARENA_TRAP) + { + AI_THINKING_STRUCT->funcResult = gBattleMons[index].ability; + gAIScriptPtr += 2; + return; + } + + if (gBaseStats[gBattleMons[index].species].ability1 != ABILITY_NONE) + { + if (gBaseStats[gBattleMons[index].species].ability2 != ABILITY_NONE) + { + // AI has no knowledge of opponent, so it guesses which ability. + if (Random() & 1) + { + AI_THINKING_STRUCT->funcResult = gBaseStats[gBattleMons[index].species].ability1; + } + else + { + AI_THINKING_STRUCT->funcResult = gBaseStats[gBattleMons[index].species].ability2; + } + } + else + { + AI_THINKING_STRUCT->funcResult = gBaseStats[gBattleMons[index].species].ability1; // it's definitely ability 1. + } + } + else + { + AI_THINKING_STRUCT->funcResult = gBaseStats[gBattleMons[index].species].ability2; // AI cant actually reach this part since every mon has at least 1 ability. + } + } + else + { + // The AI knows its own ability. + AI_THINKING_STRUCT->funcResult = gBattleMons[index].ability; + } + gAIScriptPtr += 2; +} + +#ifdef NONMATCHING +static void BattleAICmd_check_ability(void) +{ + u8 bank = BattleAI_GetWantedBank(gAIScriptPtr[1]); + u8 ability = gAIScriptPtr[2]; + + if (gAIScriptPtr[1] == AI_TARGET || gAIScriptPtr[1] == AI_TARGET_PARTNER) + { + if (BATTLE_HISTORY->abilities[bank] != 0) + { + ability = BATTLE_HISTORY->abilities[bank]; + AI_THINKING_STRUCT->funcResult = ability; + } + // abilities that prevent fleeing. + else if (gBattleMons[bank].ability == ABILITY_SHADOW_TAG + || gBattleMons[bank].ability == ABILITY_MAGNET_PULL + || gBattleMons[bank].ability == ABILITY_ARENA_TRAP) + { + ability = gBattleMons[bank].ability; + } + else if (gBaseStats[gBattleMons[bank].species].ability1 != ABILITY_NONE) + { + if (gBaseStats[gBattleMons[bank].species].ability2 != ABILITY_NONE) + { + if (gBaseStats[gBattleMons[bank].species].ability1 != ability + && gBaseStats[gBattleMons[bank].species].ability2 != ability) + { + ability = gBaseStats[gBattleMons[bank].species].ability1; + } + else + ability = 0; + } + else + { + ability = gBaseStats[gBattleMons[bank].species].ability1; + } + } + else + { + ability = gBaseStats[gBattleMons[bank].species].ability2; // AI cant actually reach this part since every mon has at least 1 ability. + } + } + else + { + // The AI knows its own or partner's ability. + ability = gBattleMons[bank].ability; + } + if (ability == 0) + { + AI_THINKING_STRUCT->funcResult = 2; // unable to answer + } + else if (ability == gAIScriptPtr[2]) + { + AI_THINKING_STRUCT->funcResult = 1; // pokemon has the ability we wanted to check + } + else + { + AI_THINKING_STRUCT->funcResult = 0; // pokemon doesn't have the ability we wanted to check + } + gAIScriptPtr += 3; +} +#else +__attribute__((naked)) +static void BattleAICmd_check_ability(void) +{ + asm(".syntax unified\n\ + push {r4-r6,lr}\n\ + ldr r4, =gAIScriptPtr\n\ + ldr r0, [r4]\n\ + ldrb r0, [r0, 0x1]\n\ + bl BattleAI_GetWantedBank\n\ + lsls r0, 24\n\ + lsrs r5, r0, 24\n\ + ldr r0, [r4]\n\ + ldrb r3, [r0, 0x2]\n\ + ldrb r0, [r0, 0x1]\n\ + cmp r0, 0\n\ + beq _0813253A\n\ + cmp r0, 0x2\n\ + bne _081325BC\n\ +_0813253A:\n\ + ldr r0, =gBattleResources\n\ + ldr r4, [r0]\n\ + ldr r1, [r4, 0x18]\n\ + adds r1, 0x40\n\ + adds r2, r1, r5\n\ + ldrb r1, [r2]\n\ + adds r6, r0, 0\n\ + cmp r1, 0\n\ + beq _0813255C\n\ + adds r3, r1, 0\n\ + ldr r0, [r4, 0x14]\n\ + str r3, [r0, 0x8]\n\ + b _081325CA\n\ + .pool\n\ +_0813255C:\n\ + ldr r1, =gBattleMons\n\ + movs r0, 0x58\n\ + muls r0, r5\n\ + adds r4, r0, r1\n\ + adds r0, r4, 0\n\ + adds r0, 0x20\n\ + ldrb r0, [r0]\n\ + cmp r0, 0x17\n\ + beq _08132576\n\ + cmp r0, 0x2A\n\ + beq _08132576\n\ + cmp r0, 0x47\n\ + bne _08132588\n\ +_08132576:\n\ + movs r0, 0x58\n\ + muls r0, r5\n\ + adds r0, r1\n\ + adds r0, 0x20\n\ + ldrb r3, [r0]\n\ + b _081325CA\n\ + .pool\n\ +_08132588:\n\ + ldr r2, =gBaseStats\n\ + ldrh r1, [r4]\n\ + lsls r0, r1, 3\n\ + subs r0, r1\n\ + lsls r0, 2\n\ + adds r1, r0, r2\n\ + ldrb r4, [r1, 0x16]\n\ + cmp r4, 0\n\ + beq _081325B8\n\ + ldrb r2, [r1, 0x17]\n\ + cmp r2, 0\n\ + beq _081325B4\n\ + adds r0, r3, 0\n\ + cmp r4, r0\n\ + beq _081325CE\n\ + cmp r2, r0\n\ + beq _081325CE\n\ + adds r3, r4, 0\n\ + b _081325CA\n\ + .pool\n\ +_081325B4:\n\ + ldrb r3, [r1, 0x16]\n\ + b _081325CA\n\ +_081325B8:\n\ + ldrb r3, [r1, 0x17]\n\ + b _081325CA\n\ +_081325BC:\n\ + ldr r1, =gBattleMons\n\ + movs r0, 0x58\n\ + muls r0, r5\n\ + adds r0, r1\n\ + adds r0, 0x20\n\ + ldrb r3, [r0]\n\ + ldr r6, =gBattleResources\n\ +_081325CA:\n\ + cmp r3, 0\n\ + bne _081325E8\n\ +_081325CE:\n\ + ldr r0, [r6]\n\ + ldr r1, [r0, 0x14]\n\ + movs r0, 0x2\n\ + str r0, [r1, 0x8]\n\ + ldr r2, =gAIScriptPtr\n\ + b _08132608\n\ + .pool\n\ +_081325E8:\n\ + ldr r0, =gAIScriptPtr\n\ + ldr r1, [r0]\n\ + adds r2, r0, 0\n\ + ldrb r1, [r1, 0x2]\n\ + cmp r3, r1\n\ + bne _08132600\n\ + ldr r0, [r6]\n\ + ldr r1, [r0, 0x14]\n\ + movs r0, 0x1\n\ + b _08132606\n\ + .pool\n\ +_08132600:\n\ + ldr r0, [r6]\n\ + ldr r1, [r0, 0x14]\n\ + movs r0, 0\n\ +_08132606:\n\ + str r0, [r1, 0x8]\n\ +_08132608:\n\ + ldr r0, [r2]\n\ + adds r0, 0x3\n\ + str r0, [r2]\n\ + pop {r4-r6}\n\ + pop {r0}\n\ + bx r0\n\ + .pool\n\ + .syntax divided"); +} +#endif + +static void BattleAICmd_get_highest_type_effectiveness(void) +{ + s32 i; + u8* dynamicMoveType; + + gDynamicBasePower = 0; + dynamicMoveType = &gBattleStruct->dynamicMoveType; + *dynamicMoveType = 0; + gBattleScripting.dmgMultiplier = 1; + gBattleMoveFlags = 0; + gCritMultiplier = 1; + AI_THINKING_STRUCT->funcResult = 0; + + for (i = 0; i < 4; i++) + { + gBattleMoveDamage = 40; + gCurrentMove = gBattleMons[sBank_AI].moves[i]; + + if (gCurrentMove) + { + TypeCalc(gCurrentMove, sBank_AI, gBankTarget); + + // reduce by 1/3. + if (gBattleMoveDamage == 120) + gBattleMoveDamage = 80; + if (gBattleMoveDamage == 240) + gBattleMoveDamage = 160; + if (gBattleMoveDamage == 30) + gBattleMoveDamage = 20; + if (gBattleMoveDamage == 15) + gBattleMoveDamage = 10; + + if (gBattleMoveFlags & MOVESTATUS_NOTAFFECTED) + gBattleMoveDamage = 0; + + if (AI_THINKING_STRUCT->funcResult < gBattleMoveDamage) + AI_THINKING_STRUCT->funcResult = gBattleMoveDamage; + } + } + gAIScriptPtr += 1; +} + +static void BattleAICmd_if_type_effectiveness(void) +{ + u8 damageVar; + + gDynamicBasePower = 0; + gBattleStruct->dynamicMoveType = 0; + gBattleScripting.dmgMultiplier = 1; + gBattleMoveFlags = 0; + gCritMultiplier = 1; + + gBattleMoveDamage = 40; + gCurrentMove = AI_THINKING_STRUCT->moveConsidered; + + TypeCalc(gCurrentMove, sBank_AI, gBankTarget); + + if (gBattleMoveDamage == 120) + gBattleMoveDamage = 80; + if (gBattleMoveDamage == 240) + gBattleMoveDamage = 160; + if (gBattleMoveDamage == 30) + gBattleMoveDamage = 20; + if (gBattleMoveDamage == 15) + gBattleMoveDamage = 10; + + if (gBattleMoveFlags & MOVESTATUS_NOTAFFECTED) + gBattleMoveDamage = 0; + + // store gBattleMoveDamage in a u8 variable because gAIScriptPtr[1] is a u8. + damageVar = gBattleMoveDamage; + + if (damageVar == gAIScriptPtr[1]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_nullsub_32(void) +{ +} + +static void BattleAICmd_nullsub_33(void) +{ +} + +static void BattleAICmd_if_status_in_party(void) +{ + struct Pokemon *party; + int i; + u32 statusToCompareTo; + u8 index; + + switch(gAIScriptPtr[1]) + { + case 1: + index = sBank_AI; + break; + default: + index = gBankTarget; + break; + } + + party = (GetBankSide(index) == 0) ? gPlayerParty : gEnemyParty; + + statusToCompareTo = AIScriptRead32(gAIScriptPtr + 2); + + for (i = 0; i < 6; i++) + { + u16 species = GetMonData(&party[i], MON_DATA_SPECIES); + u16 hp = GetMonData(&party[i], MON_DATA_HP); + u32 status = GetMonData(&party[i], MON_DATA_STATUS); + + if (species != SPECIES_NONE && species != SPECIES_EGG && hp != 0 && status == statusToCompareTo) + { + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); + return; + } + } + + gAIScriptPtr += 10; +} + +static void BattleAICmd_if_status_not_in_party(void) +{ + struct Pokemon *party; + int i; + u32 statusToCompareTo; + u8 index; + + switch(gAIScriptPtr[1]) + { + case 1: + index = sBank_AI; + break; + default: + index = gBankTarget; + break; + } + + party = (GetBankSide(index) == 0) ? gPlayerParty : gEnemyParty; + + statusToCompareTo = AIScriptRead32(gAIScriptPtr + 2); + + for (i = 0; i < 6; i++) + { + u16 species = GetMonData(&party[i], MON_DATA_SPECIES); + u16 hp = GetMonData(&party[i], MON_DATA_HP); + u32 status = GetMonData(&party[i], MON_DATA_STATUS); + + if (species != SPECIES_NONE && species != SPECIES_EGG && hp != 0 && status == statusToCompareTo) + { + gAIScriptPtr += 10; // still bugged in Emerald + } + } + + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); +} + +static void BattleAICmd_get_weather(void) +{ + if (gBattleWeather & WEATHER_RAIN_ANY) + AI_THINKING_STRUCT->funcResult = 1; + if (gBattleWeather & WEATHER_SANDSTORM_ANY) + AI_THINKING_STRUCT->funcResult = 2; + if (gBattleWeather & WEATHER_SUN_ANY) + AI_THINKING_STRUCT->funcResult = 0; + if (gBattleWeather & WEATHER_HAIL_ANY) + AI_THINKING_STRUCT->funcResult = 3; + + gAIScriptPtr += 1; +} + +static void BattleAICmd_if_effect(void) +{ + if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].effect == gAIScriptPtr[1]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_if_not_effect(void) +{ + if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].effect != gAIScriptPtr[1]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_if_stat_level_less_than(void) +{ + u32 bank; + + if (gAIScriptPtr[1] == AI_USER) + bank = sBank_AI; + else + bank = gBankTarget; + + if (gBattleMons[bank].statStages[gAIScriptPtr[2]] < gAIScriptPtr[3]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); + else + gAIScriptPtr += 8; +} + +static void BattleAICmd_if_stat_level_more_than(void) +{ + u32 bank; + + if (gAIScriptPtr[1] == AI_USER) + bank = sBank_AI; + else + bank = gBankTarget; + + if (gBattleMons[bank].statStages[gAIScriptPtr[2]] > gAIScriptPtr[3]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); + else + gAIScriptPtr += 8; +} + +static void BattleAICmd_if_stat_level_equal(void) +{ + u32 bank; + + if (gAIScriptPtr[1] == AI_USER) + bank = sBank_AI; + else + bank = gBankTarget; + + if (gBattleMons[bank].statStages[gAIScriptPtr[2]] == gAIScriptPtr[3]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); + else + gAIScriptPtr += 8; +} + +static void BattleAICmd_if_stat_level_not_equal(void) +{ + u32 bank; + + if (gAIScriptPtr[1] == AI_USER) + bank = sBank_AI; + else + bank = gBankTarget; + + if (gBattleMons[bank].statStages[gAIScriptPtr[2]] != gAIScriptPtr[3]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); + else + gAIScriptPtr += 8; +} + +static void BattleAICmd_if_can_faint(void) +{ + if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power < 2) + { + gAIScriptPtr += 5; + return; + } + + gDynamicBasePower = 0; + gBattleStruct->dynamicMoveType = 0; + gBattleScripting.dmgMultiplier = 1; + gBattleMoveFlags = 0; + gCritMultiplier = 1; + gCurrentMove = AI_THINKING_STRUCT->moveConsidered; + AI_CalcDmg(sBank_AI, gBankTarget); + TypeCalc(gCurrentMove, sBank_AI, gBankTarget); + + gBattleMoveDamage = gBattleMoveDamage * AI_THINKING_STRUCT->simulatedRNG[AI_THINKING_STRUCT->movesetIndex] / 100; + + // moves always do at least 1 damage. + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + + if (gBattleMons[gBankTarget].hp <= gBattleMoveDamage) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); + else + gAIScriptPtr += 5; +} + +static void BattleAICmd_if_cant_faint(void) +{ + if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power < 2) + { + gAIScriptPtr += 5; + return; + } + + gDynamicBasePower = 0; + gBattleStruct->dynamicMoveType = 0; + gBattleScripting.dmgMultiplier = 1; + gBattleMoveFlags = 0; + gCritMultiplier = 1; + gCurrentMove = AI_THINKING_STRUCT->moveConsidered; + AI_CalcDmg(sBank_AI, gBankTarget); + TypeCalc(gCurrentMove, sBank_AI, gBankTarget); + + gBattleMoveDamage = gBattleMoveDamage * AI_THINKING_STRUCT->simulatedRNG[AI_THINKING_STRUCT->movesetIndex] / 100; + + // this macro is missing the damage 0 = 1 assumption. + + if (gBattleMons[gBankTarget].hp > gBattleMoveDamage) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); + else + gAIScriptPtr += 5; +} + +static void BattleAICmd_if_has_move(void) +{ + int i; + u16 *temp_ptr = (u16 *)(gAIScriptPtr + 2); + + switch(gAIScriptPtr[1]) + { + case AI_USER: + for (i = 0; i < 4; i++) + { + if (gBattleMons[sBank_AI].moves[i] == *temp_ptr) + break; + } + if (i == 4) + { + gAIScriptPtr += 8; + return; + } + else + { + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); + return; + } + case AI_USER_PARTNER: + if (gBattleMons[sBank_AI ^ 2].hp == 0) + { + gAIScriptPtr += 8; + return; + } + else + { + for (i = 0; i < 4; i++) + { + if (gBattleMons[sBank_AI ^ 2].moves[i] == *temp_ptr) + break; + } + } + if (i == 4) + { + gAIScriptPtr += 8; + return; + } + else + { + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); + return; + } + case AI_TARGET: + case AI_TARGET_PARTNER: + for (i = 0; i < 4; i++) + { + if (BATTLE_HISTORY->usedMoves[gBankTarget].moves[i] == *temp_ptr) + break; + } + if (i == 4) + { + gAIScriptPtr += 8; + return; + } + else + { + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); + return; + } + } +} + +static void BattleAICmd_if_dont_have_move(void) +{ + int i; + u16 *temp_ptr = (u16 *)(gAIScriptPtr + 2); + + switch(gAIScriptPtr[1]) + { + case AI_USER: + case AI_USER_PARTNER: // UB: no separate check for user partner + for (i = 0; i < 4; i++) + { + if (gBattleMons[sBank_AI].moves[i] == *temp_ptr) + break; + } + if (i != 4) + { + gAIScriptPtr += 8; + return; + } + else + { + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); + return; + } + case AI_TARGET: + case AI_TARGET_PARTNER: + for (i = 0; i < 4; i++) + { + if (BATTLE_HISTORY->usedMoves[gBankTarget].moves[i] == *temp_ptr) + break; + } + if (i != 4) + { + gAIScriptPtr += 8; + return; + } + else + { + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); + return; + } + } +} + +static void BattleAICmd_if_move_effect(void) +{ + int i; + + switch (gAIScriptPtr[1]) + { + case AI_USER: + case AI_USER_PARTNER: + for (i = 0; i < 4; i++) + { + if(gBattleMons[sBank_AI].moves[i] != 0 && gBattleMoves[gBattleMons[sBank_AI].moves[i]].effect == gAIScriptPtr[2]) + break; + } + if (i == 4) + gAIScriptPtr += 7; + else + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); + break; + case AI_TARGET: + case AI_TARGET_PARTNER: + for (i = 0; i < 4; i++) + { + if (gBattleMons[sBank_AI].moves[i] != 0 && gBattleMoves[BATTLE_HISTORY->usedMoves[gBankTarget].moves[i]].effect == gAIScriptPtr[2]) + break; + } + if (i == 4) + gAIScriptPtr += 7; + else + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); + break; + } +} + +static void BattleAICmd_if_not_move_effect(void) +{ + int i; + + switch (gAIScriptPtr[1]) + { + case AI_USER: + case AI_USER_PARTNER: + for (i = 0; i < 4; i++) + { + if(gBattleMons[sBank_AI].moves[i] != 0 && gBattleMoves[gBattleMons[sBank_AI].moves[i]].effect == gAIScriptPtr[2]) + break; + } + if (i != 4) + gAIScriptPtr += 7; + else + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); + break; + case AI_TARGET: + case AI_TARGET_PARTNER: + for (i = 0; i < 4; i++) + { + if (BATTLE_HISTORY->usedMoves[gBankTarget].moves[i] && gBattleMoves[BATTLE_HISTORY->usedMoves[gBankTarget].moves[i]].effect == gAIScriptPtr[2]) + break; + } + if (i != 4) + gAIScriptPtr += 7; + else + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); + break; + } +} + +static void BattleAICmd_if_any_move_disabled_or_encored(void) +{ + u8 bank; + + if (gAIScriptPtr[1] == AI_USER) + bank = sBank_AI; + else + bank = gBankTarget; + + if (gAIScriptPtr[2] == 0) + { + if (gDisableStructs[bank].disabledMove == 0) + { + gAIScriptPtr += 7; + return; + } + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); + return; + } + else if (gAIScriptPtr[2] != 1) // ignore the macro if its not 0 or 1. + { + gAIScriptPtr += 7; + return; + } + else if (gDisableStructs[bank].encoredMove != 0) + { + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); + return; + } + gAIScriptPtr += 7; +} + +static void BattleAICmd_if_curr_move_disabled_or_encored(void) +{ + switch (gAIScriptPtr[1]) + { + case 0: + if (gDisableStructs[gActiveBank].disabledMove == AI_THINKING_STRUCT->moveConsidered) + { + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + return; + } + gAIScriptPtr += 6; + return; + case 1: + if (gDisableStructs[gActiveBank].encoredMove == AI_THINKING_STRUCT->moveConsidered) + { + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + return; + } + gAIScriptPtr += 6; + return; + default: + gAIScriptPtr += 6; + return; + } +} + +static void BattleAICmd_flee(void) +{ + AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_FLEE | AI_ACTION_DO_NOT_ATTACK); // what matters is UNK2 being enabled. +} + +static void BattleAICmd_if_random_100(void) +{ + u8 safariFleeRate = gBattleStruct->field_7B * 5; // safari flee rate, from 0-20 + + if ((u8)(Random() % 100) < safariFleeRate) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); + else + gAIScriptPtr += 5; +} + +static void BattleAICmd_watch(void) +{ + AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_WATCH | AI_ACTION_DO_NOT_ATTACK); // what matters is UNK3 being enabled. +} + +static void BattleAICmd_get_hold_effect(void) +{ + u8 bank; + u16 status; + + if (gAIScriptPtr[1] == AI_USER) + bank = sBank_AI; + else + bank = gBankTarget; + + if (gActiveBank != bank) + { + AI_THINKING_STRUCT->funcResult = ItemId_GetHoldEffect(BATTLE_HISTORY->itemEffects[bank]); + } + else + AI_THINKING_STRUCT->funcResult = ItemId_GetHoldEffect(gBattleMons[bank].item); + + gAIScriptPtr += 2; +} + +static void BattleAICmd_if_holds_item(void) +{ + u8 bank = BattleAI_GetWantedBank(gAIScriptPtr[1]); + u16 item; + u8 var1, var2; + + if ((bank & 1) == (sBank_AI & 1)) + item = gBattleMons[bank].item; + else + item = BATTLE_HISTORY->itemEffects[bank]; + + // UB: doesn't properly read an unaligned u16 + var2 = gAIScriptPtr[2]; + var1 = gAIScriptPtr[3]; + + if ((var1 | var2) == item) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); + else + gAIScriptPtr += 8; +} + +static void BattleAICmd_get_gender(void) +{ + u8 bank; + + if (gAIScriptPtr[1] == AI_USER) + bank = sBank_AI; + else + bank = gBankTarget; + + AI_THINKING_STRUCT->funcResult = GetGenderFromSpeciesAndPersonality(gBattleMons[bank].species, gBattleMons[bank].personality); + + gAIScriptPtr += 2; +} + +static void BattleAICmd_is_first_turn(void) +{ + u8 bank; + + if (gAIScriptPtr[1] == AI_USER) + bank = sBank_AI; + else + bank = gBankTarget; + + AI_THINKING_STRUCT->funcResult = gDisableStructs[bank].isFirstTurn; + + gAIScriptPtr += 2; +} + +static void BattleAICmd_get_stockpile_count(void) +{ + u8 bank; + + if (gAIScriptPtr[1] == AI_USER) + bank = sBank_AI; + else + bank = gBankTarget; + + AI_THINKING_STRUCT->funcResult = gDisableStructs[bank].stockpileCounter; + + gAIScriptPtr += 2; +} + +static void BattleAICmd_is_double_battle(void) +{ + AI_THINKING_STRUCT->funcResult = gBattleTypeFlags & BATTLE_TYPE_DOUBLE; + + gAIScriptPtr += 1; +} + +static void BattleAICmd_get_used_held_item(void) +{ + u8 bank; + + if (gAIScriptPtr[1] == AI_USER) + bank = sBank_AI; + else + bank = gBankTarget; + + // This is likely a leftover from Ruby's code and its ugly ewram access + #ifdef NONMATCHING + AI_THINKING_STRUCT->funcResult = gBattleStruct->usedHeldItems[bank]; + #else + AI_THINKING_STRUCT->funcResult = *(u8*)((u8*)(gBattleStruct) + 0xB8 + (bank * 2)); + #endif // NONMATCHING + + gAIScriptPtr += 2; +} + +static void BattleAICmd_get_move_type_from_result(void) +{ + AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->funcResult].type; + + gAIScriptPtr += 1; +} + +static void BattleAICmd_get_move_power_from_result(void) +{ + AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->funcResult].power; + + gAIScriptPtr += 1; +} + +static void BattleAICmd_get_move_effect_from_result(void) +{ + AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->funcResult].effect; + + gAIScriptPtr += 1; +} + +static void BattleAICmd_get_protect_count(void) +{ + u8 bank; + + if (gAIScriptPtr[1] == AI_USER) + bank = sBank_AI; + else + bank = gBankTarget; + + AI_THINKING_STRUCT->funcResult = gDisableStructs[bank].protectUses; + + gAIScriptPtr += 2; +} + +static void BattleAICmd_nullsub_52(void) +{ +} + +static void BattleAICmd_nullsub_53(void) +{ +} + +static void BattleAICmd_nullsub_54(void) +{ +} + +static void BattleAICmd_nullsub_55(void) +{ +} + +static void BattleAICmd_nullsub_56(void) +{ +} + +static void BattleAICmd_nullsub_57(void) +{ +} + +static void BattleAICmd_call(void) +{ + AIStackPushVar(gAIScriptPtr + 5); + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); +} + +static void BattleAICmd_jump(void) +{ + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); +} + +static void BattleAICmd_end(void) +{ + if (AIStackPop() == 0) + AI_THINKING_STRUCT->aiAction |= AI_ACTION_DONE; +} + +static void BattleAICmd_if_level_cond(void) +{ + switch (gAIScriptPtr[1]) + { + case 0: // greater than + if (gBattleMons[sBank_AI].level > gBattleMons[gBankTarget].level) + { + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + return; + } + gAIScriptPtr += 6; + return; + case 1: // less than + if (gBattleMons[sBank_AI].level < gBattleMons[gBankTarget].level) + { + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + return; + } + gAIScriptPtr += 6; + return; + case 2: // equal + if (gBattleMons[sBank_AI].level == gBattleMons[gBankTarget].level) + { + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + return; + } + gAIScriptPtr += 6; + return; + } +} + +static void BattleAICmd_if_target_taunted(void) +{ + if (gDisableStructs[gBankTarget].tauntTimer1 != 0) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); + else + gAIScriptPtr += 5; +} + +static void BattleAICmd_if_target_not_taunted(void) +{ + if (gDisableStructs[gBankTarget].tauntTimer1 == 0) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); + else + gAIScriptPtr += 5; +} + +static void BattleAICmd_if_target_is_ally(void) +{ + if((sBank_AI & 1) == (gBankTarget & 1)) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); + else + gAIScriptPtr += 5; +} + +static void BattleAICmd_if_flash_fired(void) +{ + u8 index = BattleAI_GetWantedBank(gAIScriptPtr[1]); + + if(gBattleResources->flags->flags[index] & UNKNOWN_FLAG_FLASH_FIRE) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void AIStackPushVar(const u8 *var) +{ + gBattleResources->AI_ScriptsStack->ptr[gBattleResources->AI_ScriptsStack->size++] = var; +} + +static void AIStackPushVar_cursor(void) +{ + gBattleResources->AI_ScriptsStack->ptr[gBattleResources->AI_ScriptsStack->size++] = gAIScriptPtr; +} + +static bool8 AIStackPop(void) +{ + if (gBattleResources->AI_ScriptsStack->size != 0) + { + --gBattleResources->AI_ScriptsStack->size; + gAIScriptPtr = gBattleResources->AI_ScriptsStack->ptr[gBattleResources->AI_ScriptsStack->size]; + return TRUE; + } + else + return FALSE; +} diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c new file mode 100644 index 000000000..2e6b3dbae --- /dev/null +++ b/src/battle_script_commands.c @@ -0,0 +1,11415 @@ +#include "global.h" +#include "battle.h" +#include "battle_move_effects.h" +#include "battle_message.h" +#include "battle_ai_script_commands.h" +#include "moves.h" +#include "abilities.h" +#include "item.h" +#include "items.h" +#include "hold_effects.h" +#include "util.h" +#include "pokemon.h" +#include "calculate_base_damage.h" +#include "rng.h" +#include "battle_controllers.h" +#include "species.h" +#include "songs.h" +#include "text.h" +#include "sound.h" +#include "pokedex.h" +#include "recorded_battle.h" +#include "window.h" +#include "reshow_battle_screen.h" +#include "main.h" +#include "palette.h" +#include "money.h" +#include "bg.h" +#include "string_util.h" +#include "pokemon_icon.h" +#include "pokemon_item_effects.h" +#include "m4a.h" +#include "mail.h" +#include "event_data.h" +#include "pokemon_storage_system.h" +#include "task.h" +#include "naming_screen.h" + +// variables + +extern u8 gCritMultiplier; +extern s32 gBattleMoveDamage; +extern u32 gStatuses3[BATTLE_BANKS_COUNT]; +extern u32 gBattleTypeFlags; +extern struct BattleEnigmaBerry gEnigmaBerries[BATTLE_BANKS_COUNT]; +extern struct BattlePokemon gBattleMons[BATTLE_BANKS_COUNT]; +extern u8 gActiveBank; +extern u32 gBattleExecBuffer; +extern u8 gNoOfAllBanks; +extern u16 gBattlePartyID[BATTLE_BANKS_COUNT]; +extern u8 gTurnOrder[BATTLE_BANKS_COUNT]; +extern u8 gUnknown_0202407A[BATTLE_BANKS_COUNT]; +extern u16 gCurrentMove; +extern u8 gLastUsedAbility; +extern u16 gBattleWeather; +extern u8 gStringBank; +extern u8 gEffectBank; +extern u8 gAbsentBankFlags; +extern u8 gMultiHitCounter; +extern u16 gChosenMovesByBanks[BATTLE_BANKS_COUNT]; +extern u16 gSideAffecting[2]; +extern u16 gPauseCounterBattle; +extern u16 gPaydayMoney; +extern u16 gRandomTurnNumber; +extern u8 gBattleOutcome; +extern u8 gBattleTerrain; +extern u8 gBankAttacker; +extern u8 gBankTarget; +extern const u8* gBattlescriptCurrInstr; +extern u8 gCurrMovePos; +extern u8 gFightStateTracker; +extern u32 gHitMarker; +extern u8 gBattleMoveFlags; +extern u8 gBattleCommunication[]; +extern u16 gUnknown_02024250[4]; +extern u16 gUnknown_02024258[4]; +extern u16 gUnknown_02024260[4]; +extern u8 gUnknown_02024270[4]; +extern u8 gStringBank; +extern u16 gDynamicBasePower; +extern u16 gLastUsedItem; +extern u16 gBattleMovePower; +extern s32 gHpDealt; +extern s32 gTakenDmg[BATTLE_BANKS_COUNT]; +extern u8 gTakenDmgBanks[BATTLE_BANKS_COUNT]; +extern u8 gSentPokesToOpponent[2]; +extern u8 gBank1; +extern u16 gExpShareExp; +extern u8 gLeveledUpInBattle; +extern void (*gBattleMainFunc)(void); +extern u8 gPlayerPartyCount; +extern u16 gMoveToLearn; +extern u16 gRandomMove; +extern u8 gBankInMenu; +extern u8 gActionForBanks[BATTLE_BANKS_COUNT]; +extern u8 gCurrentMoveTurn; +extern u8 gBattleBufferB[BATTLE_BANKS_COUNT][0x200]; +extern u16 gLockedMoves[BATTLE_BANKS_COUNT]; +extern u16 gPartnerTrainerId; +extern u16 gLastUsedMove; +extern u16 gUnknownMovesUsedByBanks[BATTLE_BANKS_COUNT]; +extern u16 gLastUsedMovesByBanks[BATTLE_BANKS_COUNT]; +extern u16 gTrainerBattleOpponent_A; +extern u16 gTrainerBattleOpponent_B; +extern u8 gUnknown_020241E9; +extern u16 gBattle_BG1_X; +extern u16 gBattle_BG1_Y; +extern u16 gBattle_BG2_X; +extern u16 gBattle_BG2_Y; +extern u16 gBattle_BG3_X; +extern struct MusicPlayerInfo gMPlay_BGM; + +struct TrainerMoney +{ + u8 classId; + u8 value; +}; + +extern const struct BattleMove gBattleMoves[]; +extern const struct BaseStats gBaseStats[]; +extern const u8 gTypeEffectiveness[]; +extern const u16 gMissStringIds[]; +extern const u16 gTrappingMoves[]; +extern const struct TrainerMoney gTrainerMoneyTable[]; +extern const u8* const gBattleScriptsForMoveEffects[]; + +// functions +extern void sub_81A5718(u8 bank); // battle frontier 2 +extern void sub_81A56B4(void); // battle frontier 2 +extern void sub_81BFA38(struct Pokemon* party, u8 monPartyId, u8 monCount, void (*callback)(void), u16 move); // pokemon summary screen +extern u8 sub_81C1B94(void); // pokemon summary screen +extern void IncrementGameStat(u8 statId); // rom_4 +extern void sub_81D388C(struct Pokemon* mon, void* statStoreLocation); // pokenav.s +extern void sub_81D3640(u8 arg0, void* statStoreLocation1, void* statStoreLocation2, u8 arg3, u8 arg4, u8 arg5); // pokenav.s +extern void sub_81D3784(u8 arg0, void* statStoreLocation1, u8 arg2, u8 arg3, u8 arg4); // pokenav.s +extern u8* GetMonNickname(struct Pokemon* mon, u8* dst); // party_menu +extern u8 sub_81A5258(u8* arg0); // battle frontier 2 +extern void sub_81A5BF8(void); // battle frontier 2 +extern void sub_81A5D44(void); // battle frontier 2 +extern void sub_81B8E80(u8 bank, u8, u8); // party menu +extern bool8 sub_81B1250(void); // ? +extern u8 GetScaledHPFraction(s16 hp, s16 maxhp, u8 scale); // battle interface +extern bool8 InBattlePike(void); +extern bool8 InBattlePyramid(void); +extern u16 GetBattlePyramidPickupItemId(void); +extern u8 sav1_map_get_light_level(void); +extern u8 sub_813B21C(void); +extern u16 get_unknown_box_id(void); +extern void c2_berry_program_update_menu(void); +extern void sub_8035AA4(void); + +// BattleScripts +extern const u8 BattleScript_MoveEnd[]; +extern const u8 BattleScript_NoPPForMove[]; +extern const u8 BattleScript_MagicCoatBounce[]; +extern const u8 BattleScript_TookAttack[]; +extern const u8 BattleScript_SnatchedMove[]; +extern const u8 BattleScript_Pausex20[]; +extern const u8 BattleScript_SubstituteFade[]; +extern const u8 BattleScript_HangedOnMsg[]; +extern const u8 BattleScript_OneHitKOMsg[]; +extern const u8 BattleScript_EnduredMsg[]; +extern const u8 BattleScript_PSNPrevention[]; +extern const u8 BattleScript_BRNPrevention[]; +extern const u8 BattleScript_PRLZPrevention[]; +extern const u8 BattleScript_FlinchPrevention[]; +extern const u8 BattleScript_StatUp[]; +extern const u8 BattleScript_StatDown[]; +extern const u8 BattleScript_NoItemSteal[]; +extern const u8 BattleScript_ItemSteal[]; +extern const u8 BattleScript_RapidSpinAway[]; +extern const u8 BattleScript_TargetPRLZHeal[]; +extern const u8 BattleScript_KnockedOff[]; +extern const u8 BattleScript_StickyHoldActivates[]; +extern const u8 BattleScript_AllStatsUp[]; +extern const u8 BattleScript_AtkDefDown[]; +extern const u8 BattleScript_SAtkDown2[]; +extern const u8 BattleScript_LevelUp[]; +extern const u8 BattleScript_WrapFree[]; +extern const u8 BattleScript_LeechSeedFree[]; +extern const u8 BattleScript_SpikesFree[]; +extern const u8 BattleScript_ButItFailed[]; +extern const u8 BattleScript_ObliviousPreventsAttraction[]; +extern const u8 BattleScript_MistProtected[]; +extern const u8 BattleScript_AbilityNoStatLoss[]; +extern const u8 BattleScript_AbilityNoSpecificStatLoss[]; +extern const u8 BattleScript_TrainerBallBlock[]; +extern const u8 BattleScript_WallyBallThrow[]; +extern const u8 BattleScript_SuccessBallThrow[]; +extern const u8 BattleScript_ShakeBallThrow[]; +extern const u8 BattleScript_FaintAttacker[]; +extern const u8 BattleScript_FaintTarget[]; +extern const u8 BattleScript_DestinyBondTakesLife[]; +extern const u8 BattleScript_GrudgeTakesPp[]; +extern const u8 BattleScript_RageIsBuilding[]; +extern const u8 BattleScript_DefrostedViaFireMove[]; +extern const u8 gUnknown_082DB87D[]; +extern const u8 gUnknown_082DAE90[]; +extern const u8 gUnknown_082DAE59[]; +extern const u8 gUnknown_082DAEC7[]; +extern const u8 BattleScript_MoveEffectSleep[]; +extern const u8 BattleScript_MoveEffectPoison[]; +extern const u8 BattleScript_MoveEffectBurn[]; +extern const u8 BattleScript_MoveEffectFreeze[]; +extern const u8 BattleScript_MoveEffectParalysis[]; +extern const u8 BattleScript_MoveEffectToxic[]; +extern const u8 BattleScript_MoveEffectConfusion[]; +extern const u8 BattleScript_MoveEffectUproar[]; +extern const u8 BattleScript_MoveEffectPayDay[]; +extern const u8 BattleScript_MoveEffectWrap[]; +extern const u8 BattleScript_MoveEffectRecoil33[]; +extern const u8 BattleScript_DampStopsExplosion[]; +extern const u8 BattleScript_MistProtected[]; +extern const u8 BattleScript_AbilityNoStatLoss[]; +extern const u8 BattleScript_AbilityNoSpecificStatLoss[]; +extern const u8 BattleScript_ButItFailed[]; +extern const u8 gUnknown_082DADD8[]; +extern const u8 BattleScript_PrintPayDayMoneyString[]; +extern const u8 BattleScript_SturdyPreventsOHKO[]; +extern const u8 BattleScript_ObliviousPreventsAttraction[]; +extern const u8 BattleScript_PauseEffectivenessSoundResultMsgEndMove[]; +extern const u8 BattleScript_CastformChange[]; +extern const u8 BattleScript_TrainerBallBlock[]; +extern const u8 BattleScript_WallyBallThrow[]; +extern const u8 BattleScript_SuccessBallThrow[]; +extern const u8 BattleScript_ShakeBallThrow[]; +extern const u8 BattleScript_PresentDamageTarget[]; +extern const u8 BattleScript_AlreadyAtFullHp[]; +extern const u8 BattleScript_PresentHealTarget[]; +extern const u8 BattleScript_WrapFree[]; +extern const u8 BattleScript_LeechSeedFree[]; +extern const u8 BattleScript_SpikesFree[]; + +// strings +extern const u8 gText_BattleYesNoChoice[]; + +// read via orr +#define BSScriptRead32(ptr) ((ptr)[0] | (ptr)[1] << 8 | (ptr)[2] << 16 | (ptr)[3] << 24) +#define BSScriptRead16(ptr) ((ptr)[0] | ((ptr)[1] << 8)) +#define BSScriptReadPtr(ptr) ((void *)BSScriptRead32(ptr)) + +// read via add +#define BS2ScriptRead32(ptr) ((ptr)[0] + ((ptr)[1] << 8) + ((ptr)[2] << 16) + ((ptr)[3] << 24)) +#define BS2ScriptRead16(ptr) ((ptr)[0] + ((ptr)[1] << 8)) +#define BS2ScriptReadPtr(ptr) ((void *)BS2ScriptRead32(ptr)) + +#define TARGET_PROTECT_AFFECTED ((gProtectStructs[gBankTarget].protected && gBattleMoves[gCurrentMove].flags & FLAG_PROTECT_AFFECTED)) + +#define TARGET_TURN_DAMAGED (((gSpecialStatuses[gBankTarget].moveturnLostHP_physical || gSpecialStatuses[gBankTarget].moveturnLostHP_special))) + +// this file's functions +static bool8 IsTwoTurnsMove(u16 move); +static void DestinyBondFlagUpdate(void); +static u8 AttacksThisTurn(u8 bank, u16 move); // Note: returns 1 if it's a charging turn, otherwise 2. +static void CheckWonderGuardAndLevitate(void); +static u8 ChangeStatBuffs(s8 statValue, u8 statId, u8, const u8* BS_ptr); +static bool32 IsMonGettingExpSentOut(void); +static void sub_804F17C(void); +static bool8 sub_804F1CC(void); +static void sub_804F100(void); +static void sub_804F144(void); +static bool8 sub_804F344(void); +static void PutMonIconOnLvlUpBox(void); +static void PutLevelAndGenderOnLvlUpBox(void); + +static void SpriteCB_MonIconOnLvlUpBox(struct Sprite* sprite); + +static void atk00_attackcanceler(void); +static void atk01_accuracycheck(void); +static void atk02_attackstring(void); +static void atk03_ppreduce(void); +static void atk04_critcalc(void); +static void atk05_damagecalc1(void); +static void atk06_typecalc(void); +static void atk07_dmg_adjustment(void); +static void atk08_dmg_adjustment2(void); +static void atk09_attackanimation(void); +static void atk0A_waitanimation(void); +static void atk0B_healthbarupdate(void); +static void atk0C_datahpupdate(void); +static void atk0D_critmessage(void); +static void atk0E_effectiveness_sound(void); +static void atk0F_resultmessage(void); +static void atk10_printstring(void); +static void atk11_printstring_playeronly(void); +static void atk12_waitmessage(void); +static void atk13_printfromtable(void); +static void atk14_printfromtable_playeronly(void); +static void atk15_seteffectwithchance(void); +static void atk16_seteffectprimary(void); +static void atk17_seteffectsecondary(void); +static void atk18_status_effect_clear(void); +static void atk19_faint_pokemon(void); +static void atk1A_faint_animation(void); +static void atk1B_faint_effects_clear(void); +static void atk1C_jumpifstatus(void); +static void atk1D_jumpifstatus2(void); +static void atk1E_jumpifability(void); +static void atk1F_jumpifsideaffecting(void); +static void atk20_jumpifstat(void); +static void atk21_jumpifstatus3(void); +static void atk22_jumpiftype(void); +static void atk23_getexp(void); +static void atk24(void); +static void atk25_move_values_cleanup(void); +static void atk26_set_multihit(void); +static void atk27_decrement_multihit(void); +static void atk28_goto(void); +static void atk29_jumpifbyte(void); +static void atk2A_jumpifhalfword(void); +static void atk2B_jumpifword(void); +static void atk2C_jumpifarrayequal(void); +static void atk2D_jumpifarraynotequal(void); +static void atk2E_setbyte(void); +static void atk2F_addbyte(void); +static void atk30_subbyte(void); +static void atk31_copyarray(void); +static void atk32_copyarray_withindex(void); +static void atk33_orbyte(void); +static void atk34_orhalfword(void); +static void atk35_orword(void); +static void atk36_bicbyte(void); +static void atk37_bichalfword(void); +static void atk38_bicword(void); +static void atk39_pause(void); +static void atk3A_waitstate(void); +static void atk3B_healthbar_update(void); +static void atk3C_return(void); +static void atk3D_end(void); +static void atk3E_end2(void); +static void atk3F_end3(void); +static void atk40_jump_if_move_affected_by_protect(void); +static void atk41_call(void); +static void atk42_jumpiftype2(void); +static void atk43_jumpifabilitypresent(void); +static void atk44(void); +static void atk45_playanimation(void); +static void atk46_playanimation2(void); +static void atk47_setgraphicalstatchangevalues(void); +static void atk48_playstatchangeanimation(void); +static void atk49_moveend(void); +static void atk4A_typecalc2(void); +static void atk4B_return_atk_to_ball(void); +static void atk4C_copy_poke_data(void); +static void atk4D_switch_data_update(void); +static void atk4E_switchin_anim(void); +static void atk4F_jump_if_cannot_switch(void); +static void atk50_openpartyscreen(void); +static void atk51_switch_handle_order(void); +static void atk52_switch_in_effects(void); +static void atk53_trainer_slide(void); +static void atk54_effectiveness_sound(void); +static void atk55_play_sound(void); +static void atk56_fainting_cry(void); +static void atk57(void); +static void atk58_return_to_ball(void); +static void atk59_learnmove_inbattle(void); +static void atk5A_yesnoboxlearnmove(void); +static void atk5B_yesnoboxstoplearningmove(void); +static void atk5C_hitanimation(void); +static void atk5D_getmoneyreward(void); +static void atk5E_8025A70(void); +static void atk5F_8025B24(void); +static void atk60_increment_gamestat(void); +static void atk61_8025BA4(void); +static void atk62_08025C6C(void); +static void atk63_jumptorandomattack(void); +static void atk64_statusanimation(void); +static void atk65_status2animation(void); +static void atk66_chosenstatusanimation(void); +static void atk67_yesnobox(void); +static void atk68_80246A0(void); +static void atk69_dmg_adjustment3(void); +static void atk6A_removeitem(void); +static void atk6B_atknameinbuff1(void); +static void atk6C_draw_lvlupbox(void); +static void atk6D_reset_sentpokes_value(void); +static void atk6E_set_atk_to_player0(void); +static void atk6F_set_visible(void); +static void atk70_record_last_used_ability(void); +static void atk71_buffer_move_to_learn(void); +static void atk72_jump_if_can_run_frombattle(void); +static void atk73_hp_thresholds(void); +static void atk74_hp_thresholds2(void); +static void atk75_item_effect_on_opponent(void); +static void atk76_various(void); +static void atk77_set_protect_like(void); +static void atk78_faintifabilitynotdamp(void); +static void atk79_setatkhptozero(void); +static void atk7A_jumpwhiletargetvalid(void); +static void atk7B_healhalfHP_if_possible(void); +static void atk7C_trymirrormove(void); +static void atk7D_set_rain(void); +static void atk7E_setreflect(void); +static void atk7F_setseeded(void); +static void atk80_manipulatedamage(void); +static void atk81_setrest(void); +static void atk82_jumpifnotfirstturn(void); +static void atk83_nop(void); +static void atk84_jump_if_cant_sleep(void); +static void atk85_stockpile(void); +static void atk86_stockpiletobasedamage(void); +static void atk87_stockpiletohpheal(void); +static void atk88_negativedamage(void); +static void atk89_statbuffchange(void); +static void atk8A_normalisebuffs(void); +static void atk8B_setbide(void); +static void atk8C_confuseifrepeatingattackends(void); +static void atk8D_setmultihit_counter(void); +static void atk8E_init_multihit_string(void); +static void atk8F_forcerandomswitch(void); +static void atk90_conversion_type_change(void); +static void atk91_givepaydaymoney(void); +static void atk92_setlightscreen(void); +static void atk93_ko_move(void); +static void atk94_damagetohalftargethp(void); +static void atk95_setsandstorm(void); +static void atk96_weatherdamage(void); +static void atk97_try_infatuation(void); +static void atk98_status_icon_update(void); +static void atk99_setmist(void); +static void atk9A_set_focusenergy(void); +static void atk9B_transformdataexecution(void); +static void atk9C_set_substitute(void); +static void atk9D_mimicattackcopy(void); +static void atk9E_metronome(void); +static void atk9F_dmgtolevel(void); +static void atkA0_psywavedamageeffect(void); +static void atkA1_counterdamagecalculator(void); +static void atkA2_mirrorcoatdamagecalculator(void); +static void atkA3_disablelastusedattack(void); +static void atkA4_setencore(void); +static void atkA5_painsplitdmgcalc(void); +static void atkA6_settypetorandomresistance(void); +static void atkA7_setalwayshitflag(void); +static void atkA8_copymovepermanently(void); +static void atkA9_sleeptalk_choose_move(void); +static void atkAA_set_destinybond(void); +static void atkAB_DestinyBondFlagUpdate(void); +static void atkAC_remaininghptopower(void); +static void atkAD_spite_ppreduce(void); +static void atkAE_heal_party_status(void); +static void atkAF_cursetarget(void); +static void atkB0_set_spikes(void); +static void atkB1_set_foresight(void); +static void atkB2_setperishsong(void); +static void atkB3_rolloutdamagecalculation(void); +static void atkB4_jumpifconfusedandstatmaxed(void); +static void atkB5_furycuttercalc(void); +static void atkB6_happinesstodamagecalculation(void); +static void atkB7_presentdamagecalculation(void); +static void atkB8_set_safeguard(void); +static void atkB9_magnitudedamagecalculation(void); +static void atkBA_jumpifnopursuitswitchdmg(void); +static void atkBB_setsunny(void); +static void atkBC_maxattackhalvehp(void); +static void atkBD_copyfoestats(void); +static void atkBE_rapidspinfree(void); +static void atkBF_set_defense_curl(void); +static void atkC0_recoverbasedonsunlight(void); +static void atkC1_hidden_power(void); +static void atkC2_selectnexttarget(void); +static void atkC3_setfutureattack(void); +static void atkC4_beat_up(void); +static void atkC5_setsemiinvulnerablebit(void); +static void atkC6_clearsemiinvulnerablebit(void); +static void atkC7_setminimize(void); +static void atkC8_sethail(void); +static void atkC9_jumpifattackandspecialattackcannotfall(void); +static void atkCA_setforcedtarget(void); +static void atkCB_setcharge(void); +static void atkCC_callterrainattack(void); +static void atkCD_cureifburnedparalysedorpoisoned(void); +static void atkCE_settorment(void); +static void atkCF_jumpifnodamage(void); +static void atkD0_settaunt(void); +static void atkD1_set_helpinghand(void); +static void atkD2_swap_items(void); +static void atkD3_copy_ability(void); +static void atkD4_wish_effect(void); +static void atkD5_setroots(void); +static void atkD6_doubledamagedealtifdamaged(void); +static void atkD7_setyawn(void); +static void atkD8_setdamagetohealthdifference(void); +static void atkD9_scaledamagebyhealthratio(void); +static void atkDA_abilityswap(void); +static void atkDB_imprisoneffect(void); +static void atkDC_setgrudge(void); +static void atkDD_weightdamagecalculation(void); +static void atkDE_asistattackselect(void); +static void atkDF_setmagiccoat(void); +static void atkE0_setstealstatchange(void); +static void atkE1_intimidate_string_loader(void); +static void atkE2_switchout_abilities(void); +static void atkE3_jumpifhasnohp(void); +static void atkE4_getsecretpowereffect(void); +static void atkE5_pickup(void); +static void atkE6_castform_change_animation(void); +static void atkE7_castform_data_change(void); +static void atkE8_settypebasedhalvers(void); +static void atkE9_setweatherballtype(void); +static void atkEA_recycleitem(void); +static void atkEB_settypetoterrain(void); +static void atkEC_pursuit_sth(void); +static void atkED_802B4B4(void); +static void atkEE_removelightscreenreflect(void); +static void atkEF_pokeball_catch_calculation(void); +static void atkF0_give_caught_mon(void); +static void atkF1_set_caught_mon_dex_flags(void); +static void atkF2_display_dex_info(void); +static void atkF3_nickname_caught_poke(void); +static void atkF4_subattackerhpbydmg(void); +static void atkF5_removeattackerstatus1(void); +static void atkF6_802BF48(void); +static void atkF7_802BF54(void); +static void atkF8_trainer_slide_back(void); + +void (* const gBattleScriptingCommandsTable[])(void) = +{ + atk00_attackcanceler, + atk01_accuracycheck, + atk02_attackstring, + atk03_ppreduce, + atk04_critcalc, + atk05_damagecalc1, + atk06_typecalc, + atk07_dmg_adjustment, + atk08_dmg_adjustment2, + atk09_attackanimation, + atk0A_waitanimation, + atk0B_healthbarupdate, + atk0C_datahpupdate, + atk0D_critmessage, + atk0E_effectiveness_sound, + atk0F_resultmessage, + atk10_printstring, + atk11_printstring_playeronly, + atk12_waitmessage, + atk13_printfromtable, + atk14_printfromtable_playeronly, + atk15_seteffectwithchance, + atk16_seteffectprimary, + atk17_seteffectsecondary, + atk18_status_effect_clear, + atk19_faint_pokemon, + atk1A_faint_animation, + atk1B_faint_effects_clear, + atk1C_jumpifstatus, + atk1D_jumpifstatus2, + atk1E_jumpifability, + atk1F_jumpifsideaffecting, + atk20_jumpifstat, + atk21_jumpifstatus3, + atk22_jumpiftype, + atk23_getexp, + atk24, + atk25_move_values_cleanup, + atk26_set_multihit, + atk27_decrement_multihit, + atk28_goto, + atk29_jumpifbyte, + atk2A_jumpifhalfword, + atk2B_jumpifword, + atk2C_jumpifarrayequal, + atk2D_jumpifarraynotequal, + atk2E_setbyte, + atk2F_addbyte, + atk30_subbyte, + atk31_copyarray, + atk32_copyarray_withindex, + atk33_orbyte, + atk34_orhalfword, + atk35_orword, + atk36_bicbyte, + atk37_bichalfword, + atk38_bicword, + atk39_pause, + atk3A_waitstate, + atk3B_healthbar_update, + atk3C_return, + atk3D_end, + atk3E_end2, + atk3F_end3, + atk40_jump_if_move_affected_by_protect, + atk41_call, + atk42_jumpiftype2, + atk43_jumpifabilitypresent, + atk44, + atk45_playanimation, + atk46_playanimation2, + atk47_setgraphicalstatchangevalues, + atk48_playstatchangeanimation, + atk49_moveend, + atk4A_typecalc2, + atk4B_return_atk_to_ball, + atk4C_copy_poke_data, + atk4D_switch_data_update, + atk4E_switchin_anim, + atk4F_jump_if_cannot_switch, + atk50_openpartyscreen, + atk51_switch_handle_order, + atk52_switch_in_effects, + atk53_trainer_slide, + atk54_effectiveness_sound, + atk55_play_sound, + atk56_fainting_cry, + atk57, + atk58_return_to_ball, + atk59_learnmove_inbattle, + atk5A_yesnoboxlearnmove, + atk5B_yesnoboxstoplearningmove, + atk5C_hitanimation, + atk5D_getmoneyreward, + atk5E_8025A70, + atk5F_8025B24, + atk60_increment_gamestat, + atk61_8025BA4, + atk62_08025C6C, + atk63_jumptorandomattack, + atk64_statusanimation, + atk65_status2animation, + atk66_chosenstatusanimation, + atk67_yesnobox, + atk68_80246A0, + atk69_dmg_adjustment3, + atk6A_removeitem, + atk6B_atknameinbuff1, + atk6C_draw_lvlupbox, + atk6D_reset_sentpokes_value, + atk6E_set_atk_to_player0, + atk6F_set_visible, + atk70_record_last_used_ability, + atk71_buffer_move_to_learn, + atk72_jump_if_can_run_frombattle, + atk73_hp_thresholds, + atk74_hp_thresholds2, + atk75_item_effect_on_opponent, + atk76_various, + atk77_set_protect_like, + atk78_faintifabilitynotdamp, + atk79_setatkhptozero, + atk7A_jumpwhiletargetvalid, + atk7B_healhalfHP_if_possible, + atk7C_trymirrormove, + atk7D_set_rain, + atk7E_setreflect, + atk7F_setseeded, + atk80_manipulatedamage, + atk81_setrest, + atk82_jumpifnotfirstturn, + atk83_nop, + atk84_jump_if_cant_sleep, + atk85_stockpile, + atk86_stockpiletobasedamage, + atk87_stockpiletohpheal, + atk88_negativedamage, + atk89_statbuffchange, + atk8A_normalisebuffs, + atk8B_setbide, + atk8C_confuseifrepeatingattackends, + atk8D_setmultihit_counter, + atk8E_init_multihit_string, + atk8F_forcerandomswitch, + atk90_conversion_type_change, + atk91_givepaydaymoney, + atk92_setlightscreen, + atk93_ko_move, + atk94_damagetohalftargethp, + atk95_setsandstorm, + atk96_weatherdamage, + atk97_try_infatuation, + atk98_status_icon_update, + atk99_setmist, + atk9A_set_focusenergy, + atk9B_transformdataexecution, + atk9C_set_substitute, + atk9D_mimicattackcopy, + atk9E_metronome, + atk9F_dmgtolevel, + atkA0_psywavedamageeffect, + atkA1_counterdamagecalculator, + atkA2_mirrorcoatdamagecalculator, + atkA3_disablelastusedattack, + atkA4_setencore, + atkA5_painsplitdmgcalc, + atkA6_settypetorandomresistance, + atkA7_setalwayshitflag, + atkA8_copymovepermanently, + atkA9_sleeptalk_choose_move, + atkAA_set_destinybond, + atkAB_DestinyBondFlagUpdate, + atkAC_remaininghptopower, + atkAD_spite_ppreduce, + atkAE_heal_party_status, + atkAF_cursetarget, + atkB0_set_spikes, + atkB1_set_foresight, + atkB2_setperishsong, + atkB3_rolloutdamagecalculation, + atkB4_jumpifconfusedandstatmaxed, + atkB5_furycuttercalc, + atkB6_happinesstodamagecalculation, + atkB7_presentdamagecalculation, + atkB8_set_safeguard, + atkB9_magnitudedamagecalculation, + atkBA_jumpifnopursuitswitchdmg, + atkBB_setsunny, + atkBC_maxattackhalvehp, + atkBD_copyfoestats, + atkBE_rapidspinfree, + atkBF_set_defense_curl, + atkC0_recoverbasedonsunlight, + atkC1_hidden_power, + atkC2_selectnexttarget, + atkC3_setfutureattack, + atkC4_beat_up, + atkC5_setsemiinvulnerablebit, + atkC6_clearsemiinvulnerablebit, + atkC7_setminimize, + atkC8_sethail, + atkC9_jumpifattackandspecialattackcannotfall, + atkCA_setforcedtarget, + atkCB_setcharge, + atkCC_callterrainattack, + atkCD_cureifburnedparalysedorpoisoned, + atkCE_settorment, + atkCF_jumpifnodamage, + atkD0_settaunt, + atkD1_set_helpinghand, + atkD2_swap_items, + atkD3_copy_ability, + atkD4_wish_effect, + atkD5_setroots, + atkD6_doubledamagedealtifdamaged, + atkD7_setyawn, + atkD8_setdamagetohealthdifference, + atkD9_scaledamagebyhealthratio, + atkDA_abilityswap, + atkDB_imprisoneffect, + atkDC_setgrudge, + atkDD_weightdamagecalculation, + atkDE_asistattackselect, + atkDF_setmagiccoat, + atkE0_setstealstatchange, + atkE1_intimidate_string_loader, + atkE2_switchout_abilities, + atkE3_jumpifhasnohp, + atkE4_getsecretpowereffect, + atkE5_pickup, + atkE6_castform_change_animation, + atkE7_castform_data_change, + atkE8_settypebasedhalvers, + atkE9_setweatherballtype, + atkEA_recycleitem, + atkEB_settypetoterrain, + atkEC_pursuit_sth, + atkED_802B4B4, + atkEE_removelightscreenreflect, + atkEF_pokeball_catch_calculation, + atkF0_give_caught_mon, + atkF1_set_caught_mon_dex_flags, + atkF2_display_dex_info, + atkF3_nickname_caught_poke, + atkF4_subattackerhpbydmg, + atkF5_removeattackerstatus1, + atkF6_802BF48, + atkF7_802BF54, + atkF8_trainer_slide_back +}; + +struct StatFractions +{ + u8 dividend; + u8 divisor; +}; + +static const struct StatFractions sAccuracyStageRatios[] = +{ + { 33, 100}, // -6 + { 36, 100}, // -5 + { 43, 100}, // -4 + { 50, 100}, // -3 + { 60, 100}, // -2 + { 75, 100}, // -1 + { 1, 1}, // 0 + {133, 100}, // +1 + {166, 100}, // +2 + { 2, 1}, // +3 + {233, 100}, // +4 + {133, 50}, // +5 + { 3, 1}, // +6 +}; + +// The chance is 1/N for each stage. +static const u16 sCriticalHitChance[] = {16, 8, 4, 3, 2}; + +static const u32 sStatusFlagsForMoveEffects[] = +{ + 0x00000000, + STATUS_SLEEP, + STATUS_POISON, + STATUS_BURN, + STATUS_FREEZE, + STATUS_PARALYSIS, + STATUS_TOXIC_POISON, + STATUS2_CONFUSION, + STATUS2_FLINCHED, + 0x00000000, + STATUS2_UPROAR, + 0x00000000, + STATUS2_MULTIPLETURNS, + STATUS2_WRAPPED, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + STATUS2_RECHARGE, + 0x00000000, + 0x00000000, + STATUS2_ESCAPE_PREVENTION, + 0x08000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + STATUS2_LOCK_CONFUSE, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000 +}; + +static const u8* const sMoveEffectBS_Ptrs[] = +{ + BattleScript_MoveEffectSleep, // 0 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_SLEEP + BattleScript_MoveEffectPoison, // MOVE_EFFECT_POISON + BattleScript_MoveEffectBurn, // MOVE_EFFECT_BURN + BattleScript_MoveEffectFreeze, // MOVE_EFFECT_FREEZE + BattleScript_MoveEffectParalysis, // MOVE_EFFECT_PARALYSIS + BattleScript_MoveEffectToxic, // MOVE_EFFECT_TOXIC + BattleScript_MoveEffectConfusion, // MOVE_EFFECT_CONFUSION + BattleScript_MoveEffectSleep, // MOVE_EFFECT_FLINCH + BattleScript_MoveEffectSleep, // MOVE_EFFECT_TRI_ATTACK + BattleScript_MoveEffectUproar, // MOVE_EFFECT_UPROAR + BattleScript_MoveEffectPayDay, // MOVE_EFFECT_PAYDAY + BattleScript_MoveEffectSleep, // MOVE_EFFECT_CHARGING + BattleScript_MoveEffectWrap, // MOVE_EFFECT_WRAP + BattleScript_MoveEffectRecoil33, // MOVE_EFFECT_RECOIL_25 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_ATK_PLUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_DEF_PLUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_SPD_PLUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_SP_ATK_PLUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_SP_DEF_PLUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_ACC_PLUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_EVS_PLUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_ATK_MINUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_DEF_MINUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_SPD_MINUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_SP_ATK_MINUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_SP_DEF_MINUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_ACC_MINUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_EVS_MINUS_1 + BattleScript_MoveEffectSleep, // MOVE_EFFECT_RECHARGE + BattleScript_MoveEffectSleep, // MOVE_EFFECT_RAGE + BattleScript_MoveEffectSleep, // MOVE_EFFECT_STEAL_ITEM + BattleScript_MoveEffectSleep, // MOVE_EFFECT_PREVENT_ESCAPE + BattleScript_MoveEffectSleep, // MOVE_EFFECT_NIGHTMARE + BattleScript_MoveEffectSleep, // MOVE_EFFECT_ALL_STATS_UP + BattleScript_MoveEffectSleep, // MOVE_EFFECT_RAPIDSPIN + BattleScript_MoveEffectSleep, // MOVE_EFFECT_REMOVE_PARALYSIS + BattleScript_MoveEffectSleep, // MOVE_EFFECT_ATK_DEF_DOWN + BattleScript_MoveEffectRecoil33, // MOVE_EFFECT_RECOIL_33_PARALYSIS +}; + +static const struct WindowTemplate sUnusedWinTemplate = {0, 1, 3, 7, 0xF, 0x1F, 0x3F}; + +static const u16 sUnknown_0831C2C8[] = INCBIN_U16("graphics/battle_interface/unk_battlebox.gbapal"); +static const u8 sUnknown_0831C2E8[] = INCBIN_U8("graphics/battle_interface/unk_battlebox.4bpp.lz"); + +// unused +static const u8 sRubyLevelUpStatBoxStats[] = +{ + MON_DATA_MAX_HP, MON_DATA_SPATK, MON_DATA_ATK, + MON_DATA_SPDEF, MON_DATA_DEF, MON_DATA_SPD +}; + +#define MON_ICON_LVLUP_BOX_TAG 0xD75A + +static const struct OamData sOamData_MonIconOnLvlUpBox = +{ + .y = 0, + .affineMode = 0, + .objMode = 0, + .mosaic = 0, + .bpp = 0, + .shape = 0, + .x = 0, + .matrixNum = 0, + .size = 2, + .tileNum = 0, + .priority = 0, + .paletteNum = 0, + .affineParam = 0, +}; + +static const struct SpriteTemplate sSpriteTemplate_MonIconOnLvlUpBox = +{ + .tileTag = MON_ICON_LVLUP_BOX_TAG, + .paletteTag = MON_ICON_LVLUP_BOX_TAG, + .oam = &sOamData_MonIconOnLvlUpBox, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCB_MonIconOnLvlUpBox +}; + +static const u16 sProtectSuccessRates[] = {USHRT_MAX, USHRT_MAX / 2, USHRT_MAX / 4, USHRT_MAX / 8}; + +#define MIMIC_FORBIDDEN_END 0xFFFE +#define METRONOME_FORBIDDEN_END 0xFFFF +#define ASSIST_FORBIDDEN_END 0xFFFF + +static const u16 sMovesForbiddenToCopy[] = +{ + MOVE_METRONOME, + MOVE_STRUGGLE, + MOVE_SKETCH, + MOVE_MIMIC, + MIMIC_FORBIDDEN_END, + MOVE_COUNTER, + MOVE_MIRROR_COAT, + MOVE_PROTECT, + MOVE_DETECT, + MOVE_ENDURE, + MOVE_DESTINY_BOND, + MOVE_SLEEP_TALK, + MOVE_THIEF, + MOVE_FOLLOW_ME, + MOVE_SNATCH, + MOVE_HELPING_HAND, + MOVE_COVET, + MOVE_TRICK, + MOVE_FOCUS_PUNCH, + METRONOME_FORBIDDEN_END +}; + +static const u8 sFlailHpScaleToPowerTable[] = +{ + 1, 200, + 4, 150, + 9, 100, + 16, 80, + 32, 40, + 48, 20 +}; + +static const u16 sNaturePowerMoves[] = +{ + MOVE_STUN_SPORE, + MOVE_RAZOR_LEAF, + MOVE_EARTHQUAKE, + MOVE_HYDRO_PUMP, + MOVE_SURF, + MOVE_BUBBLE_BEAM, + MOVE_ROCK_SLIDE, + MOVE_SHADOW_BALL, + MOVE_SWIFT, + MOVE_SWIFT +}; + +// format: min. weight (hectograms), base power +static const u16 sWeightToDamageTable[] = +{ + 100, 20, + 250, 40, + 500, 60, + 1000, 80, + 2000, 100, + 0xFFFF, 0xFFFF +}; + +static const u16 sPickupItems[] = +{ + ITEM_POTION, + ITEM_ANTIDOTE, + ITEM_SUPER_POTION, + ITEM_GREAT_BALL, + ITEM_REPEL, + ITEM_ESCAPE_ROPE, + ITEM_X_ATTACK, + ITEM_FULL_HEAL, + ITEM_ULTRA_BALL, + ITEM_HYPER_POTION, + ITEM_RARE_CANDY, + ITEM_PROTEIN, + ITEM_REVIVE, + ITEM_HP_UP, + ITEM_FULL_RESTORE, + ITEM_MAX_REVIVE, + ITEM_PP_UP, + ITEM_MAX_ELIXIR, +}; + +static const u16 sRarePickupItems[] = +{ + ITEM_HYPER_POTION, + ITEM_NUGGET, + ITEM_KINGS_ROCK, + ITEM_FULL_RESTORE, + ITEM_ETHER, + ITEM_WHITE_HERB, + ITEM_TM44, + ITEM_ELIXIR, + ITEM_TM01, + ITEM_LEFTOVERS, + ITEM_TM26, +}; + +static const u8 sPickupProbabilities[] = +{ + 30, 40, 50, 60, 70, 80, 90, 94, 98 +}; + +static const u8 sTerrainToType[] = +{ + TYPE_GRASS, // tall grass + TYPE_GRASS, // long grass + TYPE_GROUND, // sand + TYPE_WATER, // underwater + TYPE_WATER, // water + TYPE_WATER, // pond water + TYPE_ROCK, // rock + TYPE_ROCK, // cave + TYPE_NORMAL, // building + TYPE_NORMAL, // plain +}; + +static const u8 sBallCatchBonuses[] = +{ + 20, 15, 10, 15 // Ultra, Great, Poke, Safari +}; + +// could be a 2d array or a struct +const ALIGNED(4) u8 gUnknown_0831C494[] = +{ + 0x3d, 0x44, 0x3d, 0x44, 0x14, 0x2d, 0x54, 0x5c, + 0x46, 0x55, 0x20, 0x5c, 0x26, 0x45, 0x46, 0x55, + 0x14, 0x5a, 0x46, 0x5c, 0x1e, 0x32, 0x20, 0x5a, + 0x38, 0x4e, 0x38, 0x4e, 0x19, 0x28, 0x4b, 0x5a, + 0x45, 0x4b, 0x1c, 0x53, 0x23, 0x2d, 0x1d, 0x23, + 0x3e, 0x48, 0x1e, 0x32, 0x3a, 0x5f, 0x58, 0x5e, + 0x22, 0x2d, 0x1d, 0x28, 0x23, 0x28, 0x23, 0x5f, + 0x38, 0x4e, 0x38, 0x4e, 0x23, 0x50, 0x22, 0x5e, + 0x2c, 0x5e, 0x22, 0x28, 0x38, 0x4e, 0x38, 0x4e, + 0x1e, 0x58, 0x1e, 0x58, 0x1e, 0x2b, 0x1b, 0x21, + 0x28, 0x5a, 0x19, 0x57, 0x12, 0x58, 0x5a, 0x5f, + 0x58, 0x5e, 0x16, 0x2a, 0x2a, 0x5c, 0x2a, 0x2f, + 0x38, 0x4e, 0x38, 0x4e +}; + +static const u8 sUnknown_0831C4F8[] = +{ + 0x03, 0x00, 0x01, 0x00, 0x00, 0x01, 0x03, 0x00, + 0x01, 0x02, 0x02, 0x00, 0x03, 0x01, 0x03, 0x01, + 0x02, 0x03, 0x03, 0x02, 0x01, 0x00, 0x02, 0x02, + 0x03, 0x00, 0x00, 0x00 +}; + +static void atk00_attackcanceler(void) +{ + s32 i; + + if (gBattleOutcome) + { + gFightStateTracker = 0xC; + return; + } + if (gBattleMons[gBankAttacker].hp == 0 && !(gHitMarker & HITMARKER_NO_ATTACKSTRING)) + { + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + gBattlescriptCurrInstr = BattleScript_MoveEnd; + return; + } + if (AtkCanceller_UnableToUseMove()) + return; + if (AbilityBattleEffects(ABILITYEFFECT_MOVES_BLOCK, gBankTarget, 0, 0, 0)) + return; + if (!gBattleMons[gBankAttacker].pp[gCurrMovePos] && gCurrentMove != MOVE_STRUGGLE && !(gHitMarker & 0x800200) + && !(gBattleMons[gBankAttacker].status2 & STATUS2_MULTIPLETURNS)) + { + gBattlescriptCurrInstr = BattleScript_NoPPForMove; + gBattleMoveFlags |= MOVESTATUS_MISSED; + return; + } + + gHitMarker &= ~(HITMARKER_x800000); + + if (!(gHitMarker & HITMARKER_OBEYS) && !(gBattleMons[gBankAttacker].status2 & STATUS2_MULTIPLETURNS)) + { + i = IsPokeDisobedient(); // why use the 'i' variable...? + switch (i) + { + case 0: + break; + case 2: + gHitMarker |= HITMARKER_OBEYS; + return; + default: + gBattleMoveFlags |= MOVESTATUS_MISSED; + return; + } + } + + gHitMarker |= HITMARKER_OBEYS; + + if (gProtectStructs[gBankTarget].bounceMove && gBattleMoves[gCurrentMove].flags & FLAG_MAGICCOAT_AFFECTED) + { + PressurePPLose(gBankAttacker, gBankTarget, MOVE_MAGIC_COAT); + gProtectStructs[gBankTarget].bounceMove = 0; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_MagicCoatBounce; + return; + } + + for (i = 0; i < gNoOfAllBanks; i++) + { + if ((gProtectStructs[gTurnOrder[i]].stealMove) && gBattleMoves[gCurrentMove].flags & FLAG_SNATCH_AFFECTED) + { + PressurePPLose(gBankAttacker, gTurnOrder[i], MOVE_SNATCH); + gProtectStructs[gTurnOrder[i]].stealMove = 0; + gBattleScripting.bank = gTurnOrder[i]; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_SnatchedMove; + return; + } + } + + if (gSpecialStatuses[gBankTarget].lightningRodRedirected) + { + gSpecialStatuses[gBankTarget].lightningRodRedirected = 0; + gLastUsedAbility = ABILITY_LIGHTNING_ROD; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_TookAttack; + RecordAbilityBattle(gBankTarget, gLastUsedAbility); + } + else if (TARGET_PROTECT_AFFECTED + && (gCurrentMove != MOVE_CURSE || (gBattleMons[gBankAttacker].type1 == TYPE_GHOST || gBattleMons[gBankAttacker].type2 == TYPE_GHOST)) + && ((!IsTwoTurnsMove(gCurrentMove) || (gBattleMons[gBankAttacker].status2 & STATUS2_MULTIPLETURNS)))) + { + CancelMultiTurnMoves(gBankAttacker); + gBattleMoveFlags |= MOVESTATUS_MISSED; + gUnknown_02024250[gBankTarget] = 0; + gUnknown_02024258[gBankTarget] = 0; + gBattleCommunication[6] = 1; + gBattlescriptCurrInstr++; + } + else + { + gBattlescriptCurrInstr++; + } +} + +static void JumpIfMoveFailed(u8 adder, u16 move) +{ + const void* BS_ptr = gBattlescriptCurrInstr + adder; + if (gBattleMoveFlags & MOVESTATUS_NOEFFECT) + { + gUnknown_02024250[gBankTarget] = 0; + gUnknown_02024258[gBankTarget] = 0; + BS_ptr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + DestinyBondFlagUpdate(); + if (AbilityBattleEffects(ABILITYEFFECT_ABSORBING, gBankTarget, 0, 0, move)) + return; + } + gBattlescriptCurrInstr = BS_ptr; +} + +static void atk40_jump_if_move_affected_by_protect(void) +{ + if (TARGET_PROTECT_AFFECTED) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + JumpIfMoveFailed(5, 0); + gBattleCommunication[6] = 1; + } + else + { + gBattlescriptCurrInstr += 5; + } +} + +bool8 JumpIfMoveAffectedByProtect(u16 move) +{ + bool8 affected = FALSE; + if (TARGET_PROTECT_AFFECTED) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + JumpIfMoveFailed(7, move); + gBattleCommunication[6] = 1; + affected = TRUE; + } + return affected; +} + +bool8 AccuracyCalcHelper(u16 move) +{ + if (gStatuses3[gBankTarget] & STATUS3_ALWAYS_HITS && gDisableStructs[gBankTarget].bankWithSureHit == gBankAttacker) + { + JumpIfMoveFailed(7, move); + return TRUE; + } + + if (!(gHitMarker & HITMARKER_IGNORE_ON_AIR) && gStatuses3[gBankTarget] & STATUS3_ON_AIR) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + JumpIfMoveFailed(7, move); + return TRUE; + } + + gHitMarker &= ~HITMARKER_IGNORE_ON_AIR; + + if (!(gHitMarker & HITMARKER_IGNORE_UNDERGROUND) && gStatuses3[gBankTarget] & STATUS3_UNDERGROUND) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + JumpIfMoveFailed(7, move); + return TRUE; + } + + gHitMarker &= ~HITMARKER_IGNORE_UNDERGROUND; + + if (!(gHitMarker & HITMARKER_IGNORE_UNDERWATER) && gStatuses3[gBankTarget] & STATUS3_UNDERWATER) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + JumpIfMoveFailed(7, move); + return TRUE; + } + + gHitMarker &= ~HITMARKER_IGNORE_UNDERWATER; + + if ((WEATHER_HAS_EFFECT && (gBattleWeather & WEATHER_RAIN_ANY) && gBattleMoves[move].effect == EFFECT_THUNDER) + || (gBattleMoves[move].effect == EFFECT_ALWAYS_HIT || gBattleMoves[move].effect == EFFECT_VITAL_THROW)) + { + JumpIfMoveFailed(7, move); + return TRUE; + } + + return FALSE; +} + +static void atk01_accuracycheck(void) +{ + u16 move = BS2ScriptRead16(gBattlescriptCurrInstr + 5); + + if (move == 0xFFFE || move == 0xFFFF) + { + if (gStatuses3[gBankTarget] & STATUS3_ALWAYS_HITS && move == 0xFFFF && gDisableStructs[gBankTarget].bankWithSureHit == gBankAttacker) + gBattlescriptCurrInstr += 7; + else if (gStatuses3[gBankTarget] & (STATUS3_ON_AIR | STATUS3_UNDERGROUND | STATUS3_UNDERWATER)) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + else if (!JumpIfMoveAffectedByProtect(0)) + gBattlescriptCurrInstr += 7; + } + else + { + u8 type, moveAcc, holdEffect, quality; + s8 buff; + u16 calc; + + if (move == 0) + move = gCurrentMove; + + GET_MOVE_TYPE(move, type); + + if (JumpIfMoveAffectedByProtect(move)) + return; + if (AccuracyCalcHelper(move)) + return; + + if (gBattleMons[gBankTarget].status2 & STATUS2_FORESIGHT) + { + u8 acc = gBattleMons[gBankAttacker].statStages[STAT_STAGE_ACC]; + buff = acc; + } + else + { + u8 acc = gBattleMons[gBankAttacker].statStages[STAT_STAGE_ACC]; + buff = acc + 6 - gBattleMons[gBankTarget].statStages[STAT_STAGE_EVASION]; + } + + if (buff < 0) + buff = 0; + if (buff > 0xC) + buff = 0xC; + + moveAcc = gBattleMoves[move].accuracy; + // check Thunder on sunny weather + if (WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_SUN_ANY && gBattleMoves[move].effect == EFFECT_THUNDER) + moveAcc = 50; + + calc = sAccuracyStageRatios[buff].dividend * moveAcc; + calc /= sAccuracyStageRatios[buff].divisor; + + if (gBattleMons[gBankAttacker].ability == ABILITY_COMPOUND_EYES) + calc = (calc * 130) / 100; // 1.3 compound eyes boost + if (WEATHER_HAS_EFFECT && gBattleMons[gBankTarget].ability == ABILITY_SAND_VEIL && gBattleWeather & WEATHER_SANDSTORM_ANY) + calc = (calc * 80) / 100; // 1.2 sand veil loss + if (gBattleMons[gBankAttacker].ability == ABILITY_HUSTLE && type < 9) + calc = (calc * 80) / 100; // 1.2 hustle loss + + if (gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY) + { + holdEffect = gEnigmaBerries[gBankTarget].holdEffect; + quality = gEnigmaBerries[gBankTarget].holdEffectParam; + } + else + { + holdEffect = ItemId_GetHoldEffect(gBattleMons[gBankTarget].item); + quality = ItemId_GetHoldEffectParam(gBattleMons[gBankTarget].item); + } + + gStringBank = gBankTarget; + + if (holdEffect == HOLD_EFFECT_EVASION_UP) + calc = (calc * (100 - quality)) / 100; + + // final calculation + if ((Random() % 100 + 1) > calc) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && + (gBattleMoves[move].target == MOVE_TARGET_BOTH || gBattleMoves[move].target == MOVE_TARGET_FOES_AND_ALLY)) + gBattleCommunication[6] = 2; + else + gBattleCommunication[6] = 0; + + CheckWonderGuardAndLevitate(); + } + JumpIfMoveFailed(7, move); + } +} + +static void atk02_attackstring(void) +{ + if (gBattleExecBuffer) + return; + if (!(gHitMarker & (HITMARKER_NO_ATTACKSTRING | HITMARKER_ATTACKSTRING_PRINTED))) + { + PrepareStringBattle(4, gBankAttacker); + gHitMarker |= HITMARKER_ATTACKSTRING_PRINTED; + } + gBattlescriptCurrInstr++; + gBattleCommunication[MSG_DISPLAY] = 0; +} + +static void atk03_ppreduce(void) +{ + s32 ppToDeduct = 1; + + if (gBattleExecBuffer) + return; + + if (!gSpecialStatuses[gBankAttacker].flag20) + { + switch (gBattleMoves[gCurrentMove].target) + { + case MOVE_TARGET_FOES_AND_ALLY: + ppToDeduct += AbilityBattleEffects(ABILITYEFFECT_COUNT_ON_FIELD, gBankAttacker, ABILITY_PRESSURE, 0, 0); + break; + case MOVE_TARGET_BOTH: + case MOVE_TARGET_OPPONENTS_FIELD: + ppToDeduct += AbilityBattleEffects(ABILITYEFFECT_COUNT_OTHER_SIDE, gBankAttacker, ABILITY_PRESSURE, 0, 0); + break; + default: + if (gBankAttacker != gBankTarget && gBattleMons[gBankTarget].ability == ABILITY_PRESSURE) + ppToDeduct++; + break; + } + } + + if (!(gHitMarker & (HITMARKER_NO_PPDEDUCT | HITMARKER_NO_ATTACKSTRING)) && gBattleMons[gBankAttacker].pp[gCurrMovePos]) + { + gProtectStructs[gBankAttacker].notFirstStrike = 1; + + if (gBattleMons[gBankAttacker].pp[gCurrMovePos] > ppToDeduct) + gBattleMons[gBankAttacker].pp[gCurrMovePos] -= ppToDeduct; + else + gBattleMons[gBankAttacker].pp[gCurrMovePos] = 0; + + if (!(gBattleMons[gBankAttacker].status2 & STATUS2_TRANSFORMED) + && !((gDisableStructs[gBankAttacker].unk18_b) & gBitTable[gCurrMovePos])) + { + gActiveBank = gBankAttacker; + EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + gCurrMovePos, 0, 1, &gBattleMons[gBankAttacker].pp[gCurrMovePos]); + MarkBufferBankForExecution(gBankAttacker); + } + } + + gHitMarker &= ~(HITMARKER_NO_PPDEDUCT); + gBattlescriptCurrInstr++; +} + +static void atk04_critcalc(void) +{ + u8 holdEffect; + u16 item, critChance; + + item = gBattleMons[gBankAttacker].item; + + if (item == ITEM_ENIGMA_BERRY) + holdEffect = gEnigmaBerries[gBankAttacker].holdEffect; + else + holdEffect = ItemId_GetHoldEffect(item); + + gStringBank = gBankAttacker; + + critChance = 2 * ((gBattleMons[gBankAttacker].status2 & STATUS2_FOCUS_ENERGY) != 0) + + (gBattleMoves[gCurrentMove].effect == EFFECT_HIGH_CRITICAL) + + (gBattleMoves[gCurrentMove].effect == EFFECT_SKY_ATTACK) + + (gBattleMoves[gCurrentMove].effect == EFFECT_BLAZE_KICK) + + (gBattleMoves[gCurrentMove].effect == EFFECT_POISON_TAIL) + + (holdEffect == HOLD_EFFECT_SCOPE_LENS) + + 2 * (holdEffect == HOLD_EFFECT_LUCKY_PUNCH && gBattleMons[gBankAttacker].species == SPECIES_CHANSEY) + + 2 * (holdEffect == HOLD_EFFECT_STICK && gBattleMons[gBankAttacker].species == SPECIES_FARFETCHD); + + if (critChance > 4) + critChance = 4; + + if ((gBattleMons[gBankTarget].ability != ABILITY_BATTLE_ARMOR && gBattleMons[gBankTarget].ability != ABILITY_SHELL_ARMOR) + && !(gStatuses3[gBankAttacker] & STATUS3_CANT_SCORE_A_CRIT) + && !(gBattleTypeFlags & (BATTLE_TYPE_WALLY_TUTORIAL | BATTLE_TYPE_FIRST_BATTLE)) + && !(Random() % sCriticalHitChance[critChance])) + gCritMultiplier = 2; + else + gCritMultiplier = 1; + + gBattlescriptCurrInstr++; +} + +static void atk05_damagecalc1(void) +{ + u16 sideStatus = gSideAffecting[GET_BANK_SIDE(gBankTarget)]; + gBattleMoveDamage = CalculateBaseDamage(&gBattleMons[gBankAttacker], &gBattleMons[gBankTarget], gCurrentMove, + sideStatus, gDynamicBasePower, + gBattleStruct->dynamicMoveType, gBankAttacker, gBankTarget); + gBattleMoveDamage = gBattleMoveDamage * gCritMultiplier * gBattleScripting.dmgMultiplier; + + if (gStatuses3[gBankAttacker] & STATUS3_CHARGED_UP && gBattleMoves[gCurrentMove].type == TYPE_ELECTRIC) + gBattleMoveDamage *= 2; + if (gProtectStructs[gBankAttacker].helpingHand) + gBattleMoveDamage = gBattleMoveDamage * 15 / 10; + + gBattlescriptCurrInstr++; +} + +void AI_CalcDmg(u8 bankAtk, u8 bankDef) +{ + u16 sideStatus = gSideAffecting[GET_BANK_SIDE(bankDef)]; + gBattleMoveDamage = CalculateBaseDamage(&gBattleMons[bankAtk], &gBattleMons[bankDef], gCurrentMove, + sideStatus, gDynamicBasePower, + gBattleStruct->dynamicMoveType, bankAtk, bankDef); + gDynamicBasePower = 0; + gBattleMoveDamage = gBattleMoveDamage * gCritMultiplier * gBattleScripting.dmgMultiplier; + + if (gStatuses3[bankAtk] & STATUS3_CHARGED_UP && gBattleMoves[gCurrentMove].type == TYPE_ELECTRIC) + gBattleMoveDamage *= 2; + if (gProtectStructs[bankAtk].helpingHand) + gBattleMoveDamage = gBattleMoveDamage * 15 / 10; +} + +static void ModulateDmgByType(u8 multiplier) +{ + gBattleMoveDamage = gBattleMoveDamage * multiplier / 10; + if (gBattleMoveDamage == 0 && multiplier != 0) + gBattleMoveDamage = 1; + + switch (multiplier) + { + case TYPE_MUL_NO_EFFECT: + gBattleMoveFlags |= MOVESTATUS_NOTAFFECTED; + gBattleMoveFlags &= ~MOVESTATUS_NOTVERYEFFECTIVE; + gBattleMoveFlags &= ~MOVESTATUS_SUPEREFFECTIVE; + break; + case TYPE_MUL_NOT_EFFECTIVE: + if (gBattleMoves[gCurrentMove].power && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + if (gBattleMoveFlags & MOVESTATUS_SUPEREFFECTIVE) + gBattleMoveFlags &= ~MOVESTATUS_SUPEREFFECTIVE; + else + gBattleMoveFlags |= MOVESTATUS_NOTVERYEFFECTIVE; + } + break; + case TYPE_MUL_SUPER_EFFECTIVE: + if (gBattleMoves[gCurrentMove].power && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + if (gBattleMoveFlags & MOVESTATUS_NOTVERYEFFECTIVE) + gBattleMoveFlags &= ~MOVESTATUS_NOTVERYEFFECTIVE; + else + gBattleMoveFlags |= MOVESTATUS_SUPEREFFECTIVE; + } + break; + } +} + +#define TYPE_FORESIGHT 0xFE +#define TYPE_ENDTABLE 0xFF + +static void atk06_typecalc(void) +{ + s32 i = 0; + u8 moveType; + + if (gCurrentMove == MOVE_STRUGGLE) + { + gBattlescriptCurrInstr++; + return; + } + + GET_MOVE_TYPE(gCurrentMove, moveType); + + // check stab + if (gBattleMons[gBankAttacker].type1 == moveType || gBattleMons[gBankAttacker].type2 == moveType) + { + gBattleMoveDamage = gBattleMoveDamage * 15; + gBattleMoveDamage = gBattleMoveDamage / 10; + } + + if (gBattleMons[gBankTarget].ability == ABILITY_LEVITATE && moveType == TYPE_GROUND) + { + gLastUsedAbility = gBattleMons[gBankTarget].ability; + gBattleMoveFlags |= (MOVESTATUS_MISSED | MOVESTATUS_NOTAFFECTED); + gUnknown_02024250[gBankTarget] = 0; + gUnknown_02024258[gBankTarget] = 0; + gBattleCommunication[6] = moveType; + RecordAbilityBattle(gBankTarget, gLastUsedAbility); + } + else + { + while (gTypeEffectiveness[i] != TYPE_ENDTABLE) + { + if (gTypeEffectiveness[i] == TYPE_FORESIGHT) + { + if (gBattleMons[gBankTarget].status2 & STATUS2_FORESIGHT) + break; + i += 3; + continue; + } + else if (gTypeEffectiveness[i] == moveType) + { + // check type1 + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type1) + ModulateDmgByType(gTypeEffectiveness[i + 2]); + // check type2 + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type2 && + gBattleMons[gBankTarget].type1 != gBattleMons[gBankTarget].type2) + ModulateDmgByType(gTypeEffectiveness[i + 2]); + } + i += 3; + } + } + + if (gBattleMons[gBankTarget].ability == ABILITY_WONDER_GUARD && AttacksThisTurn(gBankAttacker, gCurrentMove) == 2 + && (!(gBattleMoveFlags & MOVESTATUS_SUPEREFFECTIVE) || ((gBattleMoveFlags & (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE)) == (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE))) + && gBattleMoves[gCurrentMove].power) + { + gLastUsedAbility = ABILITY_WONDER_GUARD; + gBattleMoveFlags |= MOVESTATUS_MISSED; + gUnknown_02024250[gBankTarget] = 0; + gUnknown_02024258[gBankTarget] = 0; + gBattleCommunication[6] = 3; + RecordAbilityBattle(gBankTarget, gLastUsedAbility); + } + if (gBattleMoveFlags & MOVESTATUS_NOTAFFECTED) + gProtectStructs[gBankAttacker].notEffective = 1; + + gBattlescriptCurrInstr++; +} + +static void CheckWonderGuardAndLevitate(void) +{ + u8 flags = 0; + s32 i = 0; + u8 moveType; + + if (gCurrentMove == MOVE_STRUGGLE || !gBattleMoves[gCurrentMove].power) + return; + + GET_MOVE_TYPE(gCurrentMove, moveType); + + if (gBattleMons[gBankTarget].ability == ABILITY_LEVITATE && moveType == TYPE_GROUND) + { + gLastUsedAbility = ABILITY_LEVITATE; + gBattleCommunication[6] = moveType; + RecordAbilityBattle(gBankTarget, ABILITY_LEVITATE); + return; + } + + while (gTypeEffectiveness[i] != TYPE_ENDTABLE) + { + if (gTypeEffectiveness[i] == TYPE_FORESIGHT) + { + if (gBattleMons[gBankTarget].status2 & STATUS2_FORESIGHT) + break; + i += 3; + continue; + } + if (gTypeEffectiveness[i] == moveType) + { + // check no effect + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type1 && gTypeEffectiveness[i + 2] == 0) + { + gBattleMoveFlags |= MOVESTATUS_NOTAFFECTED; + gProtectStructs[gBankAttacker].notEffective = 1; + } + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type2 && + gBattleMons[gBankTarget].type1 != gBattleMons[gBankTarget].type2 && + gTypeEffectiveness[i + 2] == TYPE_MUL_NO_EFFECT) + { + gBattleMoveFlags |= MOVESTATUS_NOTAFFECTED; + gProtectStructs[gBankAttacker].notEffective = 1; + } + + // check super effective + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type1 && gTypeEffectiveness[i + 2] == 20) + flags |= 1; + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type2 + && gBattleMons[gBankTarget].type1 != gBattleMons[gBankTarget].type2 + && gTypeEffectiveness[i + 2] == TYPE_MUL_SUPER_EFFECTIVE) + flags |= 1; + + // check not very effective + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type1 && gTypeEffectiveness[i + 2] == 5) + flags |= 2; + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type2 + && gBattleMons[gBankTarget].type1 != gBattleMons[gBankTarget].type2 + && gTypeEffectiveness[i + 2] == TYPE_MUL_NOT_EFFECTIVE) + flags |= 2; + } + i += 3; + } + + if (gBattleMons[gBankTarget].ability == ABILITY_WONDER_GUARD && AttacksThisTurn(gBankAttacker, gCurrentMove) == 2) + { + if (((flags & 2) || !(flags & 1)) && gBattleMoves[gCurrentMove].power) + { + gLastUsedAbility = ABILITY_WONDER_GUARD; + gBattleCommunication[6] = 3; + RecordAbilityBattle(gBankTarget, ABILITY_WONDER_GUARD); + } + } +} + +static void ModulateDmgByType2(u8 multiplier, u16 move, u8* flags) // same as ModulateDmgByType except different arguments +{ + gBattleMoveDamage = gBattleMoveDamage * multiplier / 10; + if (gBattleMoveDamage == 0 && multiplier != 0) + gBattleMoveDamage = 1; + + switch (multiplier) + { + case TYPE_MUL_NO_EFFECT: + *flags |= MOVESTATUS_NOTAFFECTED; + *flags &= ~MOVESTATUS_NOTVERYEFFECTIVE; + *flags &= ~MOVESTATUS_SUPEREFFECTIVE; + break; + case TYPE_MUL_NOT_EFFECTIVE: + if (gBattleMoves[move].power && !(*flags & MOVESTATUS_NOEFFECT)) + { + if (*flags & MOVESTATUS_SUPEREFFECTIVE) + *flags &= ~MOVESTATUS_SUPEREFFECTIVE; + else + *flags |= MOVESTATUS_NOTVERYEFFECTIVE; + } + break; + case TYPE_MUL_SUPER_EFFECTIVE: + if (gBattleMoves[move].power && !(*flags & MOVESTATUS_NOEFFECT)) + { + if (*flags & MOVESTATUS_NOTVERYEFFECTIVE) + *flags &= ~MOVESTATUS_NOTVERYEFFECTIVE; + else + *flags |= MOVESTATUS_SUPEREFFECTIVE; + } + break; + } +} + +u8 TypeCalc(u16 move, u8 bankAtk, u8 bankDef) +{ + s32 i = 0; + u8 flags = 0; + u8 moveType; + + if (move == MOVE_STRUGGLE) + return 0; + + moveType = gBattleMoves[move].type; + + // check stab + if (gBattleMons[bankAtk].type1 == moveType || gBattleMons[bankAtk].type2 == moveType) + { + gBattleMoveDamage = gBattleMoveDamage * 15; + gBattleMoveDamage = gBattleMoveDamage / 10; + } + + if (gBattleMons[bankDef].ability == ABILITY_LEVITATE && moveType == TYPE_GROUND) + { + flags |= (MOVESTATUS_MISSED | MOVESTATUS_NOTAFFECTED); + } + else + { + while (gTypeEffectiveness[i]!= TYPE_ENDTABLE) + { + if (gTypeEffectiveness[i] == TYPE_FORESIGHT) + { + if (gBattleMons[bankDef].status2 & STATUS2_FORESIGHT) + break; + i += 3; + continue; + } + + else if (gTypeEffectiveness[i] == moveType) + { + // check type1 + if (gTypeEffectiveness[i + 1] == gBattleMons[bankDef].type1) + ModulateDmgByType2(gTypeEffectiveness[i + 2], move, &flags); + // check type2 + if (gTypeEffectiveness[i + 1] == gBattleMons[bankDef].type2 && + gBattleMons[bankDef].type1 != gBattleMons[bankDef].type2) + ModulateDmgByType2(gTypeEffectiveness[i + 2], move, &flags); + } + i += 3; + } + } + + if (gBattleMons[bankDef].ability == ABILITY_WONDER_GUARD && !(flags & MOVESTATUS_MISSED) + && AttacksThisTurn(bankAtk, move) == 2 + && (!(flags & MOVESTATUS_SUPEREFFECTIVE) || ((flags & (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE)) == (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE))) + && gBattleMoves[move].power) + { + flags |= MOVESTATUS_MISSED; + } + return flags; +} + +u8 AI_TypeCalc(u16 move, u16 species, u8 ability) +{ + s32 i = 0; + u8 flags = 0; + u8 type1 = gBaseStats[species].type1, type2 = gBaseStats[species].type2; + u8 moveType; + + if (move == MOVE_STRUGGLE) + return 0; + + moveType = gBattleMoves[move].type; + + if (ability == ABILITY_LEVITATE && moveType == TYPE_GROUND) + { + flags = MOVESTATUS_MISSED | MOVESTATUS_NOTAFFECTED; + } + else + { + while (gTypeEffectiveness[i] != TYPE_ENDTABLE) + { + if (gTypeEffectiveness[i] == TYPE_FORESIGHT) + { + i += 3; + continue; + } + if (gTypeEffectiveness[i] == moveType) + { + // check type1 + if (gTypeEffectiveness[i + 1] == type1) + ModulateDmgByType2(gTypeEffectiveness[i + 2], move, &flags); + // check type2 + if (gTypeEffectiveness[i + 1] == type2 && type1 != type2) + ModulateDmgByType2(gTypeEffectiveness[i + 2], move, &flags); + } + i += 3; + } + } + if (ability == ABILITY_WONDER_GUARD + && (!(flags & MOVESTATUS_SUPEREFFECTIVE) || ((flags & (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE)) == (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE))) + && gBattleMoves[move].power) + flags |= MOVESTATUS_NOTAFFECTED; + return flags; +} + +// Multiplies the damage by a random factor between 85% to 100% inclusive +static inline void ApplyRandomDmgMultiplier(void) +{ + u16 rand = Random(); + u16 randPercent = 100 - (rand % 16); + + if (gBattleMoveDamage != 0) + { + gBattleMoveDamage *= randPercent; + gBattleMoveDamage /= 100; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + } +} + +static void Unused_ApplyRandomDmgMultiplier(void) +{ + ApplyRandomDmgMultiplier(); +} + +static void atk07_dmg_adjustment(void) +{ + u8 holdEffect, quality; + + ApplyRandomDmgMultiplier(); + + if (gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY) + { + holdEffect = gEnigmaBerries[gBankTarget].holdEffect, quality = gEnigmaBerries[gBankTarget].holdEffectParam; + } + else + { + holdEffect = ItemId_GetHoldEffect(gBattleMons[gBankTarget].item); + quality = ItemId_GetHoldEffectParam(gBattleMons[gBankTarget].item); + } + + gStringBank = gBankTarget; + + if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < quality) + { + RecordItemEffectBattle(gBankTarget, holdEffect); + gSpecialStatuses[gBankTarget].focusBanded = 1; + } + if (gBattleMons[gBankTarget].status2 & STATUS2_SUBSTITUTE) + goto END; + if (gBattleMoves[gCurrentMove].effect != EFFECT_FALSE_SWIPE && !gProtectStructs[gBankTarget].endured + && !gSpecialStatuses[gBankTarget].focusBanded) + goto END; + + if (gBattleMons[gBankTarget].hp > gBattleMoveDamage) + goto END; + + gBattleMoveDamage = gBattleMons[gBankTarget].hp - 1; + + if (gProtectStructs[gBankTarget].endured) + { + gBattleMoveFlags |= MOVESTATUS_ENDURED; + } + else if (gSpecialStatuses[gBankTarget].focusBanded) + { + gBattleMoveFlags |= MOVESTATUS_HUNGON; + gLastUsedItem = gBattleMons[gBankTarget].item; + } + + END: + gBattlescriptCurrInstr++; +} + +static void atk08_dmg_adjustment2(void) // The same as 0x7 except it doesn't check for false swipe move effect. +{ + u8 holdEffect, quality; + + ApplyRandomDmgMultiplier(); + + if (gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY) + { + holdEffect = gEnigmaBerries[gBankTarget].holdEffect, quality = gEnigmaBerries[gBankTarget].holdEffectParam; + } + else + { + holdEffect = ItemId_GetHoldEffect(gBattleMons[gBankTarget].item); + quality = ItemId_GetHoldEffectParam(gBattleMons[gBankTarget].item); + } + + gStringBank = gBankTarget; + + if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < quality) + { + RecordItemEffectBattle(gBankTarget, holdEffect); + gSpecialStatuses[gBankTarget].focusBanded = 1; + } + if (gBattleMons[gBankTarget].status2 & STATUS2_SUBSTITUTE) + goto END; + if (!gProtectStructs[gBankTarget].endured && !gSpecialStatuses[gBankTarget].focusBanded) + goto END; + if (gBattleMons[gBankTarget].hp > gBattleMoveDamage) + goto END; + + gBattleMoveDamage = gBattleMons[gBankTarget].hp - 1; + + if (gProtectStructs[gBankTarget].endured) + { + gBattleMoveFlags |= MOVESTATUS_ENDURED; + } + else if (gSpecialStatuses[gBankTarget].focusBanded) + { + gBattleMoveFlags |= MOVESTATUS_HUNGON; + gLastUsedItem = gBattleMons[gBankTarget].item; + } + + END: + gBattlescriptCurrInstr++; +} + +static void atk09_attackanimation(void) +{ + if (gBattleExecBuffer) + return; + + if ((gHitMarker & HITMARKER_NO_ANIMATIONS) && (gCurrentMove != MOVE_TRANSFORM && gCurrentMove != MOVE_SUBSTITUTE)) + { + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_Pausex20; + gBattleScripting.animTurn++; + gBattleScripting.animTargetsHit++; + } + else + { + if ((gBattleMoves[gCurrentMove].target & MOVE_TARGET_BOTH + || gBattleMoves[gCurrentMove].target & MOVE_TARGET_FOES_AND_ALLY + || gBattleMoves[gCurrentMove].target & MOVE_TARGET_DEPENDS) + && gBattleScripting.animTargetsHit) + { + gBattlescriptCurrInstr++; + return; + } + if (!(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + u8 multihit; + + gActiveBank = gBankAttacker; + + if (gBattleMons[gBankTarget].status2 & STATUS2_SUBSTITUTE) + multihit = gMultiHitCounter; + else if (gMultiHitCounter != 0 && gMultiHitCounter != 1) + { + if (gBattleMons[gBankTarget].hp <= gBattleMoveDamage) + multihit = 1; + else + multihit = gMultiHitCounter; + } + else + multihit = gMultiHitCounter; + + EmitMoveAnimation(0, gCurrentMove, gBattleScripting.animTurn, gBattleMovePower, gBattleMoveDamage, gBattleMons[gBankAttacker].friendship, &gDisableStructs[gBankAttacker], multihit); + gBattleScripting.animTurn += 1; + gBattleScripting.animTargetsHit += 1; + MarkBufferBankForExecution(gBankAttacker); + gBattlescriptCurrInstr++; + } + else + { + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_Pausex20; + } + } +} + +static void atk0A_waitanimation(void) +{ + if (gBattleExecBuffer == 0) + gBattlescriptCurrInstr++; +} + +static void atk0B_healthbarupdate(void) +{ + if (gBattleExecBuffer) + return; + + if (!(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + + if (gBattleMons[gActiveBank].status2 & STATUS2_SUBSTITUTE && gDisableStructs[gActiveBank].substituteHP && !(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE)) + { + PrepareStringBattle(0x80, gActiveBank); + } + else + { + s16 healthValue; + + s32 currDmg = gBattleMoveDamage; + s32 maxPossibleDmgValue = 10000; // not present in R/S, ensures that huge damage values don't change sign + + if (currDmg <= maxPossibleDmgValue) + healthValue = currDmg; + else + healthValue = maxPossibleDmgValue; + + EmitHealthBarUpdate(0, healthValue); + MarkBufferBankForExecution(gActiveBank); + + if (GetBankSide(gActiveBank) == SIDE_PLAYER && gBattleMoveDamage > 0) + gBattleResults.unk5_0 = 1; + } + } + + gBattlescriptCurrInstr += 2; +} + +static void atk0C_datahpupdate(void) +{ + u32 moveType; + + if (gBattleExecBuffer) + return; + + if (gBattleStruct->dynamicMoveType == 0) + moveType = gBattleMoves[gCurrentMove].type; + else if (!(gBattleStruct->dynamicMoveType & 0x40)) + moveType = gBattleStruct->dynamicMoveType & 0x3F; + else + moveType = gBattleMoves[gCurrentMove].type; + + if (!(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + if (gBattleMons[gActiveBank].status2 & STATUS2_SUBSTITUTE && gDisableStructs[gActiveBank].substituteHP && !(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE)) + { + if (gDisableStructs[gActiveBank].substituteHP >= gBattleMoveDamage) + { + if (gSpecialStatuses[gActiveBank].moveturnLostHP == 0) + gSpecialStatuses[gActiveBank].moveturnLostHP = gBattleMoveDamage; + gDisableStructs[gActiveBank].substituteHP -= gBattleMoveDamage; + gHpDealt = gBattleMoveDamage; + } + else + { + if (gSpecialStatuses[gActiveBank].moveturnLostHP == 0) + gSpecialStatuses[gActiveBank].moveturnLostHP = gDisableStructs[gActiveBank].substituteHP; + gHpDealt = gDisableStructs[gActiveBank].substituteHP; + gDisableStructs[gActiveBank].substituteHP = 0; + } + // check substitute fading + if (gDisableStructs[gActiveBank].substituteHP == 0) + { + gBattlescriptCurrInstr += 2; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_SubstituteFade; + return; + } + } + else + { + gHitMarker &= ~(HITMARKER_IGNORE_SUBSTITUTE); + if (gBattleMoveDamage < 0) // hp goes up + { + gBattleMons[gActiveBank].hp -= gBattleMoveDamage; + if (gBattleMons[gActiveBank].hp > gBattleMons[gActiveBank].maxHP) + gBattleMons[gActiveBank].hp = gBattleMons[gActiveBank].maxHP; + + } + else // hp goes down + { + if (gHitMarker & HITMARKER_x20) + { + gHitMarker &= ~(HITMARKER_x20); + } + else + { + gTakenDmg[gActiveBank] += gBattleMoveDamage; + if (gBattlescriptCurrInstr[1] == BS_GET_TARGET) + gTakenDmgBanks[gActiveBank] = gBankAttacker; + else + gTakenDmgBanks[gActiveBank] = gBankTarget; + } + + if (gBattleMons[gActiveBank].hp > gBattleMoveDamage) + { + gBattleMons[gActiveBank].hp -= gBattleMoveDamage; + gHpDealt = gBattleMoveDamage; + } + else + { + gHpDealt = gBattleMons[gActiveBank].hp; + gBattleMons[gActiveBank].hp = 0; + } + + if (!gSpecialStatuses[gActiveBank].moveturnLostHP && !(gHitMarker & HITMARKER_x100000)) + gSpecialStatuses[gActiveBank].moveturnLostHP = gHpDealt; + + if (moveType <= 8 && !(gHitMarker & HITMARKER_x100000) && gCurrentMove != MOVE_PAIN_SPLIT) + { + gProtectStructs[gActiveBank].physicalDmg = gHpDealt; + gSpecialStatuses[gActiveBank].moveturnLostHP_physical = gHpDealt; + if (gBattlescriptCurrInstr[1] == BS_GET_TARGET) + { + gProtectStructs[gActiveBank].physicalBank = gBankAttacker; + gSpecialStatuses[gActiveBank].moveturnPhysicalBank = gBankAttacker; + } + else + { + gProtectStructs[gActiveBank].physicalBank = gBankTarget; + gSpecialStatuses[gActiveBank].moveturnPhysicalBank = gBankTarget; + } + } + else if (moveType > 8 && !(gHitMarker & HITMARKER_x100000)) + { + gProtectStructs[gActiveBank].specialDmg = gHpDealt; + gSpecialStatuses[gActiveBank].moveturnLostHP_special = gHpDealt; + if (gBattlescriptCurrInstr[1] == BS_GET_TARGET) + { + gProtectStructs[gActiveBank].specialBank = gBankAttacker; + gSpecialStatuses[gActiveBank].moveturnSpecialBank = gBankAttacker; + } + else + { + gProtectStructs[gActiveBank].specialBank = gBankTarget; + gSpecialStatuses[gActiveBank].moveturnSpecialBank = gBankTarget; + } + } + } + gHitMarker &= ~(HITMARKER_x100000); + EmitSetMonData(0, REQUEST_HP_BATTLE, 0, 2, &gBattleMons[gActiveBank].hp); + MarkBufferBankForExecution(gActiveBank); + } + } + else + { + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + if (gSpecialStatuses[gActiveBank].moveturnLostHP == 0) + gSpecialStatuses[gActiveBank].moveturnLostHP = 0xFFFF; + } + gBattlescriptCurrInstr += 2; +} + +static void atk0D_critmessage(void) +{ + if (gBattleExecBuffer == 0) + { + if (gCritMultiplier == 2 && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + PrepareStringBattle(0xD9, gBankAttacker); + gBattleCommunication[MSG_DISPLAY] = 1; + } + gBattlescriptCurrInstr++; + } +} + +static void atk0E_effectiveness_sound(void) +{ + if (gBattleExecBuffer) + return; + + gActiveBank = gBankTarget; + if (!(gBattleMoveFlags & MOVESTATUS_MISSED)) + { + switch (gBattleMoveFlags & (u8)(~(MOVESTATUS_MISSED))) + { + case MOVESTATUS_SUPEREFFECTIVE: + EmitEffectivenessSound(0, SE_KOUKA_H); + MarkBufferBankForExecution(gActiveBank); + break; + case MOVESTATUS_NOTVERYEFFECTIVE: + EmitEffectivenessSound(0, SE_KOUKA_L); + MarkBufferBankForExecution(gActiveBank); + break; + case MOVESTATUS_NOTAFFECTED: + case MOVESTATUS_FAILED: + // no sound + break; + case MOVESTATUS_ENDURED: + case MOVESTATUS_ONEHITKO: + case MOVESTATUS_HUNGON: + default: + if (gBattleMoveFlags & MOVESTATUS_SUPEREFFECTIVE) + { + EmitEffectivenessSound(0, SE_KOUKA_H); + MarkBufferBankForExecution(gActiveBank); + } + else if (gBattleMoveFlags & MOVESTATUS_NOTVERYEFFECTIVE) + { + EmitEffectivenessSound(0, SE_KOUKA_L); + MarkBufferBankForExecution(gActiveBank); + } + else if (!(gBattleMoveFlags & (MOVESTATUS_NOTAFFECTED | MOVESTATUS_FAILED))) + { + EmitEffectivenessSound(0, SE_KOUKA_M); + MarkBufferBankForExecution(gActiveBank); + } + break; + } + } + gBattlescriptCurrInstr++; +} + +static void atk0F_resultmessage(void) +{ + u32 stringId = 0; + + if (gBattleExecBuffer) + return; + + if (gBattleMoveFlags & MOVESTATUS_MISSED && (!(gBattleMoveFlags & MOVESTATUS_NOTAFFECTED) || gBattleCommunication[6] > 2)) + { + stringId = gMissStringIds[gBattleCommunication[6]]; + gBattleCommunication[MSG_DISPLAY] = 1; + } + else + { + gBattleCommunication[MSG_DISPLAY] = 1; + switch (gBattleMoveFlags & (u8)(~(MOVESTATUS_MISSED))) + { + case MOVESTATUS_SUPEREFFECTIVE: + stringId = 0xDE; + break; + case MOVESTATUS_NOTVERYEFFECTIVE: + stringId = 0xDD; + break; + case MOVESTATUS_ONEHITKO: + stringId = 0xDA; + break; + case MOVESTATUS_ENDURED: + stringId = 0x99; + break; + case MOVESTATUS_FAILED: + stringId = 0xE5; + break; + case MOVESTATUS_NOTAFFECTED: + stringId = 0x1B; + break; + case MOVESTATUS_HUNGON: + gLastUsedItem = gBattleMons[gBankTarget].item; + gStringBank = gBankTarget; + gBattleMoveFlags &= ~(MOVESTATUS_ENDURED | MOVESTATUS_HUNGON); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_HangedOnMsg; + return; + default: + if (gBattleMoveFlags & MOVESTATUS_NOTAFFECTED) + { + stringId = 0x1B; + } + else if (gBattleMoveFlags & MOVESTATUS_ONEHITKO) + { + gBattleMoveFlags &= ~(MOVESTATUS_ONEHITKO); + gBattleMoveFlags &= ~(MOVESTATUS_SUPEREFFECTIVE); + gBattleMoveFlags &= ~(MOVESTATUS_NOTVERYEFFECTIVE); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_OneHitKOMsg; + return; + } + else if (gBattleMoveFlags & MOVESTATUS_ENDURED) + { + gBattleMoveFlags &= ~(MOVESTATUS_ENDURED | MOVESTATUS_HUNGON); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_EnduredMsg; + return; + } + else if (gBattleMoveFlags & MOVESTATUS_HUNGON) + { + gLastUsedItem = gBattleMons[gBankTarget].item; + gStringBank = gBankTarget; + gBattleMoveFlags &= ~(MOVESTATUS_ENDURED | MOVESTATUS_HUNGON); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_HangedOnMsg; + return; + } + else if (gBattleMoveFlags & MOVESTATUS_FAILED) + { + stringId = 0xE5; + } + else + { + gBattleCommunication[MSG_DISPLAY] = 0; + } + } + } + + if (stringId) + PrepareStringBattle(stringId, gBankAttacker); + + gBattlescriptCurrInstr++; +} + +static void atk10_printstring(void) +{ + if (gBattleExecBuffer == 0) + { + u16 var = BS2ScriptRead16(gBattlescriptCurrInstr + 1); + PrepareStringBattle(var, gBankAttacker); + gBattlescriptCurrInstr += 3; + gBattleCommunication[MSG_DISPLAY] = 1; + } +} + +static void atk11_printstring_playeronly(void) +{ + gActiveBank = gBankAttacker; + + EmitPrintStringPlayerOnly(0, BS2ScriptRead16(gBattlescriptCurrInstr + 1)); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 3; + gBattleCommunication[MSG_DISPLAY] = 1; +} + +static void atk12_waitmessage(void) +{ + if (gBattleExecBuffer == 0) + { + if (!gBattleCommunication[MSG_DISPLAY]) + { + gBattlescriptCurrInstr += 3; + } + else + { + u16 toWait = BS2ScriptRead16(gBattlescriptCurrInstr + 1); + if (++gPauseCounterBattle >= toWait) + { + gPauseCounterBattle = 0; + gBattlescriptCurrInstr += 3; + gBattleCommunication[MSG_DISPLAY] = 0; + } + } + } +} + +static void atk13_printfromtable(void) +{ + if (gBattleExecBuffer == 0) + { + const u16 *ptr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + ptr += gBattleCommunication[MULTISTRING_CHOOSER]; + + PrepareStringBattle(*ptr, gBankAttacker); + + gBattlescriptCurrInstr += 5; + gBattleCommunication[MSG_DISPLAY] = 1; + } +} + +static void atk14_printfromtable_playeronly(void) +{ + if (gBattleExecBuffer == 0) + { + const u16 *ptr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + ptr += gBattleCommunication[MULTISTRING_CHOOSER]; + + gActiveBank = gBankAttacker; + EmitPrintStringPlayerOnly(0, *ptr); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 5; + gBattleCommunication[MSG_DISPLAY] = 1; + } +} + +u8 BankGetTurnOrder(u8 bank) +{ + s32 i; + for (i = 0; i < gNoOfAllBanks; i++) + { + if (gTurnOrder[i] == bank) + break; + } + return i; +} + +#define INCREMENT_RESET_RETURN \ +{ \ + gBattlescriptCurrInstr++; \ + gBattleCommunication[MOVE_EFFECT_BYTE] = 0; \ + return; \ +} + +#define RESET_RETURN \ +{ \ + gBattleCommunication[MOVE_EFFECT_BYTE] = 0; \ + return; \ +} + +void SetMoveEffect(bool8 primary, u8 certain) +{ + bool32 statusChanged = FALSE; + u8 affectsUser = 0; // 0x40 otherwise + bool32 noSunCanFreeze = TRUE; + + if (gBattleCommunication[MOVE_EFFECT_BYTE] & MOVE_EFFECT_AFFECTS_USER) + { + gEffectBank = gBankAttacker; // bank that effects get applied on + gBattleCommunication[MOVE_EFFECT_BYTE] &= ~(MOVE_EFFECT_AFFECTS_USER); + affectsUser = MOVE_EFFECT_AFFECTS_USER; + gBattleScripting.bank = gBankTarget; // theoretically the attacker + } + else + { + gEffectBank = gBankTarget; + gBattleScripting.bank = gBankAttacker; + } + + if (gBattleMons[gEffectBank].ability == ABILITY_SHIELD_DUST && !(gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + && !primary && gBattleCommunication[MOVE_EFFECT_BYTE] <= 9) + INCREMENT_RESET_RETURN + + if (gSideAffecting[GET_BANK_SIDE(gEffectBank)] & SIDE_STATUS_SAFEGUARD && !(gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + && !primary && gBattleCommunication[MOVE_EFFECT_BYTE] <= 7) + INCREMENT_RESET_RETURN + + if (gBattleMons[gEffectBank].hp == 0 + && gBattleCommunication[MOVE_EFFECT_BYTE] != MOVE_EFFECT_PAYDAY + && gBattleCommunication[MOVE_EFFECT_BYTE] != MOVE_EFFECT_STEAL_ITEM) + INCREMENT_RESET_RETURN + + if (gBattleMons[gEffectBank].status2 & STATUS2_SUBSTITUTE && affectsUser != MOVE_EFFECT_AFFECTS_USER) + INCREMENT_RESET_RETURN + + if (gBattleCommunication[MOVE_EFFECT_BYTE] <= 6) // status change + { + switch (sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]) + { + case STATUS_SLEEP: + // check active uproar + if (gBattleMons[gEffectBank].ability != ABILITY_SOUNDPROOF) + { + for (gActiveBank = 0; + gActiveBank < gNoOfAllBanks && !(gBattleMons[gActiveBank].status2 & STATUS2_UPROAR); + gActiveBank++) + {} + } + else + gActiveBank = gNoOfAllBanks; + + if (gBattleMons[gEffectBank].status1) + break; + if (gActiveBank != gNoOfAllBanks) + break; + if (gBattleMons[gEffectBank].ability == ABILITY_VITAL_SPIRIT) + break; + if (gBattleMons[gEffectBank].ability == ABILITY_INSOMNIA) + break; + + CancelMultiTurnMoves(gEffectBank); + statusChanged = TRUE; + break; + case STATUS_POISON: + if (gBattleMons[gEffectBank].ability == ABILITY_IMMUNITY + && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) + { + gLastUsedAbility = ABILITY_IMMUNITY; + RecordAbilityBattle(gEffectBank, ABILITY_IMMUNITY); + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_PSNPrevention; + + if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD); + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + RESET_RETURN + } + if ((gBattleMons[gEffectBank].type1 == TYPE_POISON || gBattleMons[gEffectBank].type2 == TYPE_POISON + || gBattleMons[gEffectBank].type1 == TYPE_STEEL || gBattleMons[gEffectBank].type2 == TYPE_STEEL) + && (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) + { + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_PSNPrevention; + + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + RESET_RETURN + } + if (gBattleMons[gEffectBank].type1 == TYPE_POISON) + break; + if (gBattleMons[gEffectBank].type2 == TYPE_POISON) + break; + if (gBattleMons[gEffectBank].type1 == TYPE_STEEL) + break; + if (gBattleMons[gEffectBank].type2 == TYPE_STEEL) + break; + if (gBattleMons[gEffectBank].status1) + break; + if (gBattleMons[gEffectBank].ability == ABILITY_IMMUNITY) + break; + + statusChanged = TRUE; + break; + case STATUS_BURN: + if (gBattleMons[gEffectBank].ability == ABILITY_WATER_VEIL + && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) + { + gLastUsedAbility = ABILITY_WATER_VEIL; + RecordAbilityBattle(gEffectBank, ABILITY_WATER_VEIL); + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_BRNPrevention; + if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD); + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + RESET_RETURN + } + if ((gBattleMons[gEffectBank].type1 == TYPE_FIRE + || gBattleMons[gEffectBank].type2 == TYPE_FIRE) + && (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) + { + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_BRNPrevention; + + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + RESET_RETURN + } + if (gBattleMons[gEffectBank].type1 == TYPE_FIRE) + break; + if (gBattleMons[gEffectBank].type2 == TYPE_FIRE) + break; + if (gBattleMons[gEffectBank].ability == ABILITY_WATER_VEIL) + break; + if (gBattleMons[gEffectBank].status1) + break; + + statusChanged = TRUE; + break; + case STATUS_FREEZE: + if (WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_SUN_ANY) + noSunCanFreeze = FALSE; + if (gBattleMons[gEffectBank].type1 == TYPE_ICE) + break; + if (gBattleMons[gEffectBank].type2 == TYPE_ICE) + break; + if (gBattleMons[gEffectBank].status1) + break; + if (noSunCanFreeze == 0) + break; + if (gBattleMons[gEffectBank].ability == ABILITY_MAGMA_ARMOR) + break; + + CancelMultiTurnMoves(gEffectBank); + statusChanged = TRUE; + break; + case STATUS_PARALYSIS: + if (gBattleMons[gEffectBank].ability == ABILITY_LIMBER) + { + if (primary == TRUE || certain == MOVE_EFFECT_CERTAIN) + { + gLastUsedAbility = ABILITY_LIMBER; + RecordAbilityBattle(gEffectBank, ABILITY_LIMBER); + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_PRLZPrevention; + + if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD); + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + RESET_RETURN + } + else + break; + } + if (gBattleMons[gEffectBank].status1) + break; + + statusChanged = TRUE; + break; + case STATUS_TOXIC_POISON: + if (gBattleMons[gEffectBank].ability == ABILITY_IMMUNITY && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) + { + gLastUsedAbility = ABILITY_IMMUNITY; + RecordAbilityBattle(gEffectBank, ABILITY_IMMUNITY); + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_PSNPrevention; + + if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD); + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + RESET_RETURN + } + if ((gBattleMons[gEffectBank].type1 == TYPE_POISON || gBattleMons[gEffectBank].type2 == TYPE_POISON + || gBattleMons[gEffectBank].type1 == TYPE_STEEL || gBattleMons[gEffectBank].type2 == TYPE_STEEL) + && (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) + { + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_PSNPrevention; + + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + RESET_RETURN + } + if (gBattleMons[gEffectBank].status1) + break; + if (gBattleMons[gEffectBank].type1 != TYPE_POISON + && gBattleMons[gEffectBank].type2 != TYPE_POISON + && gBattleMons[gEffectBank].type1 != TYPE_STEEL + && gBattleMons[gEffectBank].type2 != TYPE_STEEL) + { + if (gBattleMons[gEffectBank].ability == ABILITY_IMMUNITY) + break; + + // It's redundant, because at this point we know the status1 value is 0. + gBattleMons[gEffectBank].status1 &= ~(STATUS_TOXIC_POISON); + gBattleMons[gEffectBank].status1 &= ~(STATUS_POISON); + statusChanged = TRUE; + break; + } + else + { + gBattleMoveFlags |= MOVESTATUS_NOTAFFECTED; + } + break; + } + if (statusChanged == TRUE) + { + BattleScriptPush(gBattlescriptCurrInstr + 1); + + if (sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]] == STATUS_SLEEP) + gBattleMons[gEffectBank].status1 |= ((Random() & 3) + 2); + else + gBattleMons[gEffectBank].status1 |= sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]; + + gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; + + gActiveBank = gEffectBank; + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gEffectBank].status1); + MarkBufferBankForExecution(gActiveBank); + + if (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + gHitMarker &= ~(HITMARKER_IGNORE_SAFEGUARD); + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + + // for synchronize + + if (gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_POISON + || gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_TOXIC + || gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_PARALYSIS + || gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_BURN) + { + u8* synchronizeEffect = &gBattleStruct->synchronizeMoveEffect; + *synchronizeEffect = gBattleCommunication[MOVE_EFFECT_BYTE]; + gHitMarker |= HITMARKER_SYNCHRONISE_EFFECT; + } + return; + } + else if (statusChanged == FALSE) + { + gBattleCommunication[MOVE_EFFECT_BYTE] = 0; + gBattlescriptCurrInstr++; + return; + } + return; + } + else + { + if (gBattleMons[gEffectBank].status2 & sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]) + { + gBattlescriptCurrInstr++; + } + else + { + u8 side; + switch (gBattleCommunication[MOVE_EFFECT_BYTE]) + { + case MOVE_EFFECT_CONFUSION: + if (gBattleMons[gEffectBank].ability == ABILITY_OWN_TEMPO + || gBattleMons[gEffectBank].status2 & STATUS2_CONFUSION) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleMons[gEffectBank].status2 |= (((Random()) % 0x4)) + 2; + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; + } + break; + case MOVE_EFFECT_FLINCH: + if (gBattleMons[gEffectBank].ability == ABILITY_INNER_FOCUS) + { + if (primary == TRUE || certain == MOVE_EFFECT_CERTAIN) + { + gLastUsedAbility = ABILITY_INNER_FOCUS; + RecordAbilityBattle(gEffectBank, ABILITY_INNER_FOCUS); + gBattlescriptCurrInstr = BattleScript_FlinchPrevention; + } + else + { + gBattlescriptCurrInstr++; + } + } + else + { + if (BankGetTurnOrder(gEffectBank) > gCurrentMoveTurn) + gBattleMons[gEffectBank].status2 |= sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]; + gBattlescriptCurrInstr++; + } + break; + case MOVE_EFFECT_UPROAR: + if (!(gBattleMons[gEffectBank].status2 & STATUS2_UPROAR)) + { + + gBattleMons[gEffectBank].status2 |= STATUS2_MULTIPLETURNS; + gLockedMoves[gEffectBank] = gCurrentMove; + gBattleMons[gEffectBank].status2 |= ((Random() & 3) + 2) << 4; + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; + } + else + { + gBattlescriptCurrInstr++; + } + break; + case MOVE_EFFECT_PAYDAY: + if (GET_BANK_SIDE(gBankAttacker) == SIDE_PLAYER) + { + u16 PayDay = gPaydayMoney; + gPaydayMoney += (gBattleMons[gBankAttacker].level * 5); + if (PayDay > gPaydayMoney) + gPaydayMoney = 0xFFFF; + } + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; + break; + case MOVE_EFFECT_TRI_ATTACK: + if (gBattleMons[gEffectBank].status1) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleCommunication[MOVE_EFFECT_BYTE] = Random() % 3 + 3; + SetMoveEffect(FALSE, 0); + } + break; + case MOVE_EFFECT_CHARGING: + gBattleMons[gEffectBank].status2 |= STATUS2_MULTIPLETURNS; + gLockedMoves[gEffectBank] = gCurrentMove; + gProtectStructs[gEffectBank].chargingTurn = 1; + gBattlescriptCurrInstr++; + break; + case MOVE_EFFECT_WRAP: + if (gBattleMons[gEffectBank].status2 & STATUS2_WRAPPED) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleMons[gEffectBank].status2 |= ((Random() & 3) + 3) << 0xD; + + *(gBattleStruct->wrappedMove + gEffectBank * 2 + 0) = gCurrentMove; + *(gBattleStruct->wrappedMove + gEffectBank * 2 + 1) = gCurrentMove >> 8; + *(gBattleStruct->wrappedBy + gEffectBank) = gBankAttacker; + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; + + for (gBattleCommunication[MULTISTRING_CHOOSER] = 0; ; gBattleCommunication[MULTISTRING_CHOOSER]++) + { + if (gBattleCommunication[MULTISTRING_CHOOSER] > 4) + break; + if (gTrappingMoves[gBattleCommunication[MULTISTRING_CHOOSER]] == gCurrentMove) + break; + } + } + break; + case MOVE_EFFECT_RECOIL_25: // 25% recoil + gBattleMoveDamage = (gHpDealt) / 4; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; + break; + case MOVE_EFFECT_ATK_PLUS_1: + case MOVE_EFFECT_DEF_PLUS_1: + case MOVE_EFFECT_SPD_PLUS_1: + case MOVE_EFFECT_SP_ATK_PLUS_1: + case MOVE_EFFECT_SP_DEF_PLUS_1: + case MOVE_EFFECT_ACC_PLUS_1: + case MOVE_EFFECT_EVS_PLUS_1: + if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(1), + gBattleCommunication[MOVE_EFFECT_BYTE] - MOVE_EFFECT_ATK_PLUS_1 + 1, + affectsUser, 0)) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleScripting.animArg1 = gBattleCommunication[MOVE_EFFECT_BYTE] & ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); + gBattleScripting.animArg2 = 0; + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_StatUp; + } + break; + case MOVE_EFFECT_ATK_MINUS_1: + case MOVE_EFFECT_DEF_MINUS_1: + case MOVE_EFFECT_SPD_MINUS_1: + case MOVE_EFFECT_SP_ATK_MINUS_1: + case MOVE_EFFECT_SP_DEF_MINUS_1: + case MOVE_EFFECT_ACC_MINUS_1: + case MOVE_EFFECT_EVS_MINUS_1: + if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(1) | STAT_BUFF_NEGATIVE, + gBattleCommunication[MOVE_EFFECT_BYTE] - MOVE_EFFECT_ATK_MINUS_1 + 1, + affectsUser, 0)) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleScripting.animArg1 = gBattleCommunication[MOVE_EFFECT_BYTE] & ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); + gBattleScripting.animArg2 = 0; + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_StatDown; + } + break; + case MOVE_EFFECT_ATK_PLUS_2: + case MOVE_EFFECT_DEF_PLUS_2: + case MOVE_EFFECT_SPD_PLUS_2: + case MOVE_EFFECT_SP_ATK_PLUS_2: + case MOVE_EFFECT_SP_DEF_PLUS_2: + case MOVE_EFFECT_ACC_PLUS_2: + case MOVE_EFFECT_EVS_PLUS_2: + if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(2), + gBattleCommunication[MOVE_EFFECT_BYTE] - MOVE_EFFECT_ATK_PLUS_2 + 1, + affectsUser, 0)) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleScripting.animArg1 = gBattleCommunication[MOVE_EFFECT_BYTE] & ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); + gBattleScripting.animArg2 = 0; + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_StatUp; + } + break; + case MOVE_EFFECT_ATK_MINUS_2: + case MOVE_EFFECT_DEF_MINUS_2: + case MOVE_EFFECT_SPD_MINUS_2: + case MOVE_EFFECT_SP_ATK_MINUS_2: + case MOVE_EFFECT_SP_DEF_MINUS_2: + case MOVE_EFFECT_ACC_MINUS_2: + case MOVE_EFFECT_EVS_MINUS_2: + if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(2) | STAT_BUFF_NEGATIVE, + gBattleCommunication[MOVE_EFFECT_BYTE] - MOVE_EFFECT_ATK_MINUS_2 + 1, + affectsUser, 0)) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleScripting.animArg1 = gBattleCommunication[MOVE_EFFECT_BYTE] & ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); + gBattleScripting.animArg2 = 0; + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_StatDown; + } + break; + case MOVE_EFFECT_RECHARGE: + gBattleMons[gEffectBank].status2 |= STATUS2_RECHARGE; + gDisableStructs[gEffectBank].rechargeCounter = 2; + gLockedMoves[gEffectBank] = gCurrentMove; + gBattlescriptCurrInstr++; + break; + case MOVE_EFFECT_RAGE: + gBattleMons[gBankAttacker].status2 |= STATUS2_RAGE; + gBattlescriptCurrInstr++; + break; + case MOVE_EFFECT_STEAL_ITEM: + { + if (gBattleTypeFlags & BATTLE_TYPE_x4000000) + { + gBattlescriptCurrInstr++; + break; + } + + side = GetBankSide(gBankAttacker); + if (GetBankSide(gBankAttacker) == SIDE_OPPONENT + && !(gBattleTypeFlags & + (BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_FRONTIER + | BATTLE_TYPE_LINK + | BATTLE_TYPE_x2000000 + | BATTLE_TYPE_SECRET_BASE))) + { + gBattlescriptCurrInstr++; + } + else if (!(gBattleTypeFlags & + (BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_FRONTIER + | BATTLE_TYPE_LINK + | BATTLE_TYPE_x2000000 + | BATTLE_TYPE_SECRET_BASE)) + && (gWishFutureKnock.knockedOffPokes[side] & gBitTable[gBattlePartyID[gBankAttacker]])) + { + gBattlescriptCurrInstr++; + } + else if (gBattleMons[gBankTarget].item + && gBattleMons[gBankTarget].ability == ABILITY_STICKY_HOLD) + { + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_NoItemSteal; + + gLastUsedAbility = gBattleMons[gBankTarget].ability; + RecordAbilityBattle(gBankTarget, gLastUsedAbility); + } + else if (gBattleMons[gBankAttacker].item != 0 + || gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY + || IS_ITEM_MAIL(gBattleMons[gBankTarget].item) + || gBattleMons[gBankTarget].item == 0) + { + gBattlescriptCurrInstr++; + } + else + { + u16* changedItem = &gBattleStruct->changedItems[gBankAttacker]; + gLastUsedItem = *changedItem = gBattleMons[gBankTarget].item; + gBattleMons[gBankTarget].item = 0; + + gActiveBank = gBankAttacker; + EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gLastUsedItem); + MarkBufferBankForExecution(gBankAttacker); + + gActiveBank = gBankTarget; + EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gBankTarget].item); + MarkBufferBankForExecution(gBankTarget); + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_ItemSteal; + + *(u8*)((u8*)(&gBattleStruct->choicedMove[gBankTarget]) + 0) = 0; + *(u8*)((u8*)(&gBattleStruct->choicedMove[gBankTarget]) + 1) = 0; + } + + } + break; + case MOVE_EFFECT_PREVENT_ESCAPE: + gBattleMons[gBankTarget].status2 |= STATUS2_ESCAPE_PREVENTION; + gDisableStructs[gBankTarget].bankPreventingEscape = gBankAttacker; + gBattlescriptCurrInstr++; + break; + case MOVE_EFFECT_NIGHTMARE: + gBattleMons[gBankTarget].status2 |= STATUS2_NIGHTMARE; + gBattlescriptCurrInstr++; + break; + case MOVE_EFFECT_ALL_STATS_UP: + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_AllStatsUp; + break; + case MOVE_EFFECT_RAPIDSPIN: + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_RapidSpinAway; + break; + case MOVE_EFFECT_REMOVE_PARALYSIS: // Smelling salts + if (!(gBattleMons[gBankTarget].status1 & STATUS_PARALYSIS)) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleMons[gBankTarget].status1 &= ~(STATUS_PARALYSIS); + + gActiveBank = gBankTarget; + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); + MarkBufferBankForExecution(gActiveBank); + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_TargetPRLZHeal; + } + break; + case MOVE_EFFECT_ATK_DEF_DOWN: // SuperPower + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_AtkDefDown; + break; + case MOVE_EFFECT_RECOIL_33_PARALYSIS: // Volt Tackle + gBattleMoveDamage = gHpDealt / 3; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleCommunication[MOVE_EFFECT_BYTE]]; + break; + case MOVE_EFFECT_THRASH: + if (gBattleMons[gEffectBank].status2 & STATUS2_LOCK_CONFUSE) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleMons[gEffectBank].status2 |= STATUS2_MULTIPLETURNS; + gLockedMoves[gEffectBank] = gCurrentMove; + gBattleMons[gEffectBank].status2 |= (((Random() & 1) + 2) << 0xA); + } + break; + case MOVE_EFFECT_KNOCK_OFF: + if (gBattleMons[gEffectBank].ability == ABILITY_STICKY_HOLD) + { + if (gBattleMons[gEffectBank].item == 0) + { + gBattlescriptCurrInstr++; + } + else + { + gLastUsedAbility = ABILITY_STICKY_HOLD; + gBattlescriptCurrInstr = BattleScript_StickyHoldActivates; + RecordAbilityBattle(gEffectBank, ABILITY_STICKY_HOLD); + } + break; + } + if (gBattleMons[gEffectBank].item) + { + side = GetBankSide(gEffectBank); + + gLastUsedItem = gBattleMons[gEffectBank].item; + gBattleMons[gEffectBank].item = 0; + gWishFutureKnock.knockedOffPokes[side] |= gBitTable[gBattlePartyID[gEffectBank]]; + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_KnockedOff; + + *(u8*)((u8*)(&gBattleStruct->choicedMove[gEffectBank]) + 0) = 0; + *(u8*)((u8*)(&gBattleStruct->choicedMove[gEffectBank]) + 1) = 0; + } + else + { + gBattlescriptCurrInstr++; + } + break; + case MOVE_EFFECT_SP_ATK_TWO_DOWN: // Overheat + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_SAtkDown2; + break; + } + } + } + + gBattleCommunication[MOVE_EFFECT_BYTE] = 0; +} + +static void atk15_seteffectwithchance(void) +{ + u32 percentChance; + + if (gBattleMons[gBankAttacker].ability == ABILITY_SERENE_GRACE) + percentChance = gBattleMoves[gCurrentMove].secondaryEffectChance * 2; + else + percentChance = gBattleMoves[gCurrentMove].secondaryEffectChance; + + if (gBattleCommunication[MOVE_EFFECT_BYTE] & MOVE_EFFECT_CERTAIN + && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + gBattleCommunication[MOVE_EFFECT_BYTE] &= ~(MOVE_EFFECT_CERTAIN); + SetMoveEffect(0, MOVE_EFFECT_CERTAIN); + } + else if (Random() % 100 < percentChance + && gBattleCommunication[MOVE_EFFECT_BYTE] + && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + if (percentChance >= 100) + SetMoveEffect(0, MOVE_EFFECT_CERTAIN); + else + SetMoveEffect(0, 0); + } + else + { + gBattlescriptCurrInstr++; + } + + gBattleCommunication[MOVE_EFFECT_BYTE] = 0; + gBattleScripting.field_16 = 0; +} + +static void atk16_seteffectprimary(void) +{ + SetMoveEffect(TRUE, 0); +} + +static void atk17_seteffectsecondary(void) +{ + SetMoveEffect(FALSE, 0); +} + +static void atk18_status_effect_clear(void) +{ + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + + if (gBattleCommunication[MOVE_EFFECT_BYTE] <= MOVE_EFFECT_TOXIC) + gBattleMons[gActiveBank].status1 &= (~sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]); + else + gBattleMons[gActiveBank].status2 &= (~sStatusFlagsForMoveEffects[gBattleCommunication[MOVE_EFFECT_BYTE]]); + + gBattleCommunication[MOVE_EFFECT_BYTE] = 0; + gBattlescriptCurrInstr += 2; + gBattleScripting.field_16 = 0; +} + +static void atk19_faint_pokemon(void) +{ + const u8 *BS_ptr; + + if (gBattlescriptCurrInstr[2] != 0) + { + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + if (gHitMarker & HITMARKER_FAINTED(gActiveBank)) + { + BS_ptr = BSScriptReadPtr(gBattlescriptCurrInstr + 3); + + BattleScriptPop(); + gBattlescriptCurrInstr = BS_ptr; + gSideAffecting[GetBankSide(gActiveBank)] &= ~(SIDE_STATUS_SPIKES_DAMAGED); + } + else + { + gBattlescriptCurrInstr += 7; + } + } + else + { + u8 bank; + + if (gBattlescriptCurrInstr[1] == BS_GET_ATTACKER) + { + gActiveBank = gBankAttacker; + bank = gBankTarget; + BS_ptr = BattleScript_FaintAttacker; + } + else + { + gActiveBank = gBankTarget; + bank = gBankAttacker; + BS_ptr = BattleScript_FaintTarget; + } + if (!(gAbsentBankFlags & gBitTable[gActiveBank]) + && gBattleMons[gActiveBank].hp == 0) + { + gHitMarker |= HITMARKER_FAINTED(gActiveBank); + BattleScriptPush(gBattlescriptCurrInstr + 7); + gBattlescriptCurrInstr = BS_ptr; + if (GetBankSide(gActiveBank) == SIDE_PLAYER) + { + gHitMarker |= HITMARKER_x400000; + if (gBattleResults.playerFaintCounter < 0xFF) + gBattleResults.playerFaintCounter++; + AdjustFriendshipOnBattleFaint(gActiveBank); + } + else + { + if (gBattleResults.opponentFaintCounter < 0xFF) + gBattleResults.opponentFaintCounter++; + gBattleResults.lastOpponentSpecies = GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES, NULL); + } + if ((gHitMarker & HITMARKER_DESTINYBOND) && gBattleMons[gBankAttacker].hp != 0) + { + gHitMarker &= ~(HITMARKER_DESTINYBOND); + BattleScriptPush(gBattlescriptCurrInstr); + gBattleMoveDamage = gBattleMons[bank].hp; + gBattlescriptCurrInstr = BattleScript_DestinyBondTakesLife; + } + if ((gStatuses3[gBankTarget] & STATUS3_GRUDGE) + && !(gHitMarker & HITMARKER_GRUDGE) + && GetBankSide(gBankAttacker) != GetBankSide(gBankTarget) + && gBattleMons[gBankAttacker].hp != 0 + && gCurrentMove != MOVE_STRUGGLE) + { + u8 moveIndex = *(gBattleStruct->chosenMovesIds + gBankAttacker); + + gBattleMons[gBankAttacker].pp[moveIndex] = 0; + BattleScriptPush(gBattlescriptCurrInstr); + gBattlescriptCurrInstr = BattleScript_GrudgeTakesPp; + gActiveBank = gBankAttacker; + EmitSetMonData(0, moveIndex + REQUEST_PPMOVE1_BATTLE, 0, 1, &gBattleMons[gActiveBank].pp[moveIndex]); + MarkBufferBankForExecution(gActiveBank); + + PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleMons[gBankAttacker].moves[moveIndex]) + } + } + else + { + gBattlescriptCurrInstr += 7; + } + } +} + +static void atk1A_faint_animation(void) +{ + if (gBattleExecBuffer == 0) + { + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + EmitFaintAnimation(0); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 2; + } +} + +static void atk1B_faint_effects_clear(void) +{ + if (gBattleExecBuffer == 0) + { + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + + if (!(gBattleTypeFlags & BATTLE_TYPE_ARENA) || gBattleMons[gActiveBank].hp == 0) + { + gBattleMons[gActiveBank].status1 = 0; + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 0x4, &gBattleMons[gActiveBank].status1); + MarkBufferBankForExecution(gActiveBank); + } + + UndoEffectsAfterFainting(); // Effects like attractions, trapping, etc. + gBattlescriptCurrInstr += 2; + } +} + +static void atk1C_jumpifstatus(void) +{ + u8 bank = GetBattleBank(gBattlescriptCurrInstr[1]); + u32 flags = BS2ScriptRead32(gBattlescriptCurrInstr + 2); + const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 6); + + if (gBattleMons[bank].status1 & flags && gBattleMons[bank].hp) + gBattlescriptCurrInstr = jumpPtr; + else + gBattlescriptCurrInstr += 10; +} + +static void atk1D_jumpifstatus2(void) +{ + u8 bank = GetBattleBank(gBattlescriptCurrInstr[1]); + u32 flags = BS2ScriptRead32(gBattlescriptCurrInstr + 2); + const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 6); + + if (gBattleMons[bank].status2 & flags && gBattleMons[bank].hp) + gBattlescriptCurrInstr = jumpPtr; + else + gBattlescriptCurrInstr += 10; +} + +static void atk1E_jumpifability(void) +{ + u8 bank; + u8 ability = gBattlescriptCurrInstr[2]; + const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 3); + + if (gBattlescriptCurrInstr[1] == BS_GET_ATTACKER_SIDE) + { + bank = AbilityBattleEffects(ABILITYEFFECT_CHECK_BANK_SIDE, gBankAttacker, ability, 0, 0); + if (bank) + { + gLastUsedAbility = ability; + gBattlescriptCurrInstr = jumpPtr; + RecordAbilityBattle(bank - 1, gLastUsedAbility); + gBattleScripting.field_15 = bank - 1; + } + else + gBattlescriptCurrInstr += 7; + } + else if (gBattlescriptCurrInstr[1] == BS_GET_NOT_ATTACKER_SIDE) + { + bank = AbilityBattleEffects(ABILITYEFFECT_CHECK_OTHER_SIDE, gBankAttacker, ability, 0, 0); + if (bank) + { + gLastUsedAbility = ability; + gBattlescriptCurrInstr = jumpPtr; + RecordAbilityBattle(bank - 1, gLastUsedAbility); + gBattleScripting.field_15 = bank - 1; + } + else + gBattlescriptCurrInstr += 7; + } + else + { + bank = GetBattleBank(gBattlescriptCurrInstr[1]); + if (gBattleMons[bank].ability == ability) + { + gLastUsedAbility = ability; + gBattlescriptCurrInstr = jumpPtr; + RecordAbilityBattle(bank, gLastUsedAbility); + gBattleScripting.field_15 = bank; + } + else + gBattlescriptCurrInstr += 7; + } +} + +static void atk1F_jumpifsideaffecting(void) +{ + u8 side; + u16 flags; + const u8* jumpPtr; + + if (gBattlescriptCurrInstr[1] == BS_GET_ATTACKER) + side = GET_BANK_SIDE(gBankAttacker); + else + side = GET_BANK_SIDE(gBankTarget); + + flags = BS2ScriptRead16(gBattlescriptCurrInstr + 2); + jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 4); + + if (gSideAffecting[side] & flags) + gBattlescriptCurrInstr = jumpPtr; + else + gBattlescriptCurrInstr += 8; +} + +static void atk20_jumpifstat(void) +{ + u8 ret = 0; + u8 bank = GetBattleBank(gBattlescriptCurrInstr[1]); + u8 value = gBattleMons[bank].statStages[gBattlescriptCurrInstr[3]]; + + switch (gBattlescriptCurrInstr[2]) + { + case CMP_EQUAL: + if (value == gBattlescriptCurrInstr[4]) + ret++; + break; + case CMP_NOT_EQUAL: + if (value != gBattlescriptCurrInstr[4]) + ret++; + break; + case CMP_GREATER_THAN: + if (value > gBattlescriptCurrInstr[4]) + ret++; + break; + case CMP_LESS_THAN: + if (value < gBattlescriptCurrInstr[4]) + ret++; + break; + case CMP_COMMON_BITS: + if (value & gBattlescriptCurrInstr[4]) + ret++; + break; + case CMP_NO_COMMON_BITS: + if (!(value & gBattlescriptCurrInstr[4])) + ret++; + break; + } + + if (ret) + gBattlescriptCurrInstr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5); + else + gBattlescriptCurrInstr += 9; +} + +static void atk21_jumpifstatus3(void) +{ + u32 flags; + const u8* jumpPtr; + + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + flags = BS2ScriptRead32(gBattlescriptCurrInstr + 2); + jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 7); + + if (gBattlescriptCurrInstr[6]) + { + if ((gStatuses3[gActiveBank] & flags) != 0) + gBattlescriptCurrInstr += 11; + else + gBattlescriptCurrInstr = jumpPtr; + } + else + { + if ((gStatuses3[gActiveBank] & flags) != 0) + gBattlescriptCurrInstr = jumpPtr; + else + gBattlescriptCurrInstr += 11; + } +} + +static void atk22_jumpiftype(void) +{ + u8 bank = GetBattleBank(gBattlescriptCurrInstr[1]); + u8 type = gBattlescriptCurrInstr[2]; + const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 3); + + if (gBattleMons[bank].type1 == type || gBattleMons[bank].type2 == type) + gBattlescriptCurrInstr = jumpPtr; + else + gBattlescriptCurrInstr += 7; +} + +static void atk23_getexp(void) +{ + u16 item; + s32 i; // also used as stringId + u8 holdEffect; + s32 sentIn; + + s32 viaExpShare = 0; + u16* exp = &gBattleStruct->expValue; + + gBank1 = GetBattleBank(gBattlescriptCurrInstr[1]); + sentIn = gSentPokesToOpponent[(gBank1 & 2) >> 1]; + + switch (gBattleScripting.atk23_state) + { + case 0: // check if should receive exp at all + if (GetBankSide(gBank1) != SIDE_OPPONENT || (gBattleTypeFlags & + (BATTLE_TYPE_LINK + | BATTLE_TYPE_x2000000 + | BATTLE_TYPE_x4000000 + | BATTLE_TYPE_FRONTIER + | BATTLE_TYPE_SAFARI + | BATTLE_TYPE_BATTLE_TOWER + | BATTLE_TYPE_EREADER_TRAINER))) + { + gBattleScripting.atk23_state = 6; // goto last case + } + else + { + gBattleScripting.atk23_state++; + gBattleStruct->field_DF |= gBitTable[gBattlePartyID[gBank1]]; + } + break; + case 1: // calculate experience points to redistribute + { + u16 calculatedExp; + s32 viaSentIn; + + for (viaSentIn = 0, i = 0; i < 6; i++) + { + if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) == SPECIES_NONE || GetMonData(&gPlayerParty[i], MON_DATA_HP) == 0) + continue; + if (gBitTable[i] & sentIn) + viaSentIn++; + + item = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM); + + if (item == ITEM_ENIGMA_BERRY) + holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect; + else + holdEffect = ItemId_GetHoldEffect(item); + + if (holdEffect == HOLD_EFFECT_EXP_SHARE) + viaExpShare++; + } + + calculatedExp = gBaseStats[gBattleMons[gBank1].species].expYield * gBattleMons[gBank1].level / 7; + + if (viaExpShare) // at least one mon is getting exp via exp share + { + *exp = calculatedExp / 2 / viaSentIn; + if (*exp == 0) + *exp = 1; + + gExpShareExp = calculatedExp / 2 / viaExpShare; + if (gExpShareExp == 0) + gExpShareExp = 1; + } + else + { + *exp = calculatedExp / viaSentIn; + if (*exp == 0) + *exp = 1; + gExpShareExp = 0; + } + + gBattleScripting.atk23_state++; + gBattleStruct->expGetterId = 0; + gBattleStruct->sentInPokes = sentIn; + } + // fall through + case 2: // set exp value to the poke in expgetter_id and print message + if (gBattleExecBuffer == 0) + { + item = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_HELD_ITEM); + + if (item == ITEM_ENIGMA_BERRY) + holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect; + else + holdEffect = ItemId_GetHoldEffect(item); + + if (holdEffect != HOLD_EFFECT_EXP_SHARE && !(gBattleStruct->sentInPokes & 1)) + { + *(&gBattleStruct->sentInPokes) >>= 1; + gBattleScripting.atk23_state = 5; + gBattleMoveDamage = 0; // used for exp + } + else if (GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL) == MAX_MON_LEVEL) + { + *(&gBattleStruct->sentInPokes) >>= 1; + gBattleScripting.atk23_state = 5; + gBattleMoveDamage = 0; // used for exp + } + else + { + // music change in wild battle after fainting a poke + if (!(gBattleTypeFlags & BATTLE_TYPE_TRAINER) && gBattleMons[0].hp && !gBattleStruct->wildVictorySong) + { + BattleMusicStop(); + PlayBGM(0x161); + gBattleStruct->wildVictorySong++; + } + + if (GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_HP)) + { + if (gBattleStruct->sentInPokes & 1) + gBattleMoveDamage = *exp; + else + gBattleMoveDamage = 0; + + if (holdEffect == HOLD_EFFECT_EXP_SHARE) + gBattleMoveDamage += gExpShareExp; + if (holdEffect == HOLD_EFFECT_LUCKY_EGG) + gBattleMoveDamage = (gBattleMoveDamage * 150) / 100; + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + gBattleMoveDamage = (gBattleMoveDamage * 150) / 100; + + if (IsTradedMon(&gPlayerParty[gBattleStruct->expGetterId])) + { + // check if the pokemon doesn't belong to the player + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gBattleStruct->expGetterId >= 3) + { + i = 0x149; + } + else + { + gBattleMoveDamage = (gBattleMoveDamage * 150) / 100; + i = 0x14A; + } + } + else + { + i = 0x149; + } + + // get exp getter bank + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + if (!(gBattlePartyID[2] != gBattleStruct->expGetterId) && !(gAbsentBankFlags & gBitTable[2])) + gBattleStruct->expGetterBank = 2; + else + { + if (!(gAbsentBankFlags & gBitTable[0])) + gBattleStruct->expGetterBank = 0; + else + gBattleStruct->expGetterBank = 2; + } + } + else + gBattleStruct->expGetterBank = 0; + + PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBattleStruct->expGetterBank, gBattleStruct->expGetterId) + + // buffer 'gained' or 'gained a boosted' + PREPARE_STRING_BUFFER(gBattleTextBuff2, i) + + PREPARE_WORD_NUMBER_BUFFER(gBattleTextBuff3, 5, gBattleMoveDamage) + + PrepareStringBattle(0xD, gBattleStruct->expGetterBank); + MonGainEVs(&gPlayerParty[gBattleStruct->expGetterId], gBattleMons[gBank1].species); + } + gBattleStruct->sentInPokes >>= 1; + gBattleScripting.atk23_state++; + } + } + break; + case 3: // Set stats and give exp + if (gBattleExecBuffer == 0) + { + gBattleBufferB[gBattleStruct->expGetterBank][0] = 0; + if (GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_HP) && GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL) != MAX_MON_LEVEL) + { + BATTLE_LVLUP_STATS->hp = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_MAX_HP); + BATTLE_LVLUP_STATS->atk = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_ATK); + BATTLE_LVLUP_STATS->def = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_DEF); + BATTLE_LVLUP_STATS->spd = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPD); + BATTLE_LVLUP_STATS->spAtk = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPATK); + BATTLE_LVLUP_STATS->spDef = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPDEF); + + gActiveBank = gBattleStruct->expGetterBank; + EmitExpUpdate(0, gBattleStruct->expGetterId, gBattleMoveDamage); + MarkBufferBankForExecution(gActiveBank); + } + gBattleScripting.atk23_state++; + } + break; + case 4: // lvl up if necessary + if (gBattleExecBuffer == 0) + { + gActiveBank = gBattleStruct->expGetterBank; + if (gBattleBufferB[gActiveBank][0] == 0x21 && gBattleBufferB[gActiveBank][1] == 0xB) + { + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && gBattlePartyID[gActiveBank] == gBattleStruct->expGetterId) + sub_805E990(&gPlayerParty[gBattlePartyID[gActiveBank]], gActiveBank); + + PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gActiveBank, gBattleStruct->expGetterId) + + PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff2, 3, GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL)) + + BattleScriptPushCursor(); + gLeveledUpInBattle |= gBitTable[gBattleStruct->expGetterId]; + gBattlescriptCurrInstr = BattleScript_LevelUp; + gBattleMoveDamage = (gBattleBufferB[gActiveBank][2] | (gBattleBufferB[gActiveBank][3] << 8)); + AdjustFriendship(&gPlayerParty[gBattleStruct->expGetterId], 0); + + // update battle mon structure after level up + if (gBattlePartyID[0] == gBattleStruct->expGetterId && gBattleMons[0].hp) + { + gBattleMons[0].level = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL); + gBattleMons[0].hp = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_HP); + gBattleMons[0].maxHP = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_MAX_HP); + gBattleMons[0].attack = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_ATK); + gBattleMons[0].defense = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_DEF); + // Why is this duplicated? + gBattleMons[0].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPD); + gBattleMons[0].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPD); + + gBattleMons[0].spAttack = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPATK); + gBattleMons[0].spDefense = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPDEF); + } + // What is else if? + if (gBattlePartyID[2] == gBattleStruct->expGetterId && gBattleMons[2].hp && (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + { + gBattleMons[2].level = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL); + gBattleMons[2].hp = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_HP); + gBattleMons[2].maxHP = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_MAX_HP); + gBattleMons[2].attack = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_ATK); + gBattleMons[2].defense = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_DEF); + // Duplicated again, but this time there's no Sp Defense + gBattleMons[2].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPD); + gBattleMons[2].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPD); + + gBattleMons[2].spAttack = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPATK); + } + gBattleScripting.atk23_state = 5; + } + else + { + gBattleMoveDamage = 0; + gBattleScripting.atk23_state = 5; + } + } + break; + case 5: // looper increment + if (gBattleMoveDamage) // there is exp to give, goto case 3 that gives exp + gBattleScripting.atk23_state = 3; + else + { + gBattleStruct->expGetterId++; + if (gBattleStruct->expGetterId <= 5) + gBattleScripting.atk23_state = 2; // loop again + else + gBattleScripting.atk23_state = 6; // we're done + } + break; + case 6: // increment instruction + if (gBattleExecBuffer == 0) + { + // not sure why gf clears the item and ability here + gBattleMons[gBank1].item = 0; + gBattleMons[gBank1].ability = 0; + gBattlescriptCurrInstr += 2; + } + break; + } +} + +#ifdef NONMATCHING +static void atk24(void) +{ + u16 HP_count = 0; + s32 i; + + if (gBattleExecBuffer) + return; + + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gPartnerTrainerId == STEVEN_PARTNER_ID) + { + for (i = 0; i < 3; i++) + { + if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) && !GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG)) + HP_count += GetMonData(&gPlayerParty[i], MON_DATA_HP); + } + } + else + { + for (i = 0; i < 6; i++) + { + if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) && !GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG) + && (!(gBattleTypeFlags & BATTLE_TYPE_ARENA) || !(gBattleStruct->field_2A0 & gBitTable[i]))) + { + HP_count += GetMonData(&gPlayerParty[i], MON_DATA_HP); + } + } + } + + if (HP_count == 0) + gBattleOutcome |= BATTLE_LOST; + + for (HP_count = 0, i = 0; i < 6; i++) + { + if (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES) && !GetMonData(&gEnemyParty[i], MON_DATA_IS_EGG) + && (!(gBattleTypeFlags & BATTLE_TYPE_ARENA) || !(gBattleStruct->field_2A1 & gBitTable[i]))) + { + HP_count += GetMonData(&gEnemyParty[i], MON_DATA_HP); + } + } + + if (HP_count == 0) + gBattleOutcome |= BATTLE_WON; + + if (gBattleOutcome == 0 && (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000))) + { + s32 foundPlayer; + s32 foundOpponent; + + // Impossible to decompile loops. + for (foundPlayer = 0, i = 0; i < gNoOfAllBanks; i += 2) + { + if (HITMARKER_UNK(i) & gHitMarker && !gSpecialStatuses[i].flag40) + foundPlayer++; + } + + for (foundOpponent = 0, i = 1; i < gNoOfAllBanks; i += 2) + { + if (HITMARKER_UNK(i) & gHitMarker && !gSpecialStatuses[i].flag40) + foundOpponent++; + } + + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + if (foundOpponent + foundPlayer > 1) + gBattlescriptCurrInstr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + else + gBattlescriptCurrInstr += 5; + } + else + { + if (foundOpponent != 0 && foundPlayer != 0) + gBattlescriptCurrInstr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + else + gBattlescriptCurrInstr += 5; + } + } + else + { + gBattlescriptCurrInstr += 5; + } +} +#else +__attribute__((naked)) +static void atk24(void) +{ + asm("\n\ + .syntax unified\n\ + push {r4-r7,lr}\n\ + mov r7, r8\n\ + push {r7}\n\ + movs r6, 0\n\ + ldr r0, =gBattleExecBuffer\n\ + ldr r0, [r0]\n\ + cmp r0, 0\n\ + beq _0804ACE2\n\ + b _0804AF22\n\ + _0804ACE2:\n\ + ldr r0, =gBattleTypeFlags\n\ + ldr r0, [r0]\n\ + movs r1, 0x80\n\ + lsls r1, 15\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _0804AD48\n\ + ldr r0, =gPartnerTrainerId\n\ + ldrh r1, [r0]\n\ + ldr r0, =0x00000c03\n\ + cmp r1, r0\n\ + bne _0804AD48\n\ + movs r5, 0\n\ + _0804ACFC:\n\ + movs r0, 0x64\n\ + adds r1, r5, 0\n\ + muls r1, r0\n\ + ldr r0, =gPlayerParty\n\ + adds r4, r1, r0\n\ + adds r0, r4, 0\n\ + movs r1, 0xB\n\ + bl GetMonData\n\ + cmp r0, 0\n\ + beq _0804AD2C\n\ + adds r0, r4, 0\n\ + movs r1, 0x2D\n\ + bl GetMonData\n\ + cmp r0, 0\n\ + bne _0804AD2C\n\ + adds r0, r4, 0\n\ + movs r1, 0x39\n\ + bl GetMonData\n\ + adds r0, r6, r0\n\ + lsls r0, 16\n\ + lsrs r6, r0, 16\n\ + _0804AD2C:\n\ + adds r5, 0x1\n\ + cmp r5, 0x2\n\ + ble _0804ACFC\n\ + b _0804ADA8\n\ + .pool\n\ + _0804AD48:\n\ + movs r5, 0\n\ + _0804AD4A:\n\ + movs r0, 0x64\n\ + adds r1, r5, 0\n\ + muls r1, r0\n\ + ldr r0, =gPlayerParty\n\ + adds r4, r1, r0\n\ + adds r0, r4, 0\n\ + movs r1, 0xB\n\ + bl GetMonData\n\ + cmp r0, 0\n\ + beq _0804ADA2\n\ + adds r0, r4, 0\n\ + movs r1, 0x2D\n\ + bl GetMonData\n\ + cmp r0, 0\n\ + bne _0804ADA2\n\ + ldr r0, =gBattleTypeFlags\n\ + ldr r0, [r0]\n\ + movs r1, 0x80\n\ + lsls r1, 11\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _0804AD94\n\ + ldr r0, =gBattleStruct\n\ + ldr r0, [r0]\n\ + movs r1, 0xA8\n\ + lsls r1, 2\n\ + adds r0, r1\n\ + ldrb r1, [r0]\n\ + ldr r2, =gBitTable\n\ + lsls r0, r5, 2\n\ + adds r0, r2\n\ + ldr r0, [r0]\n\ + ands r1, r0\n\ + cmp r1, 0\n\ + bne _0804ADA2\n\ + _0804AD94:\n\ + adds r0, r4, 0\n\ + movs r1, 0x39\n\ + bl GetMonData\n\ + adds r0, r6, r0\n\ + lsls r0, 16\n\ + lsrs r6, r0, 16\n\ + _0804ADA2:\n\ + adds r5, 0x1\n\ + cmp r5, 0x5\n\ + ble _0804AD4A\n\ + _0804ADA8:\n\ + cmp r6, 0\n\ + bne _0804ADB6\n\ + ldr r0, =gBattleOutcome\n\ + ldrb r1, [r0]\n\ + movs r2, 0x2\n\ + orrs r1, r2\n\ + strb r1, [r0]\n\ + _0804ADB6:\n\ + movs r6, 0\n\ + movs r5, 0\n\ + _0804ADBA:\n\ + movs r0, 0x64\n\ + adds r1, r5, 0\n\ + muls r1, r0\n\ + ldr r0, =gEnemyParty\n\ + adds r4, r1, r0\n\ + adds r0, r4, 0\n\ + movs r1, 0xB\n\ + bl GetMonData\n\ + cmp r0, 0\n\ + beq _0804AE10\n\ + adds r0, r4, 0\n\ + movs r1, 0x2D\n\ + bl GetMonData\n\ + cmp r0, 0\n\ + bne _0804AE10\n\ + ldr r0, =gBattleTypeFlags\n\ + ldr r0, [r0]\n\ + movs r1, 0x80\n\ + lsls r1, 11\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _0804AE02\n\ + ldr r0, =gBattleStruct\n\ + ldr r0, [r0]\n\ + ldr r1, =0x000002a1\n\ + adds r0, r1\n\ + ldrb r1, [r0]\n\ + ldr r2, =gBitTable\n\ + lsls r0, r5, 2\n\ + adds r0, r2\n\ + ldr r0, [r0]\n\ + ands r1, r0\n\ + cmp r1, 0\n\ + bne _0804AE10\n\ + _0804AE02:\n\ + adds r0, r4, 0\n\ + movs r1, 0x39\n\ + bl GetMonData\n\ + adds r0, r6, r0\n\ + lsls r0, 16\n\ + lsrs r6, r0, 16\n\ + _0804AE10:\n\ + adds r5, 0x1\n\ + cmp r5, 0x5\n\ + ble _0804ADBA\n\ + ldr r2, =gBattleOutcome\n\ + cmp r6, 0\n\ + bne _0804AE24\n\ + ldrb r0, [r2]\n\ + movs r1, 0x1\n\ + orrs r0, r1\n\ + strb r0, [r2]\n\ + _0804AE24:\n\ + ldrb r0, [r2]\n\ + cmp r0, 0\n\ + bne _0804AF1A\n\ + ldr r0, =gBattleTypeFlags\n\ + ldr r1, [r0]\n\ + ldr r2, =0x02000002\n\ + ands r1, r2\n\ + mov r8, r0\n\ + cmp r1, 0\n\ + beq _0804AF1A\n\ + movs r3, 0\n\ + movs r5, 0\n\ + ldr r0, =gNoOfAllBanks\n\ + ldrb r1, [r0]\n\ + mov r12, r0\n\ + ldr r7, =gBattlescriptCurrInstr\n\ + cmp r3, r1\n\ + bge _0804AE70\n\ + ldr r0, =gHitMarker\n\ + movs r6, 0x80\n\ + lsls r6, 21\n\ + ldr r4, [r0]\n\ + adds r2, r1, 0\n\ + ldr r1, =gSpecialStatuses\n\ + _0804AE54:\n\ + adds r0, r6, 0\n\ + lsls r0, r5\n\ + ands r0, r4\n\ + cmp r0, 0\n\ + beq _0804AE68\n\ + ldrb r0, [r1]\n\ + lsls r0, 25\n\ + cmp r0, 0\n\ + blt _0804AE68\n\ + adds r3, 0x1\n\ + _0804AE68:\n\ + adds r1, 0x28\n\ + adds r5, 0x2\n\ + cmp r5, r2\n\ + blt _0804AE54\n\ + _0804AE70:\n\ + movs r2, 0\n\ + movs r5, 0x1\n\ + mov r4, r12\n\ + ldrb r1, [r4]\n\ + cmp r5, r1\n\ + bge _0804AEAA\n\ + ldr r0, =gHitMarker\n\ + movs r4, 0x80\n\ + lsls r4, 21\n\ + mov r12, r4\n\ + ldr r6, [r0]\n\ + ldr r0, =gSpecialStatuses\n\ + adds r4, r1, 0\n\ + adds r1, r0, 0\n\ + adds r1, 0x14\n\ + _0804AE8E:\n\ + mov r0, r12\n\ + lsls r0, r5\n\ + ands r0, r6\n\ + cmp r0, 0\n\ + beq _0804AEA2\n\ + ldrb r0, [r1]\n\ + lsls r0, 25\n\ + cmp r0, 0\n\ + blt _0804AEA2\n\ + adds r2, 0x1\n\ + _0804AEA2:\n\ + adds r1, 0x28\n\ + adds r5, 0x2\n\ + cmp r5, r4\n\ + blt _0804AE8E\n\ + _0804AEAA:\n\ + mov r1, r8\n\ + ldr r0, [r1]\n\ + movs r1, 0x40\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _0804AEF0\n\ + adds r0, r2, r3\n\ + cmp r0, 0x1\n\ + bgt _0804AEF8\n\ + b _0804AF12\n\ + .pool\n\ + _0804AEF0:\n\ + cmp r2, 0\n\ + beq _0804AF12\n\ + cmp r3, 0\n\ + beq _0804AF12\n\ + _0804AEF8:\n\ + ldr r2, [r7]\n\ + ldrb r1, [r2, 0x1]\n\ + ldrb r0, [r2, 0x2]\n\ + lsls r0, 8\n\ + adds r1, r0\n\ + ldrb r0, [r2, 0x3]\n\ + lsls r0, 16\n\ + adds r1, r0\n\ + ldrb r0, [r2, 0x4]\n\ + lsls r0, 24\n\ + adds r1, r0\n\ + str r1, [r7]\n\ + b _0804AF22\n\ + _0804AF12:\n\ + ldr r0, [r7]\n\ + adds r0, 0x5\n\ + str r0, [r7]\n\ + b _0804AF22\n\ + _0804AF1A:\n\ + ldr r1, =gBattlescriptCurrInstr\n\ + ldr r0, [r1]\n\ + adds r0, 0x5\n\ + str r0, [r1]\n\ + _0804AF22:\n\ + pop {r3}\n\ + mov r8, r3\n\ + pop {r4-r7}\n\ + pop {r0}\n\ + bx r0\n\ + .pool\n\ + .syntax divided"); +} + +#endif // NONMATCHING + +static void MoveValuesCleanUp(void) +{ + gBattleMoveFlags = 0; + gBattleScripting.dmgMultiplier = 1; + gCritMultiplier = 1; + gBattleCommunication[MOVE_EFFECT_BYTE] = 0; + gBattleCommunication[6] = 0; + gHitMarker &= ~(HITMARKER_DESTINYBOND); + gHitMarker &= ~(HITMARKER_SYNCHRONISE_EFFECT); +} + +static void atk25_move_values_cleanup(void) +{ + MoveValuesCleanUp(); + gBattlescriptCurrInstr += 1; +} + +static void atk26_set_multihit(void) +{ + gMultiHitCounter = gBattlescriptCurrInstr[1]; + gBattlescriptCurrInstr += 2; +} + +static void atk27_decrement_multihit(void) +{ + if (--gMultiHitCounter == 0) + gBattlescriptCurrInstr += 5; + else + gBattlescriptCurrInstr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); +} + +static void atk28_goto(void) +{ + gBattlescriptCurrInstr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); +} + +static void atk29_jumpifbyte(void) +{ + u8 caseID = gBattlescriptCurrInstr[1]; + const u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 2); + u8 value = gBattlescriptCurrInstr[6]; + const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 7); + + gBattlescriptCurrInstr += 11; + + switch (caseID) + { + case CMP_EQUAL: + if (*memByte == value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_NOT_EQUAL: + if (*memByte != value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_GREATER_THAN: + if (*memByte > value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_LESS_THAN: + if (*memByte < value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_COMMON_BITS: + if (*memByte & value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_NO_COMMON_BITS: + if (!(*memByte & value)) + gBattlescriptCurrInstr = jumpPtr; + break; + } +} + +static void atk2A_jumpifhalfword(void) +{ + u8 caseID = gBattlescriptCurrInstr[1]; + const u16* memHword = BS2ScriptReadPtr(gBattlescriptCurrInstr + 2); + u16 value = BS2ScriptRead16(gBattlescriptCurrInstr + 6); + const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 8); + + gBattlescriptCurrInstr += 12; + + switch (caseID) + { + case CMP_EQUAL: + if (*memHword == value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_NOT_EQUAL: + if (*memHword != value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_GREATER_THAN: + if (*memHword > value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_LESS_THAN: + if (*memHword < value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_COMMON_BITS: + if (*memHword & value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_NO_COMMON_BITS: + if (!(*memHword & value)) + gBattlescriptCurrInstr = jumpPtr; + break; + } +} + +static void atk2B_jumpifword(void) +{ + u8 caseID = gBattlescriptCurrInstr[1]; + const u32* memWord = BS2ScriptReadPtr(gBattlescriptCurrInstr + 2); + u32 value = BSScriptRead32(gBattlescriptCurrInstr + 6); + const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 10); + + gBattlescriptCurrInstr += 14; + + switch (caseID) + { + case CMP_EQUAL: + if (*memWord == value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_NOT_EQUAL: + if (*memWord != value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_GREATER_THAN: + if (*memWord > value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_LESS_THAN: + if (*memWord < value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_COMMON_BITS: + if (*memWord & value) + gBattlescriptCurrInstr = jumpPtr; + break; + case CMP_NO_COMMON_BITS: + if (!(*memWord & value)) + gBattlescriptCurrInstr = jumpPtr; + break; + } +} + +static void atk2C_jumpifarrayequal(void) +{ + const u8* mem1 = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + const u8* mem2 = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5); + u32 size = gBattlescriptCurrInstr[9]; + const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 10); + + u8 i; + for (i = 0; i < size; i++) + { + if (*mem1 != *mem2) + { + gBattlescriptCurrInstr += 14; + break; + } + mem1++, mem2++; + } + + if (i == size) + gBattlescriptCurrInstr = jumpPtr; +} + +static void atk2D_jumpifarraynotequal(void) +{ + u8 equalBytes = 0; + const u8* mem1 = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + const u8* mem2 = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5); + u32 size = gBattlescriptCurrInstr[9]; + const u8* jumpPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 10); + + u8 i; + for (i = 0; i < size; i++) + { + if (*mem1 == *mem2) + { + equalBytes++; + } + mem1++, mem2++; + } + + if (equalBytes != size) + gBattlescriptCurrInstr = jumpPtr; + else + gBattlescriptCurrInstr += 14; +} + +static void atk2E_setbyte(void) +{ + u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + *memByte = gBattlescriptCurrInstr[5]; + + gBattlescriptCurrInstr += 6; +} + +static void atk2F_addbyte(void) +{ + u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + *memByte += gBattlescriptCurrInstr[5]; + gBattlescriptCurrInstr += 6; +} + +static void atk30_subbyte(void) +{ + u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + *memByte -= gBattlescriptCurrInstr[5]; + gBattlescriptCurrInstr += 6; +} + +static void atk31_copyarray(void) +{ + u8* dest = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + const u8* src = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5); + s32 size = gBattlescriptCurrInstr[9]; + + s32 i; + for (i = 0; i < size; i++) + { + dest[i] = src[i]; + } + + gBattlescriptCurrInstr += 10; +} + +static void atk32_copyarray_withindex(void) +{ + u8* dest = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + const u8* src = BS2ScriptReadPtr(gBattlescriptCurrInstr + 5); + const u8* index = BS2ScriptReadPtr(gBattlescriptCurrInstr + 9); + s32 size = gBattlescriptCurrInstr[13]; + + s32 i; + for (i = 0; i < size; i++) + { + dest[i] = src[i + *index]; + } + + gBattlescriptCurrInstr += 14; +} + +static void atk33_orbyte(void) +{ + u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + *memByte |= gBattlescriptCurrInstr[5]; + gBattlescriptCurrInstr += 6; +} + +static void atk34_orhalfword(void) +{ + u16* memHword = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + u16 val = BS2ScriptRead16(gBattlescriptCurrInstr + 5); + + *memHword |= val; + gBattlescriptCurrInstr += 7; +} + +static void atk35_orword(void) +{ + u32* memWord = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + u32 val = BS2ScriptRead32(gBattlescriptCurrInstr + 5); + + *memWord |= val; + gBattlescriptCurrInstr += 9; +} + +static void atk36_bicbyte(void) +{ + u8* memByte = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + *memByte &= ~(gBattlescriptCurrInstr[5]); + gBattlescriptCurrInstr += 6; +} + +static void atk37_bichalfword(void) +{ + u16* memHword = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + u16 val = BS2ScriptRead16(gBattlescriptCurrInstr + 5); + + *memHword &= ~val; + gBattlescriptCurrInstr += 7; +} + +static void atk38_bicword(void) +{ + u32* memWord = BS2ScriptReadPtr(gBattlescriptCurrInstr + 1); + u32 val = BS2ScriptRead32(gBattlescriptCurrInstr + 5); + + *memWord &= ~val; + gBattlescriptCurrInstr += 9; +} + +static void atk39_pause(void) +{ + if (gBattleExecBuffer == 0) + { + u16 value = BS2ScriptRead16(gBattlescriptCurrInstr + 1); + if (++gPauseCounterBattle >= value) + { + gPauseCounterBattle = 0; + gBattlescriptCurrInstr += 3; + } + } +} + +static void atk3A_waitstate(void) +{ + if (gBattleExecBuffer == 0) + gBattlescriptCurrInstr++; +} + +static void atk3B_healthbar_update(void) +{ + if (gBattlescriptCurrInstr[1] == BS_GET_TARGET) + gActiveBank = gBankTarget; + else + gActiveBank = gBankAttacker; + + EmitHealthBarUpdate(0, gBattleMoveDamage); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 2; +} + +static void atk3C_return(void) +{ + BattleScriptPop(); +} + +static void atk3D_end(void) +{ + if (gBattleTypeFlags & BATTLE_TYPE_ARENA) + sub_81A5718(gBankAttacker); + + gBattleMoveFlags = 0; + gActiveBank = 0; + gFightStateTracker = 0xB; +} + +static void atk3E_end2(void) +{ + gActiveBank = 0; + gFightStateTracker = 0xB; +} + +static void atk3F_end3(void) // pops the main function stack +{ + BattleScriptPop(); + if (BATTLE_CALLBACKS_STACK->size) + BATTLE_CALLBACKS_STACK->size--; + gBattleMainFunc = BATTLE_CALLBACKS_STACK->function[BATTLE_CALLBACKS_STACK->size]; +} + +static void atk41_call(void) +{ + BattleScriptPush(gBattlescriptCurrInstr + 5); + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); +} + +static void atk42_jumpiftype2(void) +{ + u8 bank = GetBattleBank(gBattlescriptCurrInstr[1]); + + if (gBattlescriptCurrInstr[2] == gBattleMons[bank].type1 || gBattlescriptCurrInstr[2] == gBattleMons[bank].type2) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 3); + else + gBattlescriptCurrInstr += 7; +} + +static void atk43_jumpifabilitypresent(void) +{ + if (AbilityBattleEffects(ABILITYEFFECT_CHECK_ON_FIELD, 0, gBattlescriptCurrInstr[1], 0, 0)) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + else + gBattlescriptCurrInstr += 6; +} + +static void atk44(void) +{ + *(gBankAttacker + gBattleStruct->field_54) = 1; +} + +static void atk45_playanimation(void) +{ + const u16* argumentPtr; + + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + argumentPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 3); + + if (gBattlescriptCurrInstr[2] == B_ANIM_STATS_CHANGE + || gBattlescriptCurrInstr[2] == B_ANIM_SNATCH_MOVE + || gBattlescriptCurrInstr[2] == B_ANIM_SUBSTITUTE_FADE) + { + EmitBattleAnimation(0, gBattlescriptCurrInstr[2], *argumentPtr); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 7; + } + else if (gHitMarker & HITMARKER_NO_ANIMATIONS) + { + BattleScriptPush(gBattlescriptCurrInstr + 7); + gBattlescriptCurrInstr = BattleScript_Pausex20; + } + else if (gBattlescriptCurrInstr[2] == B_ANIM_RAIN_CONTINUES + || gBattlescriptCurrInstr[2] == B_ANIM_SUN_CONTINUES + || gBattlescriptCurrInstr[2] == B_ANIM_SANDSTORM_CONTINUES + || gBattlescriptCurrInstr[2] == B_ANIM_HAIL_CONTINUES) + { + EmitBattleAnimation(0, gBattlescriptCurrInstr[2], *argumentPtr); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 7; + } + else if (gStatuses3[gActiveBank] & STATUS3_SEMI_INVULNERABLE) + { + gBattlescriptCurrInstr += 7; + } + else + { + EmitBattleAnimation(0, gBattlescriptCurrInstr[2], *argumentPtr); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 7; + } +} + +static void atk46_playanimation2(void) // animation Id is stored in the first pointer +{ + const u16* argumentPtr; + const u8* animationIdPtr; + + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + animationIdPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 2); + argumentPtr = BS2ScriptReadPtr(gBattlescriptCurrInstr + 6); + + if (*animationIdPtr == B_ANIM_STATS_CHANGE + || *animationIdPtr == B_ANIM_SNATCH_MOVE + || *animationIdPtr == B_ANIM_SUBSTITUTE_FADE) + { + EmitBattleAnimation(0, *animationIdPtr, *argumentPtr); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 10; + } + else if (gHitMarker & HITMARKER_NO_ANIMATIONS) + { + gBattlescriptCurrInstr += 10; + } + else if (*animationIdPtr == B_ANIM_RAIN_CONTINUES + || *animationIdPtr == B_ANIM_SUN_CONTINUES + || *animationIdPtr == B_ANIM_SANDSTORM_CONTINUES + || *animationIdPtr == B_ANIM_HAIL_CONTINUES) + { + EmitBattleAnimation(0, *animationIdPtr, *argumentPtr); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 10; + } + else if (gStatuses3[gActiveBank] & STATUS3_SEMI_INVULNERABLE) + { + gBattlescriptCurrInstr += 10; + } + else + { + EmitBattleAnimation(0, *animationIdPtr, *argumentPtr); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 10; + } +} + +static void atk47_setgraphicalstatchangevalues(void) +{ + u8 value = 0; + switch (gBattleScripting.statChanger & 0xF0) + { + case 0x10: // +1 + value = 0xF; + break; + case 0x20: // +2 + value = 0x27; + break; + case 0x90: // -1 + value = 0x16; + break; + case 0xA0: // -2 + value = 0x2E; + break; + } + gBattleScripting.animArg1 = (gBattleScripting.statChanger & 0xF) + value - 1; + gBattleScripting.animArg2 = 0; + gBattlescriptCurrInstr++; +} + +#ifdef NONMATCHING +static void atk48_playstatchangeanimation(void) +{ + u32 currStat = 0; + s16 statAnimId = 0; + s16 checkingStatAnimId = 0; + s32 changeableStats = 0; + u32 statsToCheck = 0; + + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + statsToCheck = gBattlescriptCurrInstr[2]; + + if (gBattlescriptCurrInstr[3] & ATK48_STAT_NEGATIVE) // goes down + { + checkingStatAnimId = (gBattlescriptCurrInstr[3] & ATK48_STAT_BY_TWO) ? 0x2D : 0x15; + while (statsToCheck != 0) + { + if (statsToCheck & 1) + { + if (!(gBattlescriptCurrInstr[3] & ATK48_LOWER_FAIL_CHECK)) + { + if (gBattleMons[gActiveBank].statStages[currStat] > 0) + { + statAnimId = checkingStatAnimId; + changeableStats++; + } + } + else if (!gSideTimers[GET_BANK_SIDE(gActiveBank)].mistTimer + && gBattleMons[gActiveBank].ability != ABILITY_CLEAR_BODY + && gBattleMons[gActiveBank].ability != ABILITY_WHITE_SMOKE + && !(gBattleMons[gActiveBank].ability == ABILITY_KEEN_EYE && currStat == STAT_STAGE_ACC) + && !(gBattleMons[gActiveBank].ability == ABILITY_HYPER_CUTTER && currStat == STAT_STAGE_ATK)) + { + if (gBattleMons[gActiveBank].statStages[currStat] > 0) + { + statAnimId = checkingStatAnimId; + changeableStats++; + } + } + } + statsToCheck >>= 1, checkingStatAnimId++, currStat++; + } + + if (changeableStats > 1) // more than one stat, so the color is gray + { + if (gBattlescriptCurrInstr[3] & ATK48_STAT_BY_TWO) + statAnimId = 0x3A; + else + statAnimId = 0x39; + } + } + else // goes up + { + checkingStatAnimId = (gBattlescriptCurrInstr[3] & ATK48_STAT_BY_TWO) ? 0x26 : 0xE; + while (statsToCheck != 0) + { + if (statsToCheck & 1 && gBattleMons[gActiveBank].statStages[currStat] < 0xC) + { + statAnimId = checkingStatAnimId; + changeableStats++; + } + statsToCheck >>= 1, checkingStatAnimId += 1, currStat++; + } + + if (changeableStats > 1) // more than one stat, so the color is gray + { + if (gBattlescriptCurrInstr[3] & ATK48_STAT_BY_TWO) + statAnimId = 0x38; + else + statAnimId = 0x37; + } + } + + if (gBattlescriptCurrInstr[3] & ATK48_BIT_x4 && changeableStats < 2) + { + gBattlescriptCurrInstr += 4; + } + else if (changeableStats != 0 && gBattleScripting.field_1B == 0) + { + EmitBattleAnimation(0, B_ANIM_STATS_CHANGE, statAnimId); + MarkBufferBankForExecution(gActiveBank); + if (gBattlescriptCurrInstr[3] & ATK48_BIT_x4 && changeableStats > 1) + gBattleScripting.field_1B = 1; + gBattlescriptCurrInstr += 4; + } + else + { + gBattlescriptCurrInstr += 4; + } +} +#else +__attribute__((naked)) +static void atk48_playstatchangeanimation(void) +{ + asm("\n\ + .syntax unified\n\ + push {r4-r7,lr}\n\ + mov r7, r10\n\ + mov r6, r9\n\ + mov r5, r8\n\ + push {r5-r7}\n\ + sub sp, 0x4\n\ + movs r7, 0\n\ + movs r0, 0\n\ + mov r8, r0\n\ + movs r3, 0\n\ + ldr r5, =gBattlescriptCurrInstr\n\ + ldr r0, [r5]\n\ + ldrb r0, [r0, 0x1]\n\ + str r3, [sp]\n\ + bl GetBattleBank\n\ + ldr r2, =gActiveBank\n\ + strb r0, [r2]\n\ + ldr r0, [r5]\n\ + ldrb r4, [r0, 0x2]\n\ + ldrb r1, [r0, 0x3]\n\ + movs r0, 0x1\n\ + ands r0, r1\n\ + ldr r3, [sp]\n\ + cmp r0, 0\n\ + beq _0804BAEC\n\ + movs r0, 0x2\n\ + ands r0, r1\n\ + movs r1, 0x15\n\ + cmp r0, 0\n\ + beq _0804BA18\n\ + movs r1, 0x2D\n\ +_0804BA18:\n\ + cmp r4, 0\n\ + beq _0804BAC0\n\ + movs r0, 0x1\n\ + mov r10, r0\n\ + ldr r0, =gBattleMons + 0x18\n\ + mov r9, r0\n\ + lsls r5, r1, 16\n\ +_0804BA26:\n\ + adds r0, r4, 0\n\ + mov r1, r10\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _0804BAB2\n\ + ldr r0, =gBattlescriptCurrInstr\n\ + ldr r0, [r0]\n\ + ldrb r1, [r0, 0x3]\n\ + movs r0, 0x8\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _0804BA58\n\ + ldr r0, =gActiveBank\n\ + ldrb r1, [r0]\n\ + movs r0, 0x58\n\ + muls r0, r1\n\ + adds r0, r7, r0\n\ + b _0804BAA0\n\ + .pool\n\ +_0804BA58:\n\ + ldr r6, =gActiveBank\n\ + ldrb r0, [r6]\n\ + str r3, [sp]\n\ + bl GetBankIdentity\n\ + mov r1, r10\n\ + ands r1, r0\n\ + lsls r0, r1, 1\n\ + adds r0, r1\n\ + lsls r0, 2\n\ + ldr r1, =gSideTimers\n\ + adds r0, r1\n\ + ldrb r0, [r0, 0x4]\n\ + ldr r3, [sp]\n\ + cmp r0, 0\n\ + bne _0804BAB2\n\ + ldr r0, =gBattleMons\n\ + ldrb r2, [r6]\n\ + movs r1, 0x58\n\ + muls r2, r1\n\ + adds r0, r2, r0\n\ + adds r0, 0x20\n\ + ldrb r0, [r0]\n\ + cmp r0, 0x1D\n\ + beq _0804BAB2\n\ + cmp r0, 0x49\n\ + beq _0804BAB2\n\ + cmp r0, 0x33\n\ + bne _0804BA96\n\ + cmp r7, 0x6\n\ + beq _0804BAB2\n\ +_0804BA96:\n\ + cmp r0, 0x34\n\ + bne _0804BA9E\n\ + cmp r7, 0x1\n\ + beq _0804BAB2\n\ +_0804BA9E:\n\ + adds r0, r7, r2\n\ +_0804BAA0:\n\ + add r0, r9\n\ + ldrb r0, [r0]\n\ + lsls r0, 24\n\ + asrs r0, 24\n\ + cmp r0, 0\n\ + ble _0804BAB2\n\ + lsrs r0, r5, 16\n\ + mov r8, r0\n\ + adds r3, 0x1\n\ +_0804BAB2:\n\ + lsrs r4, 1\n\ + movs r1, 0x80\n\ + lsls r1, 9\n\ + adds r5, r1\n\ + adds r7, 0x1\n\ + cmp r4, 0\n\ + bne _0804BA26\n\ +_0804BAC0:\n\ + ldr r0, =gBattlescriptCurrInstr\n\ + mov r9, r0\n\ + cmp r3, 0x1\n\ + ble _0804BB4E\n\ + ldr r0, [r0]\n\ + ldrb r1, [r0, 0x3]\n\ + movs r0, 0x2\n\ + ands r0, r1\n\ + movs r1, 0x39\n\ + mov r8, r1\n\ + cmp r0, 0\n\ + beq _0804BB4E\n\ + movs r0, 0x3A\n\ + b _0804BB4C\n\ + .pool\n\ +_0804BAEC:\n\ + movs r0, 0x2\n\ + ands r0, r1\n\ + movs r1, 0xE\n\ + cmp r0, 0\n\ + beq _0804BAF8\n\ + movs r1, 0x26\n\ +_0804BAF8:\n\ + mov r9, r5\n\ + cmp r4, 0\n\ + beq _0804BB34\n\ + ldr r6, =gBattleMons + 0x18\n\ + adds r5, r2, 0\n\ + lsls r2, r1, 16\n\ +_0804BB04:\n\ + movs r0, 0x1\n\ + ands r0, r4\n\ + cmp r0, 0\n\ + beq _0804BB26\n\ + ldrb r1, [r5]\n\ + movs r0, 0x58\n\ + muls r0, r1\n\ + adds r0, r7, r0\n\ + adds r0, r6\n\ + ldrb r0, [r0]\n\ + lsls r0, 24\n\ + asrs r0, 24\n\ + cmp r0, 0xB\n\ + bgt _0804BB26\n\ + lsrs r1, r2, 16\n\ + mov r8, r1\n\ + adds r3, 0x1\n\ +_0804BB26:\n\ + lsrs r4, 1\n\ + movs r0, 0x80\n\ + lsls r0, 9\n\ + adds r2, r0\n\ + adds r7, 0x1\n\ + cmp r4, 0\n\ + bne _0804BB04\n\ +_0804BB34:\n\ + cmp r3, 0x1\n\ + ble _0804BB4E\n\ + mov r1, r9\n\ + ldr r0, [r1]\n\ + ldrb r1, [r0, 0x3]\n\ + movs r0, 0x2\n\ + ands r0, r1\n\ + movs r1, 0x37\n\ + mov r8, r1\n\ + cmp r0, 0\n\ + beq _0804BB4E\n\ + movs r0, 0x38\n\ +_0804BB4C:\n\ + mov r8, r0\n\ +_0804BB4E:\n\ + mov r1, r9\n\ + ldr r2, [r1]\n\ + ldrb r1, [r2, 0x3]\n\ + movs r0, 0x4\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _0804BB6C\n\ + cmp r3, 0x1\n\ + bgt _0804BB6C\n\ + adds r0, r2, 0x4\n\ + mov r1, r9\n\ + b _0804BBBA\n\ + .pool\n\ +_0804BB6C:\n\ + cmp r3, 0\n\ + beq _0804BBB4\n\ + ldr r4, =gBattleScripting\n\ + ldrb r0, [r4, 0x1B]\n\ + cmp r0, 0\n\ + bne _0804BBB4\n\ + movs r0, 0\n\ + movs r1, 0x1\n\ + mov r2, r8\n\ + str r3, [sp]\n\ + bl EmitBattleAnimation\n\ + ldr r0, =gActiveBank\n\ + ldrb r0, [r0]\n\ + bl MarkBufferBankForExecution\n\ + ldr r0, =gBattlescriptCurrInstr\n\ + ldr r0, [r0]\n\ + ldrb r1, [r0, 0x3]\n\ + movs r0, 0x4\n\ + ands r0, r1\n\ + ldr r3, [sp]\n\ + cmp r0, 0\n\ + beq _0804BBA4\n\ + cmp r3, 0x1\n\ + ble _0804BBA4\n\ + movs r0, 0x1\n\ + strb r0, [r4, 0x1B]\n\ +_0804BBA4:\n\ + ldr r1, =gBattlescriptCurrInstr\n\ + b _0804BBB6\n\ + .pool\n\ +_0804BBB4:\n\ + mov r1, r9\n\ +_0804BBB6:\n\ + ldr r0, [r1]\n\ + adds r0, 0x4\n\ +_0804BBBA:\n\ + str r0, [r1]\n\ + add sp, 0x4\n\ + pop {r3-r5}\n\ + mov r8, r3\n\ + mov r9, r4\n\ + mov r10, r5\n\ + pop {r4-r7}\n\ + pop {r0}\n\ + bx r0\n\ + .syntax divided"); +} +#endif // NONMATCHING + +#define ATK49_LAST_CASE 17 + +static void atk49_moveend(void) +{ + s32 i; + bool32 effect; + u8 moveType; + u8 holdEffectAtk; + u16 *choicedMoveAtk; + u8 arg1, arg2; + u16 lastMove; + + effect = FALSE; + + if (gLastUsedMove == 0xFFFF) + lastMove = 0; + else + lastMove = gLastUsedMove; + + arg1 = gBattlescriptCurrInstr[1]; + arg2 = gBattlescriptCurrInstr[2]; + + if (gBattleMons[gBankAttacker].item == ITEM_ENIGMA_BERRY) + holdEffectAtk = gEnigmaBerries[gBankAttacker].holdEffect; + else + holdEffectAtk = ItemId_GetHoldEffect(gBattleMons[gBankAttacker].item); + + choicedMoveAtk = &gBattleStruct->choicedMove[gBankAttacker]; + + GET_MOVE_TYPE(gCurrentMove, moveType); + + do + { + switch (gBattleScripting.atk49_state) + { + case 0: // rage check + if (gBattleMons[gBankTarget].status2 & STATUS2_RAGE + && gBattleMons[gBankTarget].hp != 0 && gBankAttacker != gBankTarget + && GetBankSide(gBankAttacker) != GetBankSide(gBankTarget) + && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT) && TARGET_TURN_DAMAGED + && gBattleMoves[gCurrentMove].power && gBattleMons[gBankTarget].statStages[STAT_STAGE_ATK] <= 0xB) + { + gBattleMons[gBankTarget].statStages[STAT_STAGE_ATK]++; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_RageIsBuilding; + effect = TRUE; + } + gBattleScripting.atk49_state++; + break; + case 1: // defrosting check + if (gBattleMons[gBankTarget].status1 & STATUS_FREEZE + && gBattleMons[gBankTarget].hp != 0 && gBankAttacker != gBankTarget + && gSpecialStatuses[gBankTarget].moveturnLostHP_special + && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT) && moveType == TYPE_FIRE) + { + gBattleMons[gBankTarget].status1 &= ~(STATUS_FREEZE); + gActiveBank = gBankTarget; + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gBankTarget].status1); + MarkBufferBankForExecution(gActiveBank); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_DefrostedViaFireMove; + effect = TRUE; + } + gBattleScripting.atk49_state++; + break; + case 2: // target synchronize + if (AbilityBattleEffects(ABILITYEFFECT_SYNCHRONIZE, gBankTarget, 0, 0, 0)) + effect = TRUE; + gBattleScripting.atk49_state++; + break; + case 3: // contact abilities + if (AbilityBattleEffects(ABILITYEFFECT_CONTACT, gBankTarget, 0, 0, 0)) + effect = TRUE; + gBattleScripting.atk49_state++; + break; + case 4: // status immunities + if (AbilityBattleEffects(ABILITYEFFECT_IMMUNITY, 0, 0, 0, 0)) + effect = TRUE; // it loops through all banks, so we increment after its done with all banks + else + gBattleScripting.atk49_state++; + break; + case 5: // attacker synchronize + if (AbilityBattleEffects(ABILITYEFFECT_ATK_SYNCHRONIZE, gBankAttacker, 0, 0, 0)) + effect = TRUE; + gBattleScripting.atk49_state++; + break; + case 6: // update choice band move + if (!(gHitMarker & HITMARKER_OBEYS) || holdEffectAtk != HOLD_EFFECT_CHOICE_BAND + || gLastUsedMove == MOVE_STRUGGLE || (*choicedMoveAtk != 0 && *choicedMoveAtk != 0xFFFF)) + goto LOOP; + if (gLastUsedMove == MOVE_BATON_PASS && !(gBattleMoveFlags & MOVESTATUS_FAILED)) + { + gBattleScripting.atk49_state++; + break; + } + *choicedMoveAtk = gLastUsedMove; + LOOP: + { + for (i = 0; i < 4; i++) + { + if (gBattleMons[gBankAttacker].moves[i] == *choicedMoveAtk) + break; + } + if (i == 4) + *choicedMoveAtk = 0; + + gBattleScripting.atk49_state++; + } + break; + case 7: // changed held items + for (i = 0; i < gNoOfAllBanks; i++) + { + u16* changedItem = &gBattleStruct->changedItems[i]; + if (*changedItem != 0) + { + gBattleMons[i].item = *changedItem; + *changedItem = 0; + } + } + gBattleScripting.atk49_state++; + break; + case 11: // item effects for all banks + if (ItemBattleEffects(3, 0, FALSE)) + effect = TRUE; + else + gBattleScripting.atk49_state++; + break; + case 12: // king's rock and shell bell + if (ItemBattleEffects(4, 0, FALSE)) + effect = TRUE; + gBattleScripting.atk49_state++; + break; + case 8: // make attacker sprite invisible + if (gStatuses3[gBankAttacker] & (STATUS3_SEMI_INVULNERABLE) + && gHitMarker & HITMARKER_NO_ANIMATIONS) + { + gActiveBank = gBankAttacker; + EmitSpriteInvisibility(0, TRUE); + MarkBufferBankForExecution(gActiveBank); + gBattleScripting.atk49_state++; + return; + } + gBattleScripting.atk49_state++; + break; + case 9: // make attacker sprite visible + if (gBattleMoveFlags & MOVESTATUS_NOEFFECT + || !(gStatuses3[gBankAttacker] & (STATUS3_SEMI_INVULNERABLE)) + || HasMoveFailed(gBankAttacker)) + { + gActiveBank = gBankAttacker; + EmitSpriteInvisibility(0, FALSE); + MarkBufferBankForExecution(gActiveBank); + gStatuses3[gBankAttacker] &= ~(STATUS3_SEMI_INVULNERABLE); + gSpecialStatuses[gBankAttacker].restoredBankSprite = 1; + gBattleScripting.atk49_state++; + return; + } + gBattleScripting.atk49_state++; + break; + case 10: // make target sprite visible + if (!gSpecialStatuses[gBankTarget].restoredBankSprite && gBankTarget < gNoOfAllBanks + && !(gStatuses3[gBankTarget] & STATUS3_SEMI_INVULNERABLE)) + { + gActiveBank = gBankTarget; + EmitSpriteInvisibility(0, FALSE); + MarkBufferBankForExecution(gActiveBank); + gStatuses3[gBankTarget] &= ~(STATUS3_SEMI_INVULNERABLE); + gBattleScripting.atk49_state++; + return; + } + gBattleScripting.atk49_state++; + break; + case 13: // update substitute + for (i = 0; i < gNoOfAllBanks; i++) + { + if (gDisableStructs[i].substituteHP == 0) + gBattleMons[i].status2 &= ~(STATUS2_SUBSTITUTE); + } + gBattleScripting.atk49_state++; + break; + case 14: // This case looks interesting, although I am not certain what it does. Probably fine tunes edge cases. + if (gHitMarker & HITMARKER_PURSUIT_TRAP) + { + gActiveBank = gBankAttacker; + gBankAttacker = gBankTarget; + gBankTarget = gActiveBank; + gHitMarker &= ~(HITMARKER_PURSUIT_TRAP); + } + if (gHitMarker & HITMARKER_ATTACKSTRING_PRINTED) + { + gUnknownMovesUsedByBanks[gBankAttacker] = gLastUsedMove; + } + if (!(gAbsentBankFlags & gBitTable[gBankAttacker]) + && !(gBattleStruct->field_91 & gBitTable[gBankAttacker]) + && gBattleMoves[lastMove].effect != EFFECT_BATON_PASS) + { + if (gHitMarker & HITMARKER_OBEYS) + { + gLastUsedMovesByBanks[gBankAttacker] = gLastUsedMove; + gUnknown_02024260[gBankAttacker] = gCurrentMove; + } + else + { + gLastUsedMovesByBanks[gBankAttacker] = 0xFFFF; + gUnknown_02024260[gBankAttacker] = 0xFFFF; + } + + if (!(gHitMarker & HITMARKER_FAINTED(gBankTarget))) + gUnknown_02024270[gBankTarget] = gBankAttacker; + + if (gHitMarker & HITMARKER_OBEYS && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + if (gLastUsedMove == 0xFFFF) + { + gUnknown_02024250[gBankTarget] = gLastUsedMove; + } + else + { + gUnknown_02024250[gBankTarget] = gCurrentMove; + GET_MOVE_TYPE(gCurrentMove, gUnknown_02024258[gBankTarget]); + } + } + else + { + gUnknown_02024250[gBankTarget] = 0xFFFF; + } + } + gBattleScripting.atk49_state++; + break; + case 15: // mirror move + if (!(gAbsentBankFlags & gBitTable[gBankAttacker]) && !(gBattleStruct->field_91 & gBitTable[gBankAttacker]) + && gBattleMoves[lastMove].flags & FLAG_MIRROR_MOVE_AFFECTED && gHitMarker & HITMARKER_OBEYS + && gBankAttacker != gBankTarget && !(gHitMarker & HITMARKER_FAINTED(gBankTarget)) + && !(gBattleMoveFlags & MOVESTATUS_NOEFFECT)) + { + u8 target, attacker; + + *(gBattleStruct->mirrorMoves + gBankTarget * 2 + 0) = gLastUsedMove; + *(gBattleStruct->mirrorMoves + gBankTarget * 2 + 1) = gLastUsedMove >> 8; + + target = gBankTarget; + attacker = gBankAttacker; + *(attacker * 2 + target * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = gLastUsedMove; + + target = gBankTarget; + attacker = gBankAttacker; + *(attacker * 2 + target * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) = gLastUsedMove >> 8; + } + gBattleScripting.atk49_state++; + break; + case 16: // + if (!(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) && gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && !gProtectStructs[gBankAttacker].chargingTurn && gBattleMoves[gCurrentMove].target == MOVE_TARGET_BOTH + && !(gHitMarker & HITMARKER_NO_ATTACKSTRING)) + { + u8 bank = GetBankByIdentity(GetBankIdentity(gBankTarget) ^ BIT_MON); + if (gBattleMons[bank].hp != 0) + { + gBankTarget = bank; + gHitMarker |= HITMARKER_NO_ATTACKSTRING; + gBattleScripting.atk49_state = 0; + MoveValuesCleanUp(); + BattleScriptPush(gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]); + gBattlescriptCurrInstr = gUnknown_082DB87D; + return; + } + else + { + gHitMarker |= HITMARKER_NO_ATTACKSTRING; + } + } + gBattleScripting.atk49_state++; + break; + case ATK49_LAST_CASE: + break; + } + + if (arg1 == 1 && effect == FALSE) + gBattleScripting.atk49_state = ATK49_LAST_CASE; + if (arg1 == 2 && arg2 == gBattleScripting.atk49_state) + gBattleScripting.atk49_state = ATK49_LAST_CASE; + + } while (gBattleScripting.atk49_state != ATK49_LAST_CASE && effect == FALSE); + + if (gBattleScripting.atk49_state == ATK49_LAST_CASE && effect == FALSE) + gBattlescriptCurrInstr += 3; +} + +static void atk4A_typecalc2(void) +{ + u8 flags = 0; + s32 i = 0; + u8 moveType = gBattleMoves[gCurrentMove].type; + + if (gBattleMons[gBankTarget].ability == ABILITY_LEVITATE && moveType == TYPE_GROUND) + { + gLastUsedAbility = gBattleMons[gBankTarget].ability; + gBattleMoveFlags |= (MOVESTATUS_MISSED | MOVESTATUS_NOTAFFECTED); + gUnknown_02024250[gBankTarget] = 0; + gBattleCommunication[6] = moveType; + RecordAbilityBattle(gBankTarget, gLastUsedAbility); + } + else + { + while (gTypeEffectiveness[i]!= TYPE_ENDTABLE) + { + if (gTypeEffectiveness[i] == TYPE_FORESIGHT) + { + if (gBattleMons[gBankTarget].status2 & STATUS2_FORESIGHT) + { + break; + } + else + { + i += 3; + continue; + } + } + + if (gTypeEffectiveness[i] == moveType) + { + // check type1 + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type1) + { + if (gTypeEffectiveness[i + 2] == 0) + { + gBattleMoveFlags |= MOVESTATUS_NOTAFFECTED; + break; + } + if (gTypeEffectiveness[i + 2] == 5) + { + flags |= MOVESTATUS_NOTVERYEFFECTIVE; + } + if (gTypeEffectiveness[i + 2] == 20) + { + flags |= MOVESTATUS_SUPEREFFECTIVE; + } + } + // check type2 + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type2) + { + if (gBattleMons[gBankTarget].type1 != gBattleMons[gBankTarget].type2 + && gTypeEffectiveness[i + 2] == 0) + { + gBattleMoveFlags |= MOVESTATUS_NOTAFFECTED; + break; + } + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type2 + && gBattleMons[gBankTarget].type1 != gBattleMons[gBankTarget].type2 + && gTypeEffectiveness[i + 2] == 5) + { + flags |= MOVESTATUS_NOTVERYEFFECTIVE; + } + if (gTypeEffectiveness[i + 1] == gBattleMons[gBankTarget].type2 + && gBattleMons[gBankTarget].type1 != gBattleMons[gBankTarget].type2 + && gTypeEffectiveness[i + 2] == 20) + { + flags |= MOVESTATUS_SUPEREFFECTIVE; + } + } + } + i += 3; + } + } + + if (gBattleMons[gBankTarget].ability == ABILITY_WONDER_GUARD + && !(flags & MOVESTATUS_NOEFFECT) + && AttacksThisTurn(gBankAttacker, gCurrentMove) == 2 + && (!(flags & MOVESTATUS_SUPEREFFECTIVE) || ((flags & (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE)) == (MOVESTATUS_SUPEREFFECTIVE | MOVESTATUS_NOTVERYEFFECTIVE))) + && gBattleMoves[gCurrentMove].power) + { + gLastUsedAbility = ABILITY_WONDER_GUARD; + gBattleMoveFlags |= MOVESTATUS_MISSED; + gUnknown_02024250[gBankTarget] = 0; + gBattleCommunication[6] = 3; + RecordAbilityBattle(gBankTarget, gLastUsedAbility); + } + if (gBattleMoveFlags & MOVESTATUS_NOTAFFECTED) + gProtectStructs[gBankAttacker].notEffective = 1; + + gBattlescriptCurrInstr++; +} + +static void atk4B_return_atk_to_ball(void) +{ + gActiveBank = gBankAttacker; + if (!(gHitMarker & HITMARKER_FAINTED(gActiveBank))) + { + EmitReturnPokeToBall(0, 0); + MarkBufferBankForExecution(gActiveBank); + } + gBattlescriptCurrInstr++; +} + +static void atk4C_copy_poke_data(void) +{ + if (gBattleExecBuffer) + return; + + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + + gBattlePartyID[gActiveBank] = *(gBattleStruct->field_5C + gActiveBank); + + EmitGetMonData(0, 0, gBitTable[gBattlePartyID[gActiveBank]]); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 2; +} + +static void atk4D_switch_data_update(void) +{ + struct BattlePokemon oldData; + s32 i; + u8 *monData; + + if (gBattleExecBuffer) + return; + + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + oldData = gBattleMons[gActiveBank]; + monData = (u8*)(&gBattleMons[gActiveBank]); + + for (i = 0; i < sizeof(struct BattlePokemon); i++) + { + monData[i] = gBattleBufferB[gActiveBank][4 + i]; + } + + gBattleMons[gActiveBank].type1 = gBaseStats[gBattleMons[gActiveBank].species].type1; + gBattleMons[gActiveBank].type2 = gBaseStats[gBattleMons[gActiveBank].species].type2; + gBattleMons[gActiveBank].ability = GetAbilityBySpecies(gBattleMons[gActiveBank].species, gBattleMons[gActiveBank].altAbility); + + // check knocked off item + i = GetBankSide(gActiveBank); + if (gWishFutureKnock.knockedOffPokes[i] & gBitTable[gBattlePartyID[gActiveBank]]) + { + gBattleMons[gActiveBank].item = 0; + } + + if (gBattleMoves[gCurrentMove].effect == EFFECT_BATON_PASS) + { + for (i = 0; i < 8; i++) + { + gBattleMons[gActiveBank].statStages[i] = oldData.statStages[i]; + } + gBattleMons[gActiveBank].status2 = oldData.status2; + } + + SwitchInClearStructs(); + + if (gBattleTypeFlags & BATTLE_TYPE_PALACE && gBattleMons[gActiveBank].maxHP / 2 >= gBattleMons[gActiveBank].hp + && gBattleMons[gActiveBank].hp != 0 && !(gBattleMons[gActiveBank].status1 & STATUS_SLEEP)) + { + gBattleStruct->field_92 |= gBitTable[gActiveBank]; + } + + gBattleScripting.bank = gActiveBank; + gBattleTextBuff1[0] = PLACEHOLDER_BEGIN; + gBattleTextBuff1[1] = 7; + gBattleTextBuff1[2] = gActiveBank; + gBattleTextBuff1[3] = gBattlePartyID[gActiveBank]; + gBattleTextBuff1[4] = EOS; + + gBattlescriptCurrInstr += 2; +} + +static void atk4E_switchin_anim(void) +{ + if (gBattleExecBuffer) + return; + + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + + if (GetBankSide(gActiveBank) == SIDE_OPPONENT + && !(gBattleTypeFlags & (BATTLE_TYPE_LINK + | BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_x2000000 + | BATTLE_TYPE_x4000000 + | BATTLE_TYPE_FRONTIER))) + HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gActiveBank].species), FLAG_SET_SEEN, gBattleMons[gActiveBank].personality); + + gAbsentBankFlags &= ~(gBitTable[gActiveBank]); + + EmitSwitchInAnim(0, gBattlePartyID[gActiveBank], gBattlescriptCurrInstr[2]); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 3; + + if (gBattleTypeFlags & BATTLE_TYPE_ARENA) + sub_81A56B4(); +} + +static void atk4F_jump_if_cannot_switch(void) +{ + s32 val = 0; + s32 compareVar = 0; + struct Pokemon *party = NULL; + s32 r7 = 0; + + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1] & ~(ATK4F_DONT_CHECK_STATUSES)); + + if (!(gBattlescriptCurrInstr[1] & ATK4F_DONT_CHECK_STATUSES) + && ((gBattleMons[gActiveBank].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION)) + || (gStatuses3[gActiveBank] & STATUS3_ROOTED))) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + } + else if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + { + #ifndef NONMATCHING + asm("":::"r5"); + #endif // NONMATCHING + if (GetBankSide(gActiveBank) == SIDE_OPPONENT) + party = gEnemyParty; + else + party = gPlayerParty; + + val = 0; + if (2 & gActiveBank) + val = 3; + + for (compareVar = val + 3; val < compareVar; val++) + { + if (GetMonData(&party[val], MON_DATA_SPECIES) != SPECIES_NONE + && !GetMonData(&party[val], MON_DATA_IS_EGG) + && GetMonData(&party[val], MON_DATA_HP) != 0 + && gBattlePartyID[gActiveBank] != val) + break; + } + + if (val == compareVar) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + else + gBattlescriptCurrInstr += 6; + } + else if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + if (gBattleTypeFlags & BATTLE_TYPE_x800000) + { + if (GetBankSide(gActiveBank) == SIDE_PLAYER) + { + party = gPlayerParty; + + val = 0; + if (sub_806D82C(sub_806D864(gActiveBank)) == TRUE) + val = 3; + } + else + { + party = gEnemyParty; + + if (gActiveBank == 1) + val = 0; + else + val = 3; + } + } + else + { + if (GetBankSide(gActiveBank) == SIDE_OPPONENT) + party = gEnemyParty; + else + party = gPlayerParty; + + + val = 0; + if (sub_806D82C(sub_806D864(gActiveBank)) == TRUE) + val = 3; + } + + for (compareVar = val + 3; val < compareVar; val++) + { + if (GetMonData(&party[val], MON_DATA_SPECIES) != SPECIES_NONE + && !GetMonData(&party[val], MON_DATA_IS_EGG) + && GetMonData(&party[val], MON_DATA_HP) != 0 + && gBattlePartyID[gActiveBank] != val) + break; + } + + if (val == compareVar) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + else + gBattlescriptCurrInstr += 6; + } + else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS && GetBankSide(gActiveBank) == SIDE_OPPONENT) + { + party = gEnemyParty; + + val = 0; + if (gActiveBank == 3) + val = 3; + + for (compareVar = val + 3; val < compareVar; val++) + { + if (GetMonData(&party[val], MON_DATA_SPECIES) != SPECIES_NONE + && !GetMonData(&party[val], MON_DATA_IS_EGG) + && GetMonData(&party[val], MON_DATA_HP) != 0 + && gBattlePartyID[gActiveBank] != val) + break; + } + + if (val == compareVar) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + else + gBattlescriptCurrInstr += 6; + } + else + { + if (GetBankSide(gActiveBank) == SIDE_OPPONENT) + { + r7 = GetBankByIdentity(1); + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + compareVar = GetBankByIdentity(3); + else + compareVar = r7; + + party = gEnemyParty; + } + else + { + r7 = GetBankByIdentity(0); + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + compareVar = GetBankByIdentity(2); + else + compareVar = r7; + + party = gPlayerParty; + } + for (val = 0; val < 6; val++) + { + if (GetMonData(&party[val], MON_DATA_HP) != 0 + && GetMonData(&party[val], MON_DATA_SPECIES) != SPECIES_NONE + && !GetMonData(&party[val], MON_DATA_IS_EGG) + && val != gBattlePartyID[r7] && val != gBattlePartyID[compareVar]) + break; + } + + if (val == 6) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + else + gBattlescriptCurrInstr += 6; + } +} + +static void sub_804CF10(u8 arg0) +{ + *(gBattleStruct->field_58 + gActiveBank) = gBattlePartyID[gActiveBank]; + *(gBattleStruct->field_5C + gActiveBank) = 6; + gBattleStruct->field_93 &= ~(gBitTable[gActiveBank]); + + EmitChoosePokemon(0, 1, arg0, 0, gBattleStruct->field_60[gActiveBank]); + MarkBufferBankForExecution(gActiveBank); +} + +static void atk50_openpartyscreen(void) +{ + u32 flags; + u8 hitmarkerFaintBits; + u8 bank; + const u8 *jumpPtr; + + bank = 0; + flags = 0; + jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + + if (gBattlescriptCurrInstr[1] == 5) + { + if ((gBattleTypeFlags & (BATTLE_TYPE_DOUBLE | BATTLE_TYPE_MULTI)) != BATTLE_TYPE_DOUBLE) + { + for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++) + { + if (gHitMarker & HITMARKER_FAINTED(gActiveBank)) + { + if (sub_80423F4(gActiveBank, 6, 6)) + { + gAbsentBankFlags |= gBitTable[gActiveBank]; + gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + } + else if (!gSpecialStatuses[gActiveBank].flag40) + { + sub_804CF10(6); + gSpecialStatuses[gActiveBank].flag40 = 1; + } + } + else + { + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + } + } + } + else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + u8 flag40_0, flag40_1, flag40_2, flag40_3; + + hitmarkerFaintBits = gHitMarker >> 0x1C; + + if (gBitTable[0] & hitmarkerFaintBits) + { + gActiveBank = 0; + if (sub_80423F4(0, 6, 6)) + { + gAbsentBankFlags |= gBitTable[gActiveBank]; + gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); + Emit_x2A(0); + MarkBufferBankForExecution(gActiveBank); + } + else if (!gSpecialStatuses[gActiveBank].flag40) + { + sub_804CF10(gBattleStruct->field_5C[2]); + gSpecialStatuses[gActiveBank].flag40 = 1; + } + else + { + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + flags |= 1; + } + } + if (gBitTable[2] & hitmarkerFaintBits && !(gBitTable[0] & hitmarkerFaintBits)) + { + gActiveBank = 2; + if (sub_80423F4(2, 6, 6)) + { + gAbsentBankFlags |= gBitTable[gActiveBank]; + gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); + Emit_x2A(0); + MarkBufferBankForExecution(gActiveBank); + } + else if (!gSpecialStatuses[gActiveBank].flag40) + { + sub_804CF10(gBattleStruct->field_5C[0]); + gSpecialStatuses[gActiveBank].flag40 = 1; + } + else if (!(flags & 1)) + { + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + } + } + if (gBitTable[1] & hitmarkerFaintBits) + { + gActiveBank = 1; + if (sub_80423F4(1, 6, 6)) + { + gAbsentBankFlags |= gBitTable[gActiveBank]; + gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); + Emit_x2A(0); + MarkBufferBankForExecution(gActiveBank); + } + else if (!gSpecialStatuses[gActiveBank].flag40) + { + sub_804CF10(gBattleStruct->field_5C[3]); + gSpecialStatuses[gActiveBank].flag40 = 1; + } + else + { + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + flags |= 2; + } + } + if (gBitTable[3] & hitmarkerFaintBits && !(gBitTable[1] & hitmarkerFaintBits)) + { + gActiveBank = 3; + if (sub_80423F4(3, 6, 6)) + { + gAbsentBankFlags |= gBitTable[gActiveBank]; + gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); + Emit_x2A(0); + MarkBufferBankForExecution(gActiveBank); + } + else if (!gSpecialStatuses[gActiveBank].flag40) + { + sub_804CF10(gBattleStruct->field_5C[1]); + gSpecialStatuses[gActiveBank].flag40 = 1; + } + else if (!(flags & 2)) + { + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + } + } + + flag40_0 = gSpecialStatuses[0].flag40; + if (!flag40_0) + { + flag40_2 = gSpecialStatuses[2].flag40; + if (!flag40_2 && hitmarkerFaintBits != 0) + { + if (gAbsentBankFlags & gBitTable[0]) + gActiveBank = 2; + else + gActiveBank = 0; + + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + } + + } + flag40_1 = gSpecialStatuses[1].flag40; + if (!flag40_1) + { + flag40_3 = gSpecialStatuses[3].flag40; + if (!flag40_3 && hitmarkerFaintBits != 0) + { + if (gAbsentBankFlags & gBitTable[1]) + gActiveBank = 3; + else + gActiveBank = 1; + + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + } + } + } + gBattlescriptCurrInstr += 6; + } + else if (gBattlescriptCurrInstr[1] == 6) + { + if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI)) + { + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + hitmarkerFaintBits = gHitMarker >> 0x1C; + if (gBitTable[2] & hitmarkerFaintBits && gBitTable[0] & hitmarkerFaintBits) + { + gActiveBank = 2; + if (sub_80423F4(2, gBattleBufferB[0][1], 6)) + { + gAbsentBankFlags |= gBitTable[gActiveBank]; + gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); + Emit_x2A(0); + MarkBufferBankForExecution(gActiveBank); + } + else if (!gSpecialStatuses[gActiveBank].flag40) + { + sub_804CF10(gBattleStruct->field_5C[0]); + gSpecialStatuses[gActiveBank].flag40 = 1; + } + } + if (gBitTable[3] & hitmarkerFaintBits && hitmarkerFaintBits & gBitTable[1]) + { + gActiveBank = 3; + if (sub_80423F4(3, gBattleBufferB[1][1], 6)) + { + gAbsentBankFlags |= gBitTable[gActiveBank]; + gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); + Emit_x2A(0); + MarkBufferBankForExecution(gActiveBank); + } + else if (!gSpecialStatuses[gActiveBank].flag40) + { + sub_804CF10(gBattleStruct->field_5C[1]); + gSpecialStatuses[gActiveBank].flag40 = 1; + } + } + gBattlescriptCurrInstr += 6; + } + else + { + gBattlescriptCurrInstr += 6; + } + } + else + { + gBattlescriptCurrInstr += 6; + } + + hitmarkerFaintBits = gHitMarker >> 0x1C; + + gBank1 = 0; + while (1) + { + if (gBitTable[gBank1] & hitmarkerFaintBits) + break; + if (gBank1 >= gNoOfAllBanks) + break; + gBank1++; + } + + if (gBank1 == gNoOfAllBanks) + gBattlescriptCurrInstr = jumpPtr; + } + else + { + if (gBattlescriptCurrInstr[1] & 0x80) + hitmarkerFaintBits = 0; // used here as the caseId for the EmitChoose function + else + hitmarkerFaintBits = 1; + + bank = GetBattleBank(gBattlescriptCurrInstr[1] & ~(0x80)); + if (gSpecialStatuses[bank].flag40) + { + gBattlescriptCurrInstr += 6; + } + else if (sub_80423F4(bank, 6, 6)) + { + gActiveBank = bank; + gAbsentBankFlags |= gBitTable[gActiveBank]; + gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); + gBattlescriptCurrInstr = jumpPtr; + } + else + { + gActiveBank = bank; + *(gBattleStruct->field_58 + gActiveBank) = gBattlePartyID[gActiveBank]; + *(gBattleStruct->field_5C + gActiveBank) = 6; + gBattleStruct->field_93 &= ~(gBitTable[gActiveBank]); + + EmitChoosePokemon(0, hitmarkerFaintBits, *(gBattleStruct->field_5C + (gActiveBank ^ 2)), 0, gBattleStruct->field_60[gActiveBank]); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 6; + + if (GetBankIdentity(gActiveBank) == 0 && gBattleResults.playerSwitchesCounter < 0xFF) + gBattleResults.playerSwitchesCounter++; + + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++) + { + if (gActiveBank != bank) + { + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + } + } + } + else + { + gActiveBank = GetBankByIdentity(GetBankIdentity(bank) ^ BIT_SIDE); + if (gAbsentBankFlags & gBitTable[gActiveBank]) + gActiveBank ^= BIT_MON; + + EmitLinkStandbyMsg(0, 2, 0); + MarkBufferBankForExecution(gActiveBank); + } + } + } +} + +static void atk51_switch_handle_order(void) +{ + s32 i; + if (gBattleExecBuffer) + return; + + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + + switch (gBattlescriptCurrInstr[2]) + { + case 0: + for (i = 0; i < gNoOfAllBanks; i++) + { + if (gBattleBufferB[i][0] == 0x22) + { + *(gBattleStruct->field_5C + i) = gBattleBufferB[i][1]; + if (!(gBattleStruct->field_93 & gBitTable[i])) + { + RecordedBattle_SetBankAction(i, gBattleBufferB[i][1]); + gBattleStruct->field_93 |= gBitTable[i]; + } + } + } + break; + case 1: + if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI)) + sub_803BDA0(gActiveBank); + break; + case 2: + if (!(gBattleStruct->field_93 & gBitTable[gActiveBank])) + { + RecordedBattle_SetBankAction(gActiveBank, gBattleBufferB[gActiveBank][1]); + gBattleStruct->field_93 |= gBitTable[gActiveBank]; + } + // fall through + case 3: + gBattleCommunication[0] = gBattleBufferB[gActiveBank][1]; + *(gBattleStruct->field_5C + gActiveBank) = gBattleBufferB[gActiveBank][1]; + + if ((gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_LINK)) == (BATTLE_TYPE_MULTI | BATTLE_TYPE_LINK)) + { + *(gActiveBank * 3 + (u8*)(gBattleStruct->field_60) + 0) &= 0xF; + *(gActiveBank * 3 + (u8*)(gBattleStruct->field_60) + 0) |= (gBattleBufferB[gActiveBank][2] & 0xF0); + *(gActiveBank * 3 + (u8*)(gBattleStruct->field_60) + 1) = gBattleBufferB[gActiveBank][3]; + + *((gActiveBank ^ 2) * 3 + (u8*)(gBattleStruct->field_60) + 0) &= (0xF0); + *((gActiveBank ^ 2) * 3 + (u8*)(gBattleStruct->field_60) + 0) |= (gBattleBufferB[gActiveBank][2] & 0xF0) >> 4; + *((gActiveBank ^ 2) * 3 + (u8*)(gBattleStruct->field_60) + 2) = gBattleBufferB[gActiveBank][3]; + } + else if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + { + sub_80571DC(gActiveBank, *(gBattleStruct->field_5C + gActiveBank)); + } + else + { + sub_803BDA0(gActiveBank); + } + + PREPARE_SPECIES_BUFFER(gBattleTextBuff1, gBattleMons[gBankAttacker].species) + PREPARE_MON_NICK_BUFFER(gBattleTextBuff2, gActiveBank, gBattleBufferB[gActiveBank][1]) + + break; + } + + gBattlescriptCurrInstr += 3; +} + +static void atk52_switch_in_effects(void) +{ + s32 i; + + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + sub_803FA70(gActiveBank); + + gHitMarker &= ~(HITMARKER_FAINTED(gActiveBank)); + gSpecialStatuses[gActiveBank].flag40 = 0; + + if (!(gSideAffecting[GetBankSide(gActiveBank)] & SIDE_STATUS_SPIKES_DAMAGED) + && (gSideAffecting[GetBankSide(gActiveBank)] & SIDE_STATUS_SPIKES) + && gBattleMons[gActiveBank].type1 != TYPE_FLYING + && gBattleMons[gActiveBank].type2 != TYPE_FLYING + && gBattleMons[gActiveBank].ability != ABILITY_LEVITATE) + { + u8 spikesDmg; + + gSideAffecting[GetBankSide(gActiveBank)] |= SIDE_STATUS_SPIKES_DAMAGED; + + gBattleMons[gActiveBank].status2 &= ~(STATUS2_DESTINY_BOND); + gHitMarker &= ~(HITMARKER_DESTINYBOND); + + spikesDmg = (5 - gSideTimers[GetBankSide(gActiveBank)].spikesAmount) * 2; + gBattleMoveDamage = gBattleMons[gActiveBank].maxHP / (spikesDmg); + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + + gBattleScripting.bank = gActiveBank; + BattleScriptPushCursor(); + + if (gBattlescriptCurrInstr[1] == 0) + gBattlescriptCurrInstr = gUnknown_082DAE90; + else if (gBattlescriptCurrInstr[1] == 1) + gBattlescriptCurrInstr = gUnknown_082DAE59; + else + gBattlescriptCurrInstr = gUnknown_082DAEC7; + } + else + { + if (gBattleMons[gActiveBank].ability == ABILITY_TRUANT && !gDisableStructs[gActiveBank].truantUnknownBit) + gDisableStructs[gActiveBank].truantCounter = 1; + + gDisableStructs[gActiveBank].truantUnknownBit = 0; + + if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, gActiveBank, 0, 0, 0) == 0 && + ItemBattleEffects(0, gActiveBank, 0) == 0) + { + gSideAffecting[GetBankSide(gActiveBank)] &= ~(SIDE_STATUS_SPIKES_DAMAGED); + + for (i = 0; i < gNoOfAllBanks; i++) + { + if (gTurnOrder[i] == gActiveBank) + gUnknown_0202407A[i] = 0xC; + } + + for (i = 0; i < gNoOfAllBanks; i++) + { + u16* hpOnSwitchout = &gBattleStruct->hpOnSwitchout[GetBankSide(i)]; + *hpOnSwitchout = gBattleMons[i].hp; + } + + if (gBattlescriptCurrInstr[1] == 5) + { + u32 hitmarkerFaintBits = gHitMarker >> 0x1C; + + gBank1++; + while (1) + { + if (hitmarkerFaintBits & gBitTable[gBank1] && !(gAbsentBankFlags & gBitTable[gBank1])) + break; + if (gBank1 >= gNoOfAllBanks) + break; + gBank1++; + } + } + gBattlescriptCurrInstr += 2; + } + } +} + +static void atk53_trainer_slide(void) +{ + gActiveBank = GetBankByIdentity(gBattlescriptCurrInstr[1]); + EmitTrainerSlide(0); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 2; +} + +static void atk54_effectiveness_sound(void) +{ + gActiveBank = gBankAttacker; + EmitEffectivenessSound(0, BS2ScriptRead16(gBattlescriptCurrInstr + 1)); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 3; +} + +static void atk55_play_sound(void) +{ + gActiveBank = gBankAttacker; + EmitPlaySound(0, BS2ScriptRead16(gBattlescriptCurrInstr + 1), 0); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 3; +} + +static void atk56_fainting_cry(void) +{ + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + EmitFaintingCry(0); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 2; +} + +static void atk57(void) +{ + gActiveBank = GetBankByIdentity(0); + Emit_x37(0, gBattleOutcome); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 1; +} + +static void atk58_return_to_ball(void) +{ + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + EmitReturnPokeToBall(0, 1); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 2; +} + +static void atk59_learnmove_inbattle(void) +{ + const u8* jumpPtr1 = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + const u8* jumpPtr2 = BSScriptReadPtr(gBattlescriptCurrInstr + 5); + + u16 ret = MonTryLearningNewMove(&gPlayerParty[gBattleStruct->expGetterId], gBattlescriptCurrInstr[9]); + while (ret == 0xFFFE) + ret = MonTryLearningNewMove(&gPlayerParty[gBattleStruct->expGetterId], 0); + + if (ret == 0) + { + gBattlescriptCurrInstr = jumpPtr2; + } + else if (ret == 0xFFFF) + { + gBattlescriptCurrInstr += 10; + } + else + { + gActiveBank = GetBankByIdentity(0); + + if (gBattlePartyID[gActiveBank] == gBattleStruct->expGetterId + && !(gBattleMons[gActiveBank].status2 & STATUS2_TRANSFORMED)) + { + GiveMoveToBattleMon(&gBattleMons[gActiveBank], ret); + } + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + gActiveBank = GetBankByIdentity(2); + if (gBattlePartyID[gActiveBank] == gBattleStruct->expGetterId + && !(gBattleMons[gActiveBank].status2 & STATUS2_TRANSFORMED)) + { + GiveMoveToBattleMon(&gBattleMons[gActiveBank], ret); + } + } + + gBattlescriptCurrInstr = jumpPtr1; + } +} + +static void atk5A_yesnoboxlearnmove(void) +{ + gActiveBank = 0; + + switch (gBattleScripting.learnMoveState) + { + case 0: + sub_8056A3C(0x18, 8, 0x1D, 0xD, 0); + sub_814F9EC(gText_BattleYesNoChoice, 0xC); + gBattleScripting.learnMoveState++; + gBattleCommunication[CURSOR_POSITION] = 0; + BattleCreateCursorAt(0); + break; + case 1: + if (gMain.newKeys & DPAD_UP && gBattleCommunication[CURSOR_POSITION] != 0) + { + PlaySE(SE_SELECT); + BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); + gBattleCommunication[CURSOR_POSITION] = 0; + BattleCreateCursorAt(0); + } + if (gMain.newKeys & DPAD_DOWN && gBattleCommunication[CURSOR_POSITION] == 0) + { + PlaySE(SE_SELECT); + BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); + gBattleCommunication[CURSOR_POSITION] = 1; + BattleCreateCursorAt(1); + } + if (gMain.newKeys & A_BUTTON) + { + PlaySE(SE_SELECT); + if (gBattleCommunication[1] == 0) + { + sub_8056A3C(0x18, 0x8, 0x1D, 0xD, 1); + BeginNormalPaletteFade(-1, 0, 0, 0x10, 0); + gBattleScripting.learnMoveState++; + } + else + { + gBattleScripting.learnMoveState = 5; + } + } + else if (gMain.newKeys & B_BUTTON) + { + PlaySE(SE_SELECT); + gBattleScripting.learnMoveState = 5; + } + break; + case 2: + if (!gPaletteFade.active) + { + FreeAllWindowBuffers(); + sub_81BFA38(gPlayerParty, gBattleStruct->expGetterId, gPlayerPartyCount - 1, ReshowBattleScreenAfterMenu, gMoveToLearn); + gBattleScripting.learnMoveState++; + } + break; + case 3: + if (!gPaletteFade.active && gMain.callback2 == BattleMainCB2) + { + gBattleScripting.learnMoveState++; + } + break; + case 4: + if (!gPaletteFade.active && gMain.callback2 == BattleMainCB2) + { + u8 movePosition = sub_81C1B94(); + if (movePosition == 4) + { + gBattleScripting.learnMoveState = 5; + } + else + { + u16 moveId = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_MOVE1 + movePosition); + if (IsHMMove2(moveId)) + { + PrepareStringBattle(0x13F, gActiveBank); + gBattleScripting.learnMoveState = 6; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + + PREPARE_MOVE_BUFFER(gBattleTextBuff2, moveId) + + RemoveMonPPBonus(&gPlayerParty[gBattleStruct->expGetterId], movePosition); + SetMonMoveSlot(&gPlayerParty[gBattleStruct->expGetterId], gMoveToLearn, movePosition); + + if (gBattlePartyID[0] == gBattleStruct->expGetterId + && !(gBattleMons[0].status2 & STATUS2_TRANSFORMED) + && !(gDisableStructs[0].unk18_b & gBitTable[movePosition])) + { + RemoveBattleMonPPBonus(&gBattleMons[0], movePosition); + SetBattleMonMoveSlot(&gBattleMons[0], gMoveToLearn, movePosition); + } + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && gBattlePartyID[2] == gBattleStruct->expGetterId + && !(gBattleMons[2].status2 & STATUS2_TRANSFORMED) + && !(gDisableStructs[2].unk18_b & gBitTable[movePosition])) + { + RemoveBattleMonPPBonus(&gBattleMons[2], movePosition); + SetBattleMonMoveSlot(&gBattleMons[2], gMoveToLearn, movePosition); + } + } + } + } + break; + case 5: + sub_8056A3C(0x18, 8, 0x1D, 0xD, 1); + gBattlescriptCurrInstr += 5; + break; + case 6: + if (gBattleExecBuffer == 0) + { + gBattleScripting.learnMoveState = 2; + } + break; + } +} + +static void atk5B_yesnoboxstoplearningmove(void) +{ + switch (gBattleScripting.learnMoveState) + { + case 0: + sub_8056A3C(0x18, 8, 0x1D, 0xD, 0); + sub_814F9EC(gText_BattleYesNoChoice, 0xC); + gBattleScripting.learnMoveState++; + gBattleCommunication[CURSOR_POSITION] = 0; + BattleCreateCursorAt(0); + break; + case 1: + if (gMain.newKeys & DPAD_UP && gBattleCommunication[CURSOR_POSITION] != 0) + { + PlaySE(SE_SELECT); + BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); + gBattleCommunication[CURSOR_POSITION] = 0; + BattleCreateCursorAt(0); + } + if (gMain.newKeys & DPAD_DOWN && gBattleCommunication[CURSOR_POSITION] == 0) + { + PlaySE(SE_SELECT); + BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); + gBattleCommunication[CURSOR_POSITION] = 1; + BattleCreateCursorAt(1); + } + if (gMain.newKeys & A_BUTTON) + { + PlaySE(SE_SELECT); + + if (gBattleCommunication[1] != 0) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + else + gBattlescriptCurrInstr += 5; + + sub_8056A3C(0x18, 0x8, 0x1D, 0xD, 1); + } + else if (gMain.newKeys & B_BUTTON) + { + PlaySE(SE_SELECT); + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + sub_8056A3C(0x18, 0x8, 0x1D, 0xD, 1); + } + break; + } +} + +static void atk5C_hitanimation(void) +{ + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + + if (gBattleMoveFlags & MOVESTATUS_NOEFFECT) + { + gBattlescriptCurrInstr += 2; + } + else if (!(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE) || !(gBattleMons[gActiveBank].status2 & STATUS2_SUBSTITUTE) || gDisableStructs[gActiveBank].substituteHP == 0) + { + EmitHitAnimation(0); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 2; + } + else + { + gBattlescriptCurrInstr += 2; + } +} + +static u32 GetTrainerMoneyToGive(u16 trainerId) +{ + u32 i = 0; + u32 lastMonLevel = 0; + u32 moneyReward = 0; + + if (trainerId == SECRET_BASE_OPPONENT) + { + moneyReward = 20 * gBattleResources->secretBase->partyLevels[0] * gBattleStruct->moneyMultiplier; + } + else + { + switch (gTrainers[trainerId].partyFlags) + { + case 0: + { + const struct TrainerMonNoItemDefaultMoves *party = gTrainers[trainerId].party.NoItemDefaultMoves; + lastMonLevel = party[gTrainers[trainerId].partySize - 1].lvl; + } + break; + case PARTY_FLAG_CUSTOM_MOVES: + { + const struct TrainerMonNoItemCustomMoves *party = gTrainers[trainerId].party.NoItemCustomMoves; + lastMonLevel = party[gTrainers[trainerId].partySize - 1].lvl; + } + break; + case PARTY_FLAG_HAS_ITEM: + { + const struct TrainerMonItemDefaultMoves *party = gTrainers[trainerId].party.ItemDefaultMoves; + lastMonLevel = party[gTrainers[trainerId].partySize - 1].lvl; + } + break; + case PARTY_FLAG_CUSTOM_MOVES | PARTY_FLAG_HAS_ITEM: + { + const struct TrainerMonItemCustomMoves *party = gTrainers[trainerId].party.ItemCustomMoves; + lastMonLevel = party[gTrainers[trainerId].partySize - 1].lvl; + } + break; + } + + for (; gTrainerMoneyTable[i].classId != 0xFF; i++) + { + if (gTrainerMoneyTable[i].classId == gTrainers[trainerId].trainerClass) + break; + } + + if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + moneyReward = 4 * lastMonLevel * gBattleStruct->moneyMultiplier * gTrainerMoneyTable[i].value; + else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + moneyReward = 4 * lastMonLevel * gBattleStruct->moneyMultiplier * 2 * gTrainerMoneyTable[i].value; + else + moneyReward = 4 * lastMonLevel * gBattleStruct->moneyMultiplier * gTrainerMoneyTable[i].value; + } + + return moneyReward; +} + +static void atk5D_getmoneyreward(void) +{ + u32 moneyReward = GetTrainerMoneyToGive(gTrainerBattleOpponent_A); + if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + moneyReward += GetTrainerMoneyToGive(gTrainerBattleOpponent_B); + + AddMoney(&gSaveBlock1Ptr->money, moneyReward); + + PREPARE_WORD_NUMBER_BUFFER(gBattleTextBuff1, 5, moneyReward) + + gBattlescriptCurrInstr++; +} + +static void atk5E_8025A70(void) +{ + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + + switch (gBattleCommunication[0]) + { + case 0: + EmitGetMonData(0, REQUEST_ALL_BATTLE, 0); + MarkBufferBankForExecution(gActiveBank); + gBattleCommunication[0]++; + break; + case 1: + if (gBattleExecBuffer == 0) + { + s32 i; + struct BattlePokemon* bufferPoke = (struct BattlePokemon*) &gBattleBufferB[gActiveBank][4]; + for (i = 0; i < 4; i++) + { + gBattleMons[gActiveBank].moves[i] = bufferPoke->moves[i]; + gBattleMons[gActiveBank].pp[i] = bufferPoke->pp[i]; + } + gBattlescriptCurrInstr += 2; + } + break; + } +} + +static void atk5F_8025B24(void) +{ + gActiveBank = gBankAttacker; + gBankAttacker = gBankTarget; + gBankTarget = gActiveBank; + + if (gHitMarker & HITMARKER_PURSUIT_TRAP) + gHitMarker &= ~(HITMARKER_PURSUIT_TRAP); + else + gHitMarker |= HITMARKER_PURSUIT_TRAP; + + gBattlescriptCurrInstr++; +} + +static void atk60_increment_gamestat(void) +{ + if (GetBankSide(gBankAttacker) == SIDE_PLAYER) + IncrementGameStat(gBattlescriptCurrInstr[1]); + + gBattlescriptCurrInstr += 2; +} + +static void atk61_8025BA4(void) +{ + s32 i; + struct Pokemon* party; + struct HpAndStatus hpStatuses[6]; + + if (gBattleExecBuffer) + return; + + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + + if (GetBankSide(gActiveBank) == SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + for (i = 0; i < 6; i++) + { + if (GetMonData(&party[i], MON_DATA_SPECIES2) == SPECIES_NONE + || GetMonData(&party[i], MON_DATA_SPECIES2) == SPECIES_EGG) + { + hpStatuses[i].hp = 0xFFFF; + hpStatuses[i].status = 0; + } + else + { + hpStatuses[i].hp = GetMonData(&party[i], MON_DATA_HP); + hpStatuses[i].status = GetMonData(&party[i], MON_DATA_STATUS); + } + } + + EmitCmd48(0, hpStatuses, 1); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 2; +} + +static void atk62_08025C6C(void) +{ + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + EmitCmd49(0); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 2; +} + +static void atk63_jumptorandomattack(void) +{ + if (gBattlescriptCurrInstr[1] != 0) + gCurrentMove = gRandomMove; + else + gLastUsedMove = gCurrentMove = gRandomMove; + + gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]; +} + +static void atk64_statusanimation(void) +{ + if (gBattleExecBuffer == 0) + { + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + if (!(gStatuses3[gActiveBank] & STATUS3_SEMI_INVULNERABLE) + && gDisableStructs[gActiveBank].substituteHP == 0 + && !(gHitMarker & HITMARKER_NO_ANIMATIONS)) + { + EmitStatusAnimation(0, FALSE, gBattleMons[gActiveBank].status1); + MarkBufferBankForExecution(gActiveBank); + } + gBattlescriptCurrInstr += 2; + } +} + +static void atk65_status2animation(void) +{ + u32 wantedToAnimate; + + if (gBattleExecBuffer == 0) + { + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + wantedToAnimate = BSScriptRead32(gBattlescriptCurrInstr + 2); + if (!(gStatuses3[gActiveBank] & STATUS3_SEMI_INVULNERABLE) + && gDisableStructs[gActiveBank].substituteHP == 0 + && !(gHitMarker & HITMARKER_NO_ANIMATIONS)) + { + EmitStatusAnimation(0, TRUE, gBattleMons[gActiveBank].status2 & wantedToAnimate); + MarkBufferBankForExecution(gActiveBank); + } + gBattlescriptCurrInstr += 6; + } +} + +static void atk66_chosenstatusanimation(void) +{ + u32 wantedStatus; + + if (gBattleExecBuffer == 0) + { + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + wantedStatus = BSScriptRead32(gBattlescriptCurrInstr + 3); + if (!(gStatuses3[gActiveBank] & STATUS3_SEMI_INVULNERABLE) + && gDisableStructs[gActiveBank].substituteHP == 0 + && !(gHitMarker & HITMARKER_NO_ANIMATIONS)) + { + EmitStatusAnimation(0, gBattlescriptCurrInstr[2], wantedStatus); + MarkBufferBankForExecution(gActiveBank); + } + gBattlescriptCurrInstr += 7; + } +} + +static void atk67_yesnobox(void) +{ + switch (gBattleCommunication[0]) + { + case 0: + sub_8056A3C(0x18, 8, 0x1D, 0xD, 0); + sub_814F9EC(gText_BattleYesNoChoice, 0xC); + gBattleCommunication[0]++; + gBattleCommunication[CURSOR_POSITION] = 0; + BattleCreateCursorAt(0); + break; + case 1: + if (gMain.newKeys & DPAD_UP && gBattleCommunication[CURSOR_POSITION] != 0) + { + PlaySE(SE_SELECT); + BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); + gBattleCommunication[CURSOR_POSITION] = 0; + BattleCreateCursorAt(0); + } + if (gMain.newKeys & DPAD_DOWN && gBattleCommunication[CURSOR_POSITION] == 0) + { + PlaySE(SE_SELECT); + BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); + gBattleCommunication[CURSOR_POSITION] = 1; + BattleCreateCursorAt(1); + } + if (gMain.newKeys & B_BUTTON) + { + gBattleCommunication[CURSOR_POSITION] = 1; + PlaySE(SE_SELECT); + sub_8056A3C(0x18, 8, 0x1D, 0xD, 1); + gBattlescriptCurrInstr++; + } + else if (gMain.newKeys & A_BUTTON) + { + PlaySE(SE_SELECT); + sub_8056A3C(0x18, 8, 0x1D, 0xD, 1); + gBattlescriptCurrInstr++; + } + break; + } +} + +static void atk68_80246A0(void) +{ + s32 i; + + for (i = 0; i < gNoOfAllBanks; i++) + gUnknown_0202407A[i] = 0xC; + + gBattlescriptCurrInstr++; +} + +static void atk69_dmg_adjustment3(void) // The same as 0x7, except there's no random damage multiplier. +{ + u8 holdEffect, quality; + + if (gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY) + { + holdEffect = gEnigmaBerries[gBankTarget].holdEffect, quality = gEnigmaBerries[gBankTarget].holdEffectParam; + } + else + { + holdEffect = ItemId_GetHoldEffect(gBattleMons[gBankTarget].item); + quality = ItemId_GetHoldEffectParam(gBattleMons[gBankTarget].item); + } + + gStringBank = gBankTarget; + + if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < quality) + { + RecordItemEffectBattle(gBankTarget, holdEffect); + gSpecialStatuses[gBankTarget].focusBanded = 1; + } + if (gBattleMons[gBankTarget].status2 & STATUS2_SUBSTITUTE) + goto END; + if (gBattleMoves[gCurrentMove].effect != EFFECT_FALSE_SWIPE && !gProtectStructs[gBankTarget].endured + && !gSpecialStatuses[gBankTarget].focusBanded) + goto END; + + if (gBattleMons[gBankTarget].hp > gBattleMoveDamage) + goto END; + + gBattleMoveDamage = gBattleMons[gBankTarget].hp - 1; + + if (gProtectStructs[gBankTarget].endured) + { + gBattleMoveFlags |= MOVESTATUS_ENDURED; + } + else if (gSpecialStatuses[gBankTarget].focusBanded) + { + gBattleMoveFlags |= MOVESTATUS_HUNGON; + gLastUsedItem = gBattleMons[gBankTarget].item; + } + + END: + gBattlescriptCurrInstr++; +} + +static void atk6A_removeitem(void) +{ + u16* usedHeldItem; + + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + + usedHeldItem = &gBattleStruct->usedHeldItems[gActiveBank]; + *usedHeldItem = gBattleMons[gActiveBank].item; + gBattleMons[gActiveBank].item = 0; + + EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gActiveBank].item); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 2; +} + +static void atk6B_atknameinbuff1(void) +{ + PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, gBankAttacker, gBattlePartyID[gBankAttacker]) + + gBattlescriptCurrInstr++; +} + +static void atk6C_draw_lvlupbox(void) +{ + if (gBattleScripting.atk6C_state == 0) + { + if (IsMonGettingExpSentOut()) + gBattleScripting.atk6C_state = 3; + else + gBattleScripting.atk6C_state = 1; + } + + switch (gBattleScripting.atk6C_state) + { + case 1: + gBattle_BG2_Y = 0x60; + SetBgAttribute(2, BG_CTRL_ATTR_MOSAIC, 0); + ShowBg(2); + sub_804F17C(); + gBattleScripting.atk6C_state = 2; + break; + case 2: + if (!sub_804F1CC()) + gBattleScripting.atk6C_state = 3; + break; + case 3: + gBattle_BG1_X = 0; + gBattle_BG1_Y = 0x100; + SetBgAttribute(0, BG_CTRL_ATTR_MOSAIC, 1); + SetBgAttribute(1, BG_CTRL_ATTR_MOSAIC, 0); + ShowBg(0); + ShowBg(1); + sub_8056A3C(0x12, 7, 0x1D, 0x13, 0x80); + gBattleScripting.atk6C_state = 4; + break; + case 4: + sub_804F100(); + PutWindowTilemap(13); + CopyWindowToVram(13, 3); + gBattleScripting.atk6C_state++; + break; + case 5: + case 7: + if (!IsDma3ManagerBusyWithBgCopy()) + { + gBattle_BG1_Y = 0; + gBattleScripting.atk6C_state++; + } + break; + case 6: + if (gMain.newKeys != 0) + { + PlaySE(SE_SELECT); + sub_804F144(); + CopyWindowToVram(13, 2); + gBattleScripting.atk6C_state++; + } + break; + case 8: + if (gMain.newKeys != 0) + { + PlaySE(SE_SELECT); + sub_8056A3C(0x12, 7, 0x1D, 0x13, 0x81); + gBattleScripting.atk6C_state++; + } + break; + case 9: + if (!sub_804F344()) + { + ClearWindowTilemap(14); + CopyWindowToVram(14, 1); + + ClearWindowTilemap(13); + CopyWindowToVram(13, 1); + + SetBgAttribute(2, BG_CTRL_ATTR_MOSAIC, 2); + ShowBg(2); + + gBattleScripting.atk6C_state = 10; + } + break; + case 10: + if (!IsDma3ManagerBusyWithBgCopy()) + { + SetBgAttribute(0, BG_CTRL_ATTR_MOSAIC, 0); + SetBgAttribute(1, BG_CTRL_ATTR_MOSAIC, 1); + ShowBg(0); + ShowBg(1); + gBattlescriptCurrInstr++; + } + break; + } +} + +static void sub_804F100(void) +{ + struct StatsArray currentStats; + + sub_81D388C(&gPlayerParty[gBattleStruct->expGetterId], ¤tStats); + sub_81D3640(0xD, gBattleResources->statsBeforeLvlUp, ¤tStats, 0xE, 0xD, 0xF); +} + +static void sub_804F144(void) +{ + struct StatsArray currentStats; + + sub_81D388C(&gPlayerParty[gBattleStruct->expGetterId], ¤tStats); + sub_81D3784(0xD, ¤tStats, 0xE, 0xD, 0xF); +} + +static void sub_804F17C(void) +{ + gBattle_BG2_Y = 0; + gBattle_BG2_X = 0x1A0; + + LoadPalette(sUnknown_0831C2C8, 0x60, 0x20); + CopyToWindowPixelBuffer(14, sUnknown_0831C2E8, 0, 0); + PutWindowTilemap(14); + CopyWindowToVram(14, 3); + + PutMonIconOnLvlUpBox(); +} + +static bool8 sub_804F1CC(void) +{ + if (IsDma3ManagerBusyWithBgCopy()) + return TRUE; + + if (gBattle_BG2_X == 0x200) + return FALSE; + + if (gBattle_BG2_X == 0x1A0) + PutLevelAndGenderOnLvlUpBox(); + + gBattle_BG2_X += 8; + if (gBattle_BG2_X >= 0x200) + gBattle_BG2_X = 0x200; + + return (gBattle_BG2_X != 0x200); +} + +static void PutLevelAndGenderOnLvlUpBox(void) +{ + u16 monLevel; + u8 monGender; + struct TextSubPrinter subPrinter; + u8 *txtPtr; + u32 var; + + monLevel = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_LEVEL); + monGender = GetMonGender(&gPlayerParty[gBattleStruct->expGetterId]); + GetMonNickname(&gPlayerParty[gBattleStruct->expGetterId], gStringVar4); + + subPrinter.current_text_offset = gStringVar4; + subPrinter.windowId = 14; + subPrinter.fontId = 0; + subPrinter.x = 32; + subPrinter.y = 0; + subPrinter.currentX = 32; + subPrinter.currentY = 0; + subPrinter.letterSpacing = 0; + subPrinter.lineSpacing = 0; + subPrinter.fontColor_l = TEXT_COLOR_TRANSPARENT; + subPrinter.fontColor_h = TEXT_COLOR_WHITE; + subPrinter.bgColor = TEXT_COLOR_TRANSPARENT; + subPrinter.shadowColor = TEXT_COLOR_DARK_GREY; + + AddTextPrinter(&subPrinter, 0xFF, NULL); + + txtPtr = gStringVar4; + gStringVar4[0] = CHAR_SPECIAL_F9; + txtPtr++; + txtPtr[0] = 5; + txtPtr++; + + var = (u32)(txtPtr); + txtPtr = ConvertIntToDecimalStringN(txtPtr, monLevel, STR_CONV_MODE_LEFT_ALIGN, 3); + var = (u32)(txtPtr) - var; + txtPtr = StringFill(txtPtr, 0x77, 4 - var); + + if (monGender != MON_GENDERLESS) + { + if (monGender == MON_MALE) + { + txtPtr = WriteColorChangeControlCode(txtPtr, 0, 0xC); + txtPtr = WriteColorChangeControlCode(txtPtr, 1, 0xD); + *(txtPtr++) = CHAR_MALE; + } + else + { + txtPtr = WriteColorChangeControlCode(txtPtr, 0, 0xE); + txtPtr = WriteColorChangeControlCode(txtPtr, 1, 0xF); + *(txtPtr++) = CHAR_FEMALE; + } + *(txtPtr++) = EOS; + } + + subPrinter.y = 10; + subPrinter.currentY = 10; + AddTextPrinter(&subPrinter, 0xFF, NULL); + + CopyWindowToVram(14, 2); +} + +static bool8 sub_804F344(void) +{ + if (gBattle_BG2_X == 0x1A0) + return FALSE; + + if (gBattle_BG2_X - 16 < 0x1A0) + gBattle_BG2_X = 0x1A0; + else + gBattle_BG2_X -= 16; + + return (gBattle_BG2_X != 0x1A0); +} + +#define sDestroy data0 +#define sSavedLvlUpBoxXPosition data1 + +static void PutMonIconOnLvlUpBox(void) +{ + u8 spriteId; + const u16* iconPal; + struct SpriteSheet iconSheet; + struct SpritePalette iconPalSheet; + + u16 species = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_SPECIES); + u32 personality = GetMonData(&gPlayerParty[gBattleStruct->expGetterId], MON_DATA_PERSONALITY); + + const u8* iconPtr = GetMonIconPtr(species, personality, 1); + iconSheet.data = iconPtr; + iconSheet.size = 0x200; + iconSheet.tag = MON_ICON_LVLUP_BOX_TAG; + + iconPal = GetValidMonIconPalettePtr(species); + iconPalSheet.data = iconPal; + iconPalSheet.tag = MON_ICON_LVLUP_BOX_TAG; + + LoadSpriteSheet(&iconSheet); + LoadSpritePalette(&iconPalSheet); + + spriteId = CreateSprite(&sSpriteTemplate_MonIconOnLvlUpBox, 256, 10, 0); + gSprites[spriteId].sDestroy = FALSE; + gSprites[spriteId].sSavedLvlUpBoxXPosition = gBattle_BG2_X; +} + +static void SpriteCB_MonIconOnLvlUpBox(struct Sprite* sprite) +{ + sprite->pos2.x = sprite->sSavedLvlUpBoxXPosition - gBattle_BG2_X; + + if (sprite->pos2.x != 0) + { + sprite->sDestroy = TRUE; + } + else if (sprite->sDestroy) + { + DestroySprite(sprite); + FreeSpriteTilesByTag(MON_ICON_LVLUP_BOX_TAG); + FreeSpritePaletteByTag(MON_ICON_LVLUP_BOX_TAG); + } +} + +#undef sDestroy +#undef sSavedLvlUpBoxXPosition + +static bool32 IsMonGettingExpSentOut(void) +{ + if (gBattlePartyID[0] == gBattleStruct->expGetterId) + return TRUE; + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && gBattlePartyID[2] == gBattleStruct->expGetterId) + return TRUE; + + return FALSE; +} + +static void atk6D_reset_sentpokes_value(void) +{ + ResetSentPokesToOpponentValue(); + gBattlescriptCurrInstr++; +} + +static void atk6E_set_atk_to_player0(void) +{ + gBankAttacker = GetBankByIdentity(0); + gBattlescriptCurrInstr++; +} + +static void atk6F_set_visible(void) +{ + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + EmitSpriteInvisibility(0, FALSE); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 2; +} + +static void atk70_record_last_used_ability(void) +{ + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + RecordAbilityBattle(gActiveBank, gLastUsedAbility); + gBattlescriptCurrInstr += 1; // UB: Should be + 2, one byte for command and one byte for bank argument. +} + +void BufferMoveToLearnIntoBattleTextBuff2(void) +{ + PREPARE_MOVE_BUFFER(gBattleTextBuff2, gMoveToLearn); +} + +static void atk71_buffer_move_to_learn(void) +{ + BufferMoveToLearnIntoBattleTextBuff2(); + gBattlescriptCurrInstr++; +} + +static void atk72_jump_if_can_run_frombattle(void) +{ + if (CanRunFromBattle(gBank1)) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + else + gBattlescriptCurrInstr += 5; +} + +static void atk73_hp_thresholds(void) +{ + u8 opposingBank; + s32 result; + + if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + { + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + opposingBank = gActiveBank ^ BIT_SIDE; + + result = gBattleMons[opposingBank].hp * 100 / gBattleMons[opposingBank].maxHP; + if (result == 0) + result = 1; + + if (result > 69 || !gBattleMons[opposingBank].hp) + gBattleStruct->hpScale = 0; + else if (result > 39) + gBattleStruct->hpScale = 1; + else if (result > 9) + gBattleStruct->hpScale = 2; + else + gBattleStruct->hpScale = 3; + } + + gBattlescriptCurrInstr += 2; +} + +static void atk74_hp_thresholds2(void) +{ + u8 opposingBank; + s32 result; + u8 hpSwitchout; + + if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + { + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + opposingBank = gActiveBank ^ BIT_SIDE; + hpSwitchout = *(gBattleStruct->hpOnSwitchout + GetBankSide(opposingBank)); + result = (hpSwitchout - gBattleMons[opposingBank].hp) * 100 / hpSwitchout; + + if (gBattleMons[opposingBank].hp >= hpSwitchout) + gBattleStruct->hpScale = 0; + else if (result <= 29) + gBattleStruct->hpScale = 1; + else if (result <= 69) + gBattleStruct->hpScale = 2; + else + gBattleStruct->hpScale = 3; + } + + gBattlescriptCurrInstr += 2; +} + +static void atk75_item_effect_on_opponent(void) +{ + gBankInMenu = gBankAttacker; + ExecuteTableBasedItemEffect(&gEnemyParty[gBattlePartyID[gBankAttacker]], gLastUsedItem, gBattlePartyID[gBankAttacker], 0, 1); + + gBattlescriptCurrInstr += 1; +} + +static void atk76_various(void) +{ + u8 side; + s32 i; + + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + + switch (gBattlescriptCurrInstr[2]) + { + case VARIOUS_CANCEL_MULTI_TURN_MOVES: + CancelMultiTurnMoves(gActiveBank); + break; + case VARIOUS_SET_MAGIC_COAT_TARGET: + gBankAttacker = gBankTarget; + side = GetBankSide(gBankAttacker) ^ 1; + if (gSideTimers[side].followmeTimer != 0 && gBattleMons[gSideTimers[side].followmeTarget].hp != 0) + gBankTarget = gSideTimers[side].followmeTarget; + else + gBankTarget = gActiveBank; + break; + case 2: + gBattleCommunication[0] = IsRunningFromBattleImpossible(); + break; + case VARIOUS_GET_MOVE_TARGET: + gBankTarget = GetMoveTarget(gCurrentMove, 0); + break; + case 4: + if (gHitMarker & HITMARKER_FAINTED(gActiveBank)) + gBattleCommunication[0] = 1; + else + gBattleCommunication[0] = 0; + break; + case VARIOUS_RESET_INTIMIDATE_TRACE_BITS: + gSpecialStatuses[gActiveBank].intimidatedPoke = 0; + gSpecialStatuses[gActiveBank].traced = 0; + break; + case VARIOUS_UPDATE_CHOICE_MOVE_ON_LVL_UP: + if (gBattlePartyID[0] == gBattleStruct->expGetterId || gBattlePartyID[2] == gBattleStruct->expGetterId) + { + u16 *choicedMove; + + if (gBattlePartyID[0] == gBattleStruct->expGetterId) + gActiveBank = 0; + else + gActiveBank = 2; + + choicedMove = &gBattleStruct->choicedMove[gActiveBank]; + + for (i = 0; i < 4; i++) + { + if (gBattleMons[gActiveBank].moves[i] == *choicedMove) + break; + } + if (i == 4) + *choicedMove = 0; + } + break; + case 7: + if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_DOUBLE)) + && gBattleTypeFlags & BATTLE_TYPE_TRAINER + && gBattleMons[0].hp != 0 + && gBattleMons[1].hp != 0) + { + gHitMarker &= ~(HITMARKER_x400000); + } + break; + case 8: + gBattleCommunication[0] = 0; + gBattleScripting.bank = gActiveBank = gBattleCommunication[1]; + if (!(gBattleStruct->field_92 & gBitTable[gActiveBank]) + && gBattleMons[gActiveBank].maxHP / 2 >= gBattleMons[gActiveBank].hp + && gBattleMons[gActiveBank].hp != 0 + && !(gBattleMons[gActiveBank].status1 & STATUS_SLEEP)) + { + gBattleStruct->field_92 |= gBitTable[gActiveBank]; + gBattleCommunication[0] = 1; + gBattleCommunication[MULTISTRING_CHOOSER] = sUnknown_0831C4F8[GetNatureFromPersonality(gBattleMons[gActiveBank].personality)]; + } + break; + case 9: + i = sub_81A5258(gBattleCommunication); + if (i == 0) + return; + + gBattleCommunication[1] = i; + break; + case 10: + gBattleMons[1].hp = 0; + gHitMarker |= HITMARKER_FAINTED(1); + gBattleStruct->field_2A1 |= gBitTable[gBattlePartyID[1]]; + gDisableStructs[1].truantUnknownBit = 1; + break; + case 11: + gBattleMons[0].hp = 0; + gHitMarker |= HITMARKER_FAINTED(0); + gHitMarker |= HITMARKER_x400000; + gBattleStruct->field_2A0 |= gBitTable[gBattlePartyID[0]]; + gDisableStructs[0].truantUnknownBit = 1; + break; + case 12: + gBattleMons[0].hp = 0; + gBattleMons[1].hp = 0; + gHitMarker |= HITMARKER_FAINTED(0); + gHitMarker |= HITMARKER_FAINTED(1); + gHitMarker |= HITMARKER_x400000; + gBattleStruct->field_2A0 |= gBitTable[gBattlePartyID[0]]; + gBattleStruct->field_2A1 |= gBitTable[gBattlePartyID[1]]; + gDisableStructs[0].truantUnknownBit = 1; + gDisableStructs[1].truantUnknownBit = 1; + break; + case 13: + EmitCmd13(0); + MarkBufferBankForExecution(gActiveBank); + break; + case 14: + sub_81A5BF8(); + break; + case 15: + sub_81A5D44(); + break; + case 16: + BattleStringExpandPlaceholdersToDisplayedString(gRefereeStringsTable[gBattlescriptCurrInstr[1]]); + sub_814F9EC(gDisplayedStringBattle, 0x16); + break; + case 17: + if (IsTextPrinterActive(0x16)) + return; + break; + case VARIOUS_WAIT_CRY: + if (!IsCryFinished()) + return; + break; + case VARIOUS_RETURN_OPPONENT_MON1: + gActiveBank = 1; + if (gBattleMons[gActiveBank].hp != 0) + { + EmitReturnPokeToBall(0, 0); + MarkBufferBankForExecution(gActiveBank); + } + break; + case VARIOUS_RETURN_OPPONENT_MON2: + if (gNoOfAllBanks > 3) + { + gActiveBank = 3; + if (gBattleMons[gActiveBank].hp != 0) + { + EmitReturnPokeToBall(0, 0); + MarkBufferBankForExecution(gActiveBank); + } + } + break; + case 21: + m4aMPlayVolumeControl(&gMPlay_BGM, 0xFFFF, 0x55); + break; + case 22: + m4aMPlayVolumeControl(&gMPlay_BGM, 0xFFFF, 0x100); + break; + case 23: + gBattleStruct->field_2A2 |= gBitTable[gActiveBank]; + break; + case 24: + if (sub_805725C(gActiveBank)) + return; + break; + case VARIOUS_SET_TELEPORT_OUTCOME: + if (GetBankSide(gActiveBank) == SIDE_PLAYER) + gBattleOutcome = BATTLE_PLAYER_TELEPORTED; + else + gBattleOutcome = BATTLE_OPPONENT_TELEPORTED; + break; + case VARIOUS_PLAY_TRAINER_DEFEATED_MUSIC: + EmitPlaySound(0, 0x19C, 1); + MarkBufferBankForExecution(gActiveBank); + break; + } + + gBattlescriptCurrInstr += 3; +} + +static void atk77_set_protect_like(void) // protect and endure +{ + bool8 notLastTurn = TRUE; + u16 lastMove = gUnknown_02024260[gBankAttacker]; + + if (lastMove != MOVE_PROTECT && lastMove != MOVE_DETECT && lastMove != MOVE_ENDURE) + gDisableStructs[gBankAttacker].protectUses = 0; + + if (gCurrentMoveTurn == (gNoOfAllBanks - 1)) + notLastTurn = FALSE; + + if (sProtectSuccessRates[gDisableStructs[gBankAttacker].protectUses] >= Random() && notLastTurn) + { + if (gBattleMoves[gCurrentMove].effect == EFFECT_PROTECT) + { + gProtectStructs[gBankAttacker].protected = 1; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + if (gBattleMoves[gCurrentMove].effect == EFFECT_ENDURE) + { + gProtectStructs[gBankAttacker].endured = 1; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + gDisableStructs[gBankAttacker].protectUses++; + } + else + { + gDisableStructs[gBankAttacker].protectUses = 0; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + gBattleMoveFlags |= MOVESTATUS_MISSED; + } + + gBattlescriptCurrInstr++; +} + +static void atk78_faintifabilitynotdamp(void) +{ + if (gBattleExecBuffer) + return; + + for (gBankTarget = 0; gBankTarget < gNoOfAllBanks; gBankTarget++) + { + if (gBattleMons[gBankTarget].ability == ABILITY_DAMP) + break; + } + + if (gBankTarget == gNoOfAllBanks) + { + gActiveBank = gBankAttacker; + gBattleMoveDamage = gBattleMons[gActiveBank].hp; + EmitHealthBarUpdate(0, 0x7FFF); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr++; + + for (gBankTarget = 0; gBankTarget < gNoOfAllBanks; gBankTarget++) + { + if (gBankTarget == gBankAttacker) + continue; + if (!(gAbsentBankFlags & gBitTable[gBankTarget])) + break; + } + } + else + { + gLastUsedAbility = ABILITY_DAMP; + RecordAbilityBattle(gBankTarget, gBattleMons[gBankTarget].ability); + gBattlescriptCurrInstr = BattleScript_DampStopsExplosion; + } +} + +static void atk79_setatkhptozero(void) +{ + if (gBattleExecBuffer) + return; + + gActiveBank = gBankAttacker; + gBattleMons[gActiveBank].hp = 0; + EmitSetMonData(0, REQUEST_HP_BATTLE, 0, 2, &gBattleMons[gActiveBank].hp); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr++; +} + +static void atk7A_jumpwhiletargetvalid(void) // Used by intimidate to loop through all targets. +{ + const u8* jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + for (gBankTarget++; ; gBankTarget++) + { + if (gBankTarget == gBankAttacker) + continue; + if (!(gAbsentBankFlags & gBitTable[gBankTarget])) + break; + } + + if (gBankTarget >= gNoOfAllBanks) + gBattlescriptCurrInstr += 5; + else + gBattlescriptCurrInstr = jumpPtr; + } + else + gBattlescriptCurrInstr += 5; +} + +static void atk7B_healhalfHP_if_possible(void) +{ + const u8* failPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + + if (gBattlescriptCurrInstr[5] == BS_GET_ATTACKER) + gBankTarget = gBankAttacker; + + gBattleMoveDamage = gBattleMons[gBankTarget].maxHP / 2; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + gBattleMoveDamage *= -1; + + if (gBattleMons[gBankTarget].hp == gBattleMons[gBankTarget].maxHP) + gBattlescriptCurrInstr = failPtr; + else + gBattlescriptCurrInstr += 6; +} + +static void atk7C_trymirrormove(void) +{ + s32 validMovesCount; + s32 i; + u16 move; + u16 movesArray[4]; + + for (i = 0; i < 3; i++) + movesArray[i] = 0; + + for (validMovesCount = 0, i = 0; i < gNoOfAllBanks; i++) + { + if (i != gBankAttacker) + { + move = *(i * 2 + gBankAttacker * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) + | (*(i * 2 + gBankAttacker * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) << 8); + + if (move != 0 && move != 0xFFFF) + { + movesArray[validMovesCount] = move; + validMovesCount++; + } + } + } + + move = *(gBattleStruct->mirrorMoves + gBankAttacker * 2 + 0) + | (*(gBattleStruct->mirrorMoves + gBankAttacker * 2 + 1) << 8); + + if (move != 0 && move != 0xFFFF) + { + gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); + gCurrentMove = move; + gBankTarget = GetMoveTarget(gCurrentMove, 0); + gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]; + } + else if (validMovesCount) + { + gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); + i = Random() % validMovesCount; + gCurrentMove = movesArray[i]; + gBankTarget = GetMoveTarget(gCurrentMove, 0); + gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]; + } + else + { + gSpecialStatuses[gBankAttacker].flag20 = 1; + gBattlescriptCurrInstr++; + } +} + +static void atk7D_set_rain(void) +{ + if (gBattleWeather & WEATHER_RAIN_ANY) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + } + else + { + gBattleWeather = WEATHER_RAIN_TEMPORARY; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + gWishFutureKnock.weatherDuration = 5; + } + gBattlescriptCurrInstr++; +} + +static void atk7E_setreflect(void) +{ + if (gSideAffecting[GET_BANK_SIDE(gBankAttacker)] & SIDE_STATUS_REFLECT) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + else + { + gSideAffecting[GET_BANK_SIDE(gBankAttacker)] |= SIDE_STATUS_REFLECT; + gSideTimers[GET_BANK_SIDE(gBankAttacker)].reflectTimer = 5; + gSideTimers[GET_BANK_SIDE(gBankAttacker)].reflectBank = gBankAttacker; + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && CountAliveMonsInBattle(BATTLE_ALIVE_ATK_SIDE) == 2) + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + gBattlescriptCurrInstr++; +} + +static void atk7F_setseeded(void) +{ + if (gBattleMoveFlags & MOVESTATUS_NOEFFECT || gStatuses3[gBankTarget] & STATUS3_LEECHSEED) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + else if (gBattleMons[gBankTarget].type1 == TYPE_GRASS || gBattleMons[gBankTarget].type2 == TYPE_GRASS) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + } + else + { + gStatuses3[gBankTarget] |= gBankAttacker; + gStatuses3[gBankTarget] |= STATUS3_LEECHSEED; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + + gBattlescriptCurrInstr++; +} + +static void atk80_manipulatedamage(void) +{ + switch (gBattlescriptCurrInstr[1]) + { + case ATK80_DMG_CHANGE_SIGN: + gBattleMoveDamage *= -1; + break; + case ATK80_DMG_HALF_BY_TWO_NOT_MORE_THAN_HALF_MAX_HP: + gBattleMoveDamage /= 2; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + if ((gBattleMons[gBankTarget].maxHP / 2) < gBattleMoveDamage) + gBattleMoveDamage = gBattleMons[gBankTarget].maxHP / 2; + break; + case ATK80_DMG_DOUBLED: + gBattleMoveDamage *= 2; + break; + } + + gBattlescriptCurrInstr += 2; +} + +static void atk81_setrest(void) +{ + const u8* failJump = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + gActiveBank = gBankTarget = gBankAttacker; + gBattleMoveDamage = gBattleMons[gBankTarget].maxHP * (-1); + + if (gBattleMons[gBankTarget].hp == gBattleMons[gBankTarget].maxHP) + { + gBattlescriptCurrInstr = failJump; + } + else + { + if (gBattleMons[gBankTarget].status1 & ((u8)(~STATUS_SLEEP))) + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + + gBattleMons[gBankTarget].status1 = 3; + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 5; + } +} + +static void atk82_jumpifnotfirstturn(void) +{ + const u8* failJump = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + + if (gDisableStructs[gBankAttacker].isFirstTurn) + gBattlescriptCurrInstr += 5; + else + gBattlescriptCurrInstr = failJump; +} + +static void atk83_nop(void) +{ + gBattlescriptCurrInstr++; +} + +bool8 UproarWakeUpCheck(u8 bank) +{ + s32 i; + + for (i = 0; i < gNoOfAllBanks; i++) + { + if (!(gBattleMons[i].status2 & STATUS2_UPROAR) || gBattleMons[bank].ability == ABILITY_SOUNDPROOF) + continue; + + gBattleScripting.bank = i; + + if (gBankTarget == 0xFF) + gBankTarget = i; + else if (gBankTarget == i) + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + + break; + } + + if (i == gNoOfAllBanks) + return FALSE; + else + return TRUE; +} + +static void atk84_jump_if_cant_sleep(void) +{ + const u8* jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + + if (UproarWakeUpCheck(gBankTarget)) + { + gBattlescriptCurrInstr = jumpPtr; + } + else if (gBattleMons[gBankTarget].ability == ABILITY_INSOMNIA + || gBattleMons[gBankTarget].ability == ABILITY_VITAL_SPIRIT) + { + gLastUsedAbility = gBattleMons[gBankTarget].ability; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + gBattlescriptCurrInstr = jumpPtr; + RecordAbilityBattle(gBankTarget, gLastUsedAbility); + } + else + { + gBattlescriptCurrInstr += 5; + } +} + +static void atk85_stockpile(void) +{ + if (gDisableStructs[gBankAttacker].stockpileCounter == 3) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + else + { + gDisableStructs[gBankAttacker].stockpileCounter++; + + PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff1, 1, gDisableStructs[gBankAttacker].stockpileCounter) + + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + gBattlescriptCurrInstr++; +} + +static void atk86_stockpiletobasedamage(void) +{ + const u8* jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + if (gDisableStructs[gBankAttacker].stockpileCounter == 0) + { + gBattlescriptCurrInstr = jumpPtr; + } + else + { + if (gBattleCommunication[6] != 1) + { + gBattleMoveDamage = CalculateBaseDamage(&gBattleMons[gBankAttacker], &gBattleMons[gBankTarget], gCurrentMove, + gSideAffecting[GET_BANK_SIDE(gBankTarget)], 0, + 0, gBankAttacker, gBankTarget) + * gDisableStructs[gBankAttacker].stockpileCounter; + gBattleScripting.animTurn = gDisableStructs[gBankAttacker].stockpileCounter; + + if (gProtectStructs[gBankAttacker].helpingHand) + gBattleMoveDamage = gBattleMoveDamage * 15 / 10; + } + + gDisableStructs[gBankAttacker].stockpileCounter = 0; + gBattlescriptCurrInstr += 5; + } +} + +static void atk87_stockpiletohpheal(void) +{ + const u8* jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + + if (gDisableStructs[gBankAttacker].stockpileCounter == 0) + { + gBattlescriptCurrInstr = jumpPtr; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + else if (gBattleMons[gBankAttacker].maxHP == gBattleMons[gBankAttacker].hp) + { + gDisableStructs[gBankAttacker].stockpileCounter = 0; + gBattlescriptCurrInstr = jumpPtr; + gBankTarget = gBankAttacker; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + else + { + gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / (1 << (3 - gDisableStructs[gBankAttacker].stockpileCounter)); + + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + gBattleMoveDamage *= -1; + + gBattleScripting.animTurn = gDisableStructs[gBankAttacker].stockpileCounter; + gDisableStructs[gBankAttacker].stockpileCounter = 0; + gBattlescriptCurrInstr += 5; + gBankTarget = gBankAttacker; + } +} + +static void atk88_negativedamage(void) +{ + gBattleMoveDamage = -(gHpDealt / 2); + if (gBattleMoveDamage == 0) + gBattleMoveDamage = -1; + + gBattlescriptCurrInstr++; +} + +static u8 ChangeStatBuffs(s8 statValue, u8 statId, u8 flags, const u8* BS_ptr) +{ + bool8 certain = 0; + bool8 notProtectAffected = FALSE; + u32 index; + + if (flags & MOVE_EFFECT_AFFECTS_USER) + gActiveBank = gBankAttacker; + else + gActiveBank = gBankTarget; + + flags &= ~(MOVE_EFFECT_AFFECTS_USER); + + if (flags & MOVE_EFFECT_CERTAIN) + certain++; + flags &= ~(MOVE_EFFECT_CERTAIN); + + if (flags & STAT_CHANGE_NOT_PROTECT_AFFECTED) + notProtectAffected++; + flags &= ~(STAT_CHANGE_NOT_PROTECT_AFFECTED); + + PREPARE_STAT_BUFFER(gBattleTextBuff1, statId) + + if ((statValue << 0x18) < 0) // stat decrease + { + if (gSideTimers[GET_BANK_SIDE(gActiveBank)].mistTimer + && !certain && gCurrentMove != MOVE_CURSE) + { + if (flags == STAT_CHANGE_BS_PTR) + { + if (gSpecialStatuses[gActiveBank].statLowered) + { + gBattlescriptCurrInstr = BS_ptr; + } + else + { + BattleScriptPush(BS_ptr); + gBattleScripting.bank = gActiveBank; + gBattlescriptCurrInstr = BattleScript_MistProtected; + gSpecialStatuses[gActiveBank].statLowered = 1; + } + } + return STAT_CHANGE_DIDNT_WORK; + } + else if (gCurrentMove != MOVE_CURSE + && notProtectAffected != TRUE && JumpIfMoveAffectedByProtect(0)) + { + gBattlescriptCurrInstr = BattleScript_ButItFailed; + return STAT_CHANGE_DIDNT_WORK; + } + else if ((gBattleMons[gActiveBank].ability == ABILITY_CLEAR_BODY + || gBattleMons[gActiveBank].ability == ABILITY_WHITE_SMOKE) + && !certain && gCurrentMove != MOVE_CURSE) + { + if (flags == STAT_CHANGE_BS_PTR) + { + if (gSpecialStatuses[gActiveBank].statLowered) + { + gBattlescriptCurrInstr = BS_ptr; + } + else + { + BattleScriptPush(BS_ptr); + gBattleScripting.bank = gActiveBank; + gBattlescriptCurrInstr = BattleScript_AbilityNoStatLoss; + gLastUsedAbility = gBattleMons[gActiveBank].ability; + RecordAbilityBattle(gActiveBank, gLastUsedAbility); + gSpecialStatuses[gActiveBank].statLowered = 1; + } + } + return STAT_CHANGE_DIDNT_WORK; + } + else if (gBattleMons[gActiveBank].ability == ABILITY_KEEN_EYE + && !certain && statId == STAT_STAGE_ACC) + { + if (flags == STAT_CHANGE_BS_PTR) + { + BattleScriptPush(BS_ptr); + gBattleScripting.bank = gActiveBank; + gBattlescriptCurrInstr = BattleScript_AbilityNoSpecificStatLoss; + gLastUsedAbility = gBattleMons[gActiveBank].ability; + RecordAbilityBattle(gActiveBank, gLastUsedAbility); + } + return STAT_CHANGE_DIDNT_WORK; + } + else if (gBattleMons[gActiveBank].ability == ABILITY_HYPER_CUTTER + && !certain && statId == STAT_STAGE_ATK) + { + if (flags == STAT_CHANGE_BS_PTR) + { + BattleScriptPush(BS_ptr); + gBattleScripting.bank = gActiveBank; + gBattlescriptCurrInstr = BattleScript_AbilityNoSpecificStatLoss; + gLastUsedAbility = gBattleMons[gActiveBank].ability; + RecordAbilityBattle(gActiveBank, gLastUsedAbility); + } + return STAT_CHANGE_DIDNT_WORK; + } + else if (gBattleMons[gActiveBank].ability == ABILITY_SHIELD_DUST && flags == 0) + { + return STAT_CHANGE_DIDNT_WORK; + } + else // try to decrease + { + statValue = -GET_STAT_BUFF_VALUE(statValue); + gBattleTextBuff2[0] = B_BUFF_PLACEHOLDER_BEGIN; + index = 1; + if (statValue == -2) + { + gBattleTextBuff2[1] = B_BUFF_STRING; + gBattleTextBuff2[2] = 0xD3; // harshly + gBattleTextBuff2[3] = 0xD3 >> 8; + index = 4; + } + gBattleTextBuff2[index] = B_BUFF_STRING; + index++; + gBattleTextBuff2[index] = 0xD4; // fell + index++; + gBattleTextBuff2[index] = 0xD4 >> 8; + index++; + gBattleTextBuff2[index] = B_BUFF_EOS; + + if (gBattleMons[gActiveBank].statStages[statId] == 0) + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + else + gBattleCommunication[MULTISTRING_CHOOSER] = (gBankTarget == gActiveBank); + + } + } + else // stat increase + { + statValue = GET_STAT_BUFF_VALUE(statValue); + gBattleTextBuff2[0] = B_BUFF_PLACEHOLDER_BEGIN; + index = 1; + if (statValue == 2) + { + gBattleTextBuff2[1] = B_BUFF_STRING; + gBattleTextBuff2[2] = 0xD1; // sharply + gBattleTextBuff2[3] = 0xD1 >> 8; + index = 4; + } + gBattleTextBuff2[index] = B_BUFF_STRING; + index++; + gBattleTextBuff2[index] = 0xD2; // rose + index++; + gBattleTextBuff2[index] = 0xD2 >> 8; + index++; + gBattleTextBuff2[index] = B_BUFF_EOS; + + if (gBattleMons[gActiveBank].statStages[statId] == 0xC) + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + else + gBattleCommunication[MULTISTRING_CHOOSER] = (gBankTarget == gActiveBank); + } + + gBattleMons[gActiveBank].statStages[statId] += statValue; + if (gBattleMons[gActiveBank].statStages[statId] < 0) + gBattleMons[gActiveBank].statStages[statId] = 0; + if (gBattleMons[gActiveBank].statStages[statId] > 0xC) + gBattleMons[gActiveBank].statStages[statId] = 0xC; + + if (gBattleCommunication[MULTISTRING_CHOOSER] == 2 && flags & STAT_CHANGE_BS_PTR) + gBattleMoveFlags |= MOVESTATUS_MISSED; + + if (gBattleCommunication[MULTISTRING_CHOOSER] == 2 && !(flags & STAT_CHANGE_BS_PTR)) + return STAT_CHANGE_DIDNT_WORK; + + return STAT_CHANGE_WORKED; +} + +static void atk89_statbuffchange(void) +{ + const u8* jumpPtr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + if (ChangeStatBuffs(gBattleScripting.statChanger & 0xF0, GET_STAT_BUFF_ID(gBattleScripting.statChanger), gBattlescriptCurrInstr[1], jumpPtr) == STAT_CHANGE_WORKED) + gBattlescriptCurrInstr += 6; +} + +static void atk8A_normalisebuffs(void) // haze +{ + s32 i, j; + + for (i = 0; i < gNoOfAllBanks; i++) + { + for (j = 0; j < BATTLE_STATS_NO; j++) + gBattleMons[i].statStages[j] = 6; + } + + gBattlescriptCurrInstr++; +} + +static void atk8B_setbide(void) +{ + gBattleMons[gBankAttacker].status2 |= STATUS2_MULTIPLETURNS; + gLockedMoves[gBankAttacker] = gCurrentMove; + gTakenDmg[gBankAttacker] = 0; + gBattleMons[gBankAttacker].status2 |= (STATUS2_BIDE - 0x100); // 2 turns + + gBattlescriptCurrInstr++; +} + +static void atk8C_confuseifrepeatingattackends(void) +{ + if (!(gBattleMons[gBankAttacker].status2 & STATUS2_LOCK_CONFUSE)) + gBattleCommunication[MOVE_EFFECT_BYTE] = (MOVE_EFFECT_THRASH | MOVE_EFFECT_AFFECTS_USER); + + gBattlescriptCurrInstr++; +} + +static void atk8D_setmultihit_counter(void) +{ + if (gBattlescriptCurrInstr[1]) + { + gMultiHitCounter = gBattlescriptCurrInstr[1]; + } + else + { + gMultiHitCounter = Random() & 3; + if (gMultiHitCounter > 1) + gMultiHitCounter = (Random() & 3) + 2; + else + gMultiHitCounter += 2; + } + + gBattlescriptCurrInstr += 2; +} + +static void atk8E_init_multihit_string(void) +{ + PREPARE_BYTE_NUMBER_BUFFER(gBattleScripting.multihitString, 1, 0) + + gBattlescriptCurrInstr++; +} + +static bool8 sub_8051064(void) +{ + if (gBattleMons[gBankAttacker].level >= gBattleMons[gBankTarget].level) + { + *(gBattleStruct->field_58 + gBankTarget) = gBattlePartyID[gBankTarget]; + } + else + { + u16 random = Random() & 0xFF; + if ((u32)((random * (gBattleMons[gBankAttacker].level + gBattleMons[gBankTarget].level) >> 8) + 1) <= (gBattleMons[gBankTarget].level / 4)) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + return FALSE; + } + *(gBattleStruct->field_58 + gBankTarget) = gBattlePartyID[gBankTarget]; + } + + gBattlescriptCurrInstr = gUnknown_082DADD8; + return TRUE; +} + +static void atk8F_forcerandomswitch(void) +{ + s32 i; + s32 bank1PartyId = 0; + s32 bank2PartyId = 0; + + #ifdef NONMATCHING + s32 lastMonId = 0; // + 1 + #else + register s32 lastMonId asm("r8") = 0; // + 1 + #endif // NONMATCHING + + s32 firstMonId = 0; + s32 monsCount = 0; + struct Pokemon* party = NULL; + s32 validMons = 0; + s32 minNeeded = 0; + + if ((gBattleTypeFlags & BATTLE_TYPE_TRAINER)) + { + if (GetBankSide(gBankTarget) == SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + if ((gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER && gBattleTypeFlags & BATTLE_TYPE_LINK) + || (gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER && gBattleTypeFlags & BATTLE_TYPE_x2000000) + || (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)) + { + if ((gBankTarget & BIT_MON) != 0) + { + firstMonId = 3; + lastMonId = 6; + } + else + { + firstMonId = 0; + lastMonId = 3; + } + monsCount = 3; + minNeeded = 1; + bank2PartyId = gBattlePartyID[gBankTarget]; + bank1PartyId = gBattlePartyID[gBankTarget ^ BIT_MON]; + } + else if ((gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_LINK) + || (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_x2000000)) + { + if (sub_806D82C(sub_806D864(gBankTarget)) == 1) + { + firstMonId = 3; + lastMonId = 6; + } + else + { + firstMonId = 0; + lastMonId = 3; + } + monsCount = 3; + minNeeded = 1; + bank2PartyId = gBattlePartyID[gBankTarget]; + bank1PartyId = gBattlePartyID[gBankTarget ^ BIT_MON]; + } + else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + { + if (GetBankSide(gBankTarget) == SIDE_PLAYER) + { + firstMonId = 0; + lastMonId = 6; + monsCount = 6; + minNeeded = 2; // since there are two opponents, it has to be a double battle + } + else + { + if ((gBankTarget & BIT_MON) != 0) + { + firstMonId = 3; + lastMonId = 6; + } + else + { + firstMonId = 0; + lastMonId = 3; + } + monsCount = 3; + minNeeded = 1; + } + bank2PartyId = gBattlePartyID[gBankTarget]; + bank1PartyId = gBattlePartyID[gBankTarget ^ BIT_MON]; + } + else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + firstMonId = 0; + lastMonId = 6; + monsCount = 6; + minNeeded = 2; + bank2PartyId = gBattlePartyID[gBankTarget]; + bank1PartyId = gBattlePartyID[gBankTarget ^ BIT_MON]; + } + else + { + firstMonId = 0; + lastMonId = 6; + monsCount = 6; + minNeeded = 1; + bank2PartyId = gBattlePartyID[gBankTarget]; // there is only one pokemon out in single battles + bank1PartyId = gBattlePartyID[gBankTarget]; + } + + for (i = firstMonId; i < lastMonId; i++) + { + if (GetMonData(&party[i], MON_DATA_SPECIES) != SPECIES_NONE + && !GetMonData(&party[i], MON_DATA_IS_EGG) + && GetMonData(&party[i], MON_DATA_HP) != 0) + { + validMons++; + } + } + + if (validMons <= minNeeded) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + if (sub_8051064()) + { + do + { + i = Random() % monsCount; + i += firstMonId; + } + while (i == bank2PartyId + || i == bank1PartyId + || GetMonData(&party[i], MON_DATA_SPECIES) == SPECIES_NONE + || GetMonData(&party[i], MON_DATA_IS_EGG) == TRUE + || GetMonData(&party[i], MON_DATA_HP) == 0); + } + *(gBattleStruct->field_5C + gBankTarget) = i; + + if (!sub_81B1250()) + sub_803BDA0(gBankTarget); + + if ((gBattleTypeFlags & BATTLE_TYPE_LINK && gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER) + || (gBattleTypeFlags & BATTLE_TYPE_LINK && gBattleTypeFlags & BATTLE_TYPE_MULTI) + || (gBattleTypeFlags & BATTLE_TYPE_x2000000 && gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER) + || (gBattleTypeFlags & BATTLE_TYPE_x2000000 && gBattleTypeFlags & BATTLE_TYPE_MULTI)) + { + sub_81B8E80(gBankTarget, i, 0); + sub_81B8E80(gBankTarget ^ BIT_MON, i, 1); + } + + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + sub_80571DC(gBankTarget, i); + } + } + else + { + sub_8051064(); + } +} + +static void atk90_conversion_type_change(void) // randomly changes user's type to one of its moves' type +{ + u8 validMoves = 0; + u8 moveChecked; + u8 moveType; + + while (validMoves < 4) + { + if (gBattleMons[gBankAttacker].moves[validMoves] == 0) + break; + + validMoves++; + } + + for (moveChecked = 0; moveChecked < validMoves; moveChecked++) + { + moveType = gBattleMoves[gBattleMons[gBankAttacker].moves[moveChecked]].type; + + if (moveType == TYPE_MYSTERY) + { + if (gBattleMons[gBankAttacker].type1 == TYPE_GHOST || gBattleMons[gBankAttacker].type2 == TYPE_GHOST) + moveType = TYPE_GHOST; + else + moveType = TYPE_NORMAL; + } + if (moveType != gBattleMons[gBankAttacker].type1 + && moveType != gBattleMons[gBankAttacker].type2) + { + break; + } + } + + if (moveChecked == validMoves) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + do + { + + while ((moveChecked = Random() & 3) >= validMoves); + + moveType = gBattleMoves[gBattleMons[gBankAttacker].moves[moveChecked]].type; + + if (moveType == TYPE_MYSTERY) + { + if (gBattleMons[gBankAttacker].type1 == TYPE_GHOST || gBattleMons[gBankAttacker].type2 == TYPE_GHOST) + moveType = TYPE_GHOST; + else + moveType = TYPE_NORMAL; + } + } + while (moveType == gBattleMons[gBankAttacker].type1 || moveType == gBattleMons[gBankAttacker].type2); + + gBattleMons[gBankAttacker].type1 = moveType; + gBattleMons[gBankAttacker].type2 = moveType; + + PREPARE_TYPE_BUFFER(gBattleTextBuff1, moveType) + + gBattlescriptCurrInstr += 5; + } +} + +static void atk91_givepaydaymoney(void) +{ + if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000)) && gPaydayMoney != 0) + { + u32 bonusMoney = gPaydayMoney * gBattleStruct->moneyMultiplier; + AddMoney(&gSaveBlock1Ptr->money, bonusMoney); + + PREPARE_HWORD_NUMBER_BUFFER(gBattleTextBuff1, 5, bonusMoney) + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_PrintPayDayMoneyString; + } + else + { + gBattlescriptCurrInstr++; + } +} + +static void atk92_setlightscreen(void) +{ + if (gSideAffecting[GET_BANK_SIDE(gBankAttacker)] & SIDE_STATUS_LIGHTSCREEN) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + else + { + gSideAffecting[GET_BANK_SIDE(gBankAttacker)] |= SIDE_STATUS_LIGHTSCREEN; + gSideTimers[GET_BANK_SIDE(gBankAttacker)].lightscreenTimer = 5; + gSideTimers[GET_BANK_SIDE(gBankAttacker)].lightscreenBank = gBankAttacker; + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && CountAliveMonsInBattle(BATTLE_ALIVE_ATK_SIDE) == 2) + gBattleCommunication[MULTISTRING_CHOOSER] = 4; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 3; + } + + gBattlescriptCurrInstr++; +} + +static void atk93_ko_move(void) +{ + u8 holdEffect, param; + + if (gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY) + { + holdEffect = gEnigmaBerries[gBankTarget].holdEffect; + param = gEnigmaBerries[gBankTarget].holdEffectParam; + } + else + { + holdEffect = ItemId_GetHoldEffect(gBattleMons[gBankTarget].item); + param = ItemId_GetHoldEffectParam(gBattleMons[gBankTarget].item); + } + + gStringBank = gBankTarget; + + if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < param) + { + RecordItemEffectBattle(gBankTarget, HOLD_EFFECT_FOCUS_BAND); + gSpecialStatuses[gBankTarget].focusBanded = 1; + } + + if (gBattleMons[gBankTarget].ability == ABILITY_STURDY) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gLastUsedAbility = ABILITY_STURDY; + gBattlescriptCurrInstr = BattleScript_SturdyPreventsOHKO; + RecordAbilityBattle(gBankTarget, ABILITY_STURDY); + } + else + { + u16 chance; + if (!(gStatuses3[gBankTarget] & STATUS3_ALWAYS_HITS)) + { + chance = gBattleMoves[gCurrentMove].accuracy + (gBattleMons[gBankAttacker].level - gBattleMons[gBankTarget].level); + if (Random() % 100 + 1 < chance && gBattleMons[gBankAttacker].level >= gBattleMons[gBankTarget].level) + chance = TRUE; + else + chance = FALSE; + } + else if (gDisableStructs[gBankTarget].bankWithSureHit == gBankAttacker + && gBattleMons[gBankAttacker].level >= gBattleMons[gBankTarget].level) + { + chance = TRUE; + } + else + { + chance = gBattleMoves[gCurrentMove].accuracy + (gBattleMons[gBankAttacker].level - gBattleMons[gBankTarget].level); + if (Random() % 100 + 1 < chance && gBattleMons[gBankAttacker].level >= gBattleMons[gBankTarget].level) + chance = TRUE; + else + chance = FALSE; + } + if (chance) + { + if (gProtectStructs[gBankTarget].endured) + { + gBattleMoveDamage = gBattleMons[gBankTarget].hp - 1; + gBattleMoveFlags |= MOVESTATUS_ENDURED; + } + else if (gSpecialStatuses[gBankTarget].focusBanded) + { + gBattleMoveDamage = gBattleMons[gBankTarget].hp - 1; + gBattleMoveFlags |= MOVESTATUS_HUNGON; + gLastUsedItem = gBattleMons[gBankTarget].item; + } + else + { + gBattleMoveDamage = gBattleMons[gBankTarget].hp; + gBattleMoveFlags |= MOVESTATUS_ONEHITKO; + } + gBattlescriptCurrInstr += 5; + } + else + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + if (gBattleMons[gBankAttacker].level >= gBattleMons[gBankTarget].level) + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + } +} + +static void atk94_damagetohalftargethp(void) // super fang +{ + gBattleMoveDamage = gBattleMons[gBankTarget].hp / 2; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + + gBattlescriptCurrInstr++; +} + +static void atk95_setsandstorm(void) +{ + if (gBattleWeather & WEATHER_SANDSTORM_ANY) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + } + else + { + gBattleWeather = WEATHER_SANDSTORM_TEMPORARY; + gBattleCommunication[MULTISTRING_CHOOSER] = 3; + gWishFutureKnock.weatherDuration = 5; + } + gBattlescriptCurrInstr++; +} + +static void atk96_weatherdamage(void) +{ + if (WEATHER_HAS_EFFECT) + { + if (gBattleWeather & WEATHER_SANDSTORM_ANY) + { + if (gBattleMons[gBankAttacker].type1 != TYPE_ROCK + && gBattleMons[gBankAttacker].type1 != TYPE_STEEL + && gBattleMons[gBankAttacker].type1 != TYPE_GROUND + && gBattleMons[gBankAttacker].type2 != TYPE_ROCK + && gBattleMons[gBankAttacker].type2 != TYPE_STEEL + && gBattleMons[gBankAttacker].type2 != TYPE_GROUND + && gBattleMons[gBankAttacker].ability != ABILITY_SAND_VEIL + && !(gStatuses3[gBankAttacker] & STATUS3_UNDERGROUND) + && !(gStatuses3[gBankAttacker] & STATUS3_UNDERWATER)) + { + gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 16; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + } + else + { + gBattleMoveDamage = 0; + } + } + if (gBattleWeather & WEATHER_HAIL) + { + if (gBattleMons[gBankAttacker].type1 != TYPE_ICE + && gBattleMons[gBankAttacker].type2 != TYPE_ICE + && !(gStatuses3[gBankAttacker] & STATUS3_UNDERGROUND) + && !(gStatuses3[gBankAttacker] & STATUS3_UNDERWATER)) + { + gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 16; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + } + else + { + gBattleMoveDamage = 0; + } + } + } + else + { + gBattleMoveDamage = 0; + } + + if (gAbsentBankFlags & gBitTable[gBankAttacker]) + gBattleMoveDamage = 0; + + gBattlescriptCurrInstr++; +} + +static void atk97_try_infatuation(void) +{ + struct Pokemon *monAttacker, *monTarget; + u16 speciesAttacker, speciesTarget; + u32 personalityAttacker, personalityTarget; + + if (GetBankSide(gBankAttacker) == SIDE_PLAYER) + monAttacker = &gPlayerParty[gBattlePartyID[gBankAttacker]]; + else + monAttacker = &gEnemyParty[gBattlePartyID[gBankAttacker]]; + + if (GetBankSide(gBankTarget) == SIDE_PLAYER) + monTarget = &gPlayerParty[gBattlePartyID[gBankTarget]]; + else + monTarget = &gEnemyParty[gBattlePartyID[gBankTarget]]; + + speciesAttacker = GetMonData(monAttacker, MON_DATA_SPECIES); + personalityAttacker = GetMonData(monAttacker, MON_DATA_PERSONALITY); + + speciesTarget = GetMonData(monTarget, MON_DATA_SPECIES); + personalityTarget = GetMonData(monTarget, MON_DATA_PERSONALITY); + + if (gBattleMons[gBankTarget].ability == ABILITY_OBLIVIOUS) + { + gBattlescriptCurrInstr = BattleScript_ObliviousPreventsAttraction; + gLastUsedAbility = ABILITY_OBLIVIOUS; + RecordAbilityBattle(gBankTarget, ABILITY_OBLIVIOUS); + } + else + { + if (GetGenderFromSpeciesAndPersonality(speciesAttacker, personalityAttacker) == GetGenderFromSpeciesAndPersonality(speciesTarget, personalityTarget) + || gBattleMons[gBankTarget].status2 & STATUS2_INFATUATION + || GetGenderFromSpeciesAndPersonality(speciesAttacker, personalityAttacker) == MON_GENDERLESS + || GetGenderFromSpeciesAndPersonality(speciesTarget, personalityTarget) == MON_GENDERLESS) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gBattleMons[gBankTarget].status2 |= STATUS2_INFATUATED_WITH(gBankAttacker); + gBattlescriptCurrInstr += 5; + } + } +} + +static void atk98_status_icon_update(void) +{ + if (gBattleExecBuffer) + return; + + if (gBattlescriptCurrInstr[1] != BS_ATTACKER_WITH_PARTNER) + { + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + EmitStatusIconUpdate(0, gBattleMons[gActiveBank].status1, gBattleMons[gActiveBank].status2); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 2; + } + else + { + gActiveBank = gBankAttacker; + if (!(gAbsentBankFlags & gBitTable[gActiveBank])) + { + EmitStatusIconUpdate(0, gBattleMons[gActiveBank].status1, gBattleMons[gActiveBank].status2); + MarkBufferBankForExecution(gActiveBank); + } + if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + { + gActiveBank = GetBankByIdentity(GetBankIdentity(gBankAttacker) ^ BIT_MON); + if (!(gAbsentBankFlags & gBitTable[gActiveBank])) + { + EmitStatusIconUpdate(0, gBattleMons[gActiveBank].status1, gBattleMons[gActiveBank].status2); + MarkBufferBankForExecution(gActiveBank); + } + } + gBattlescriptCurrInstr += 2; + } +} + +static void atk99_setmist(void) +{ + if (gSideTimers[GET_BANK_SIDE(gBankAttacker)].mistTimer) + { + gBattleMoveFlags |= MOVESTATUS_FAILED; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + else + { + gSideTimers[GET_BANK_SIDE(gBankAttacker)].mistTimer = 5; + gSideTimers[GET_BANK_SIDE(gBankAttacker)].mistBank = gBankAttacker; + gSideAffecting[GET_BANK_SIDE(gBankAttacker)] |= SIDE_STATUS_MIST; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + gBattlescriptCurrInstr++; +} + +static void atk9A_set_focusenergy(void) +{ + if (gBattleMons[gBankAttacker].status2 & STATUS2_FOCUS_ENERGY) + { + gBattleMoveFlags |= MOVESTATUS_FAILED; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + else + { + gBattleMons[gBankAttacker].status2 |= STATUS2_FOCUS_ENERGY; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + gBattlescriptCurrInstr++; +} + +static void atk9B_transformdataexecution(void) +{ + gLastUsedMove = 0xFFFF; + gBattlescriptCurrInstr++; + if (gBattleMons[gBankTarget].status2 & STATUS2_TRANSFORMED + || gStatuses3[gBankTarget] & STATUS3_SEMI_INVULNERABLE) + { + gBattleMoveFlags |= MOVESTATUS_FAILED; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + else + { + s32 i; + u8 *battleMonAttacker, *battleMonTarget; + + gBattleMons[gBankAttacker].status2 |= STATUS2_TRANSFORMED; + gDisableStructs[gBankAttacker].disabledMove = 0; + gDisableStructs[gBankAttacker].disableTimer1 = 0; + gDisableStructs[gBankAttacker].unk0 = gBattleMons[gBankTarget].personality; + gDisableStructs[gBankAttacker].unk18_b = 0; + + PREPARE_SPECIES_BUFFER(gBattleTextBuff1, gBattleMons[gBankTarget].species) + + battleMonAttacker = (u8*)(&gBattleMons[gBankAttacker]); + battleMonTarget = (u8*)(&gBattleMons[gBankTarget]); + + for (i = 0; i < offsetof(struct BattlePokemon, pp); i++) + battleMonAttacker[i] = battleMonTarget[i]; + + for (i = 0; i < 4; i++) + { + if (gBattleMoves[gBattleMons[gBankAttacker].moves[i]].pp < 5) + gBattleMons[gBankAttacker].pp[i] = gBattleMoves[gBattleMons[gBankAttacker].moves[i]].pp; + else + gBattleMons[gBankAttacker].pp[i] = 5; + } + + gActiveBank = gBankAttacker; + EmitResetActionMoveSelection(0, RESET_MOVE_SELECTION); + MarkBufferBankForExecution(gActiveBank); + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } +} + +static void atk9C_set_substitute(void) +{ + u32 hp = gBattleMons[gBankAttacker].maxHP / 4; + if (gBattleMons[gBankAttacker].maxHP / 4 == 0) + hp = 1; + + if (gBattleMons[gBankAttacker].hp <= hp) + { + gBattleMoveDamage = 0; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + else + { + gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 4; // one bit value will only work for pokemon which max hp can go to 1020(which is more than possible in games) + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + + gBattleMons[gBankAttacker].status2 |= STATUS2_SUBSTITUTE; + gBattleMons[gBankAttacker].status2 &= ~(STATUS2_WRAPPED); + gDisableStructs[gBankAttacker].substituteHP = gBattleMoveDamage; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + gHitMarker |= HITMARKER_IGNORE_SUBSTITUTE; + } + + gBattlescriptCurrInstr++; +} + +static bool8 IsMoveUncopyableByMimic(u16 move) +{ + s32 i; + for (i = 0; sMovesForbiddenToCopy[i] != MIMIC_FORBIDDEN_END + && sMovesForbiddenToCopy[i] != move; i++); + + return (sMovesForbiddenToCopy[i] != MIMIC_FORBIDDEN_END); +} + +static void atk9D_mimicattackcopy(void) +{ + gLastUsedMove = 0xFFFF; + + if (IsMoveUncopyableByMimic(gLastUsedMovesByBanks[gBankTarget]) + || gBattleMons[gBankAttacker].status2 & STATUS2_TRANSFORMED + || gLastUsedMovesByBanks[gBankTarget] == 0 + || gLastUsedMovesByBanks[gBankTarget] == 0xFFFF) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + s32 i; + + for (i = 0; i < 4; i++) + { + if (gBattleMons[gBankAttacker].moves[i] == gLastUsedMovesByBanks[gBankTarget]) + break; + } + + if (i == 4) + { + gBattleMons[gBankAttacker].moves[gCurrMovePos] = gLastUsedMovesByBanks[gBankTarget]; + if (gBattleMoves[gLastUsedMovesByBanks[gBankTarget]].pp < 5) + gBattleMons[gBankAttacker].pp[gCurrMovePos] = gBattleMoves[gLastUsedMovesByBanks[gBankTarget]].pp; + else + gBattleMons[gBankAttacker].pp[gCurrMovePos] = 5; + + + PREPARE_MOVE_BUFFER(gBattleTextBuff1, gLastUsedMovesByBanks[gBankTarget]) + + gDisableStructs[gBankAttacker].unk18_b |= gBitTable[gCurrMovePos]; + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + } +} + +#ifdef NONMATCHING +static void atk9E_metronome(void) +{ + while (1) + { + const u16 *move; + s32 i, j; + + gCurrentMove = (Random() & 0x1FF) + 1; + if (gCurrentMove > LAST_MOVE_INDEX) + continue; + + for (i = 0; i < 4; i++); // ? + + for (move = sMovesForbiddenToCopy; ; move++) + { + if (*move == gCurrentMove) + break; + if (*move == METRONOME_FORBIDDEN_END) + break; + } + + if (*move == METRONOME_FORBIDDEN_END) + break; + } + + gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); + gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]; + gBankTarget = GetMoveTarget(gCurrentMove, 0); +} + +#else +__attribute__((naked)) +static void atk9E_metronome(void) +{ + asm( + "\n\ + .syntax unified\n\ + push {r4-r7,lr}\n\ + mov r7, r8\n\ + push {r7}\n\ + ldr r7, =gCurrentMove\n\ + movs r6, 0xB1\n\ + lsls r6, 1\n\ + ldr r5, =sMovesForbiddenToCopy\n\ + ldr r0, =gBattlescriptCurrInstr\n\ + mov r8, r0\n\ +_080524EE:\n\ + bl Random\n\ + ldr r2, =0x000001ff\n\ + adds r1, r2, 0\n\ + ands r0, r1\n\ + adds r0, 0x1\n\ + strh r0, [r7]\n\ + cmp r0, r6\n\ + bhi _080524EE\n\ + movs r0, 0x3\n\ +_08052502:\n\ + subs r0, 0x1\n\ + cmp r0, 0\n\ + bge _08052502\n\ + ldr r4, =gCurrentMove\n\ + ldrh r2, [r4]\n\ + ldr r3, =0x0000ffff\n\ + subs r0, r5, 0x2\n\ +_08052510:\n\ + adds r0, 0x2\n\ + ldrh r1, [r0]\n\ + cmp r1, r2\n\ + beq _0805251C\n\ + cmp r1, r3\n\ + bne _08052510\n\ +_0805251C:\n\ + ldr r0, =0x0000ffff\n\ + cmp r1, r0\n\ + bne _080524EE\n\ + ldr r2, =gHitMarker\n\ + ldr r0, [r2]\n\ + ldr r1, =0xfffffbff\n\ + ands r0, r1\n\ + str r0, [r2]\n\ + ldr r3, =gBattleScriptsForMoveEffects\n\ + ldr r2, =gBattleMoves\n\ + ldrh r1, [r4]\n\ + lsls r0, r1, 1\n\ + adds r0, r1\n\ + lsls r0, 2\n\ + adds r0, r2\n\ + ldrb r0, [r0]\n\ + lsls r0, 2\n\ + adds r0, r3\n\ + ldr r0, [r0]\n\ + mov r1, r8\n\ + str r0, [r1]\n\ + ldrh r0, [r4]\n\ + movs r1, 0\n\ + bl GetMoveTarget\n\ + ldr r1, =gBankTarget\n\ + strb r0, [r1]\n\ + pop {r3}\n\ + mov r8, r3\n\ + pop {r4-r7}\n\ + pop {r0}\n\ + bx r0\n\ + .pool\n\ + .syntax divided"); +} + +#endif // NONMATCHING + +static void atk9F_dmgtolevel(void) +{ + gBattleMoveDamage = gBattleMons[gBankAttacker].level; + gBattlescriptCurrInstr++; +} + +static void atkA0_psywavedamageeffect(void) +{ + s32 randDamage; + + while ((randDamage = (Random() & 0xF)) > 10); + + randDamage *= 10; + gBattleMoveDamage = gBattleMons[gBankAttacker].level * (randDamage + 50) / 100; + gBattlescriptCurrInstr++; +} + +static void atkA1_counterdamagecalculator(void) +{ + u8 sideAttacker = GetBankSide(gBankAttacker); + u8 sideTarget = GetBankSide(gProtectStructs[gBankAttacker].physicalBank); + + if (gProtectStructs[gBankAttacker].physicalDmg + && sideAttacker != sideTarget + && gBattleMons[gProtectStructs[gBankAttacker].physicalBank].hp) + { + gBattleMoveDamage = gProtectStructs[gBankAttacker].physicalDmg * 2; + + if (gSideTimers[sideTarget].followmeTimer && gBattleMons[gSideTimers[sideTarget].followmeTarget].hp) + gBankTarget = gSideTimers[sideTarget].followmeTarget; + else + gBankTarget = gProtectStructs[gBankAttacker].physicalBank; + + gBattlescriptCurrInstr += 5; + } + else + { + gSpecialStatuses[gBankAttacker].flag20 = 1; + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkA2_mirrorcoatdamagecalculator(void) // a copy of atkA1 with the physical -> special field changes +{ + u8 sideAttacker = GetBankSide(gBankAttacker); + u8 sideTarget = GetBankSide(gProtectStructs[gBankAttacker].specialBank); + + if (gProtectStructs[gBankAttacker].specialDmg && sideAttacker != sideTarget && gBattleMons[gProtectStructs[gBankAttacker].specialBank].hp) + { + gBattleMoveDamage = gProtectStructs[gBankAttacker].specialDmg * 2; + + if (gSideTimers[sideTarget].followmeTimer && gBattleMons[gSideTimers[sideTarget].followmeTarget].hp) + gBankTarget = gSideTimers[sideTarget].followmeTarget; + else + gBankTarget = gProtectStructs[gBankAttacker].specialBank; + + gBattlescriptCurrInstr += 5; + } + else + { + gSpecialStatuses[gBankAttacker].flag20 = 1; + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkA3_disablelastusedattack(void) +{ + s32 i; + + for (i = 0; i < 4; i++) + { + if (gBattleMons[gBankTarget].moves[i] == gLastUsedMovesByBanks[gBankTarget]) + break; + } + if (gDisableStructs[gBankTarget].disabledMove == 0 + && i != 4 && gBattleMons[gBankTarget].pp[i] != 0) + { + PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleMons[gBankTarget].moves[i]) + + gDisableStructs[gBankTarget].disabledMove = gBattleMons[gBankTarget].moves[i]; + gDisableStructs[gBankTarget].disableTimer1 = (Random() & 3) + 2; + gDisableStructs[gBankTarget].disableTimer2 = gDisableStructs[gBankTarget].disableTimer1; // used to save the random amount of turns? + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkA4_setencore(void) +{ + s32 i; + + for (i = 0; i < 4; i++) + { + if (gBattleMons[gBankTarget].moves[i] == gLastUsedMovesByBanks[gBankTarget]) + break; + } + + if (gLastUsedMovesByBanks[gBankTarget] == MOVE_STRUGGLE + || gLastUsedMovesByBanks[gBankTarget] == MOVE_ENCORE + || gLastUsedMovesByBanks[gBankTarget] == MOVE_MIRROR_MOVE) + { + i = 4; + } + + if (gDisableStructs[gBankTarget].encoredMove == 0 + && i != 4 && gBattleMons[gBankTarget].pp[i] != 0) + { + gDisableStructs[gBankTarget].encoredMove = gBattleMons[gBankTarget].moves[i]; + gDisableStructs[gBankTarget].encoredMovePos = i; + gDisableStructs[gBankTarget].encoreTimer1 = (Random() & 3) + 3; + gDisableStructs[gBankTarget].encoreTimer2 = gDisableStructs[gBankTarget].encoreTimer1; + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkA5_painsplitdmgcalc(void) +{ + if (!(gBattleMons[gBankTarget].status2 & STATUS2_SUBSTITUTE)) + { + s32 hpDiff = (gBattleMons[gBankAttacker].hp + gBattleMons[gBankTarget].hp) / 2; + s32 painSplitHp = gBattleMoveDamage = gBattleMons[gBankTarget].hp - hpDiff; + u8* storeLoc = (void*)(&gBattleScripting.painSplitHp); + + storeLoc[0] = (painSplitHp); + storeLoc[1] = (painSplitHp & 0x0000FF00) >> 8; + storeLoc[2] = (painSplitHp & 0x00FF0000) >> 16; + storeLoc[3] = (painSplitHp & 0xFF000000) >> 24; + + gBattleMoveDamage = gBattleMons[gBankAttacker].hp - hpDiff; + gSpecialStatuses[gBankTarget].moveturnLostHP = 0xFFFF; + + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +#ifdef NONMATCHING +static void atkA6_settypetorandomresistance(void) // conversion 2 +{ + if (gUnknown_02024250[gBankAttacker] == 0 + || gUnknown_02024250[gBankAttacker] == 0xFFFF) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else if (IsTwoTurnsMove(gUnknown_02024250[gBankAttacker]) + && gBattleMons[gUnknown_02024270[gBankAttacker]].status2 & STATUS2_MULTIPLETURNS) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + s32 type = 0, rands = 0; + do + { + while (((type = (Random() & 0x7F)) > 0x70)); + + type *= 3; + + if (gTypeEffectiveness[type] == gUnknown_02024258[gBankAttacker] + && gTypeEffectiveness[type + 2] <= 5 + && gBattleMons[gBankAttacker].type1 != gTypeEffectiveness[type + 1] + && gBattleMons[gBankAttacker].type2 != gTypeEffectiveness[type + 1]) + { + gBattleMons[gBankAttacker].type1 = type; + gBattleMons[gBankAttacker].type2 = type; + + PREPARE_TYPE_BUFFER(gBattleTextBuff1, type) + + gBattlescriptCurrInstr += 5; + return; + } + + rands++; + } while (rands <= 999); + + type = 0, rands = 0; + do + { + s8 var = (s8)(gTypeEffectiveness[type]); + if (var > -1 || var < -2) + { + if (gTypeEffectiveness[type] == gUnknown_02024258[gBankAttacker] + && gTypeEffectiveness[type + 2] <= 5 + && gBattleMons[gBankAttacker].type1 != gTypeEffectiveness[type + 1] + && gBattleMons[gBankAttacker].type2 != gTypeEffectiveness[type + 1]) + { + gBattleMons[gBankAttacker].type1 = gTypeEffectiveness[rands + 1]; + gBattleMons[gBankAttacker].type2 = gTypeEffectiveness[rands + 1]; + + PREPARE_TYPE_BUFFER(gBattleTextBuff1, gTypeEffectiveness[rands + 1]) + + gBattlescriptCurrInstr += 5; + return; + } + } + type += 3, rands += 3; + } while (rands < 336); + + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +#else +__attribute__((naked)) +static void atkA6_settypetorandomresistance(void) // conversion 2 +{ + asm(".syntax unified\n\ + push {r4-r7,lr}\n\ + mov r7, r10\n\ + mov r6, r9\n\ + mov r5, r8\n\ + push {r5-r7}\n\ + ldr r1, =gUnknown_02024250\n\ + ldr r4, =gBankAttacker\n\ + ldrb r0, [r4]\n\ + lsls r0, 1\n\ + adds r2, r0, r1\n\ + ldrh r1, [r2]\n\ + cmp r1, 0\n\ + beq _08052B7E\n\ + ldr r0, =0x0000ffff\n\ + cmp r1, r0\n\ + beq _08052B7E\n\ + ldrh r0, [r2]\n\ + bl IsTwoTurnsMove\n\ + lsls r0, 24\n\ + cmp r0, 0\n\ + beq _08052C1C\n\ + ldr r1, =gBattleMons\n\ + ldr r2, =gUnknown_02024270\n\ + ldrb r0, [r4]\n\ + adds r0, r2\n\ + ldrb r2, [r0]\n\ + movs r0, 0x58\n\ + muls r0, r2\n\ + adds r1, 0x50\n\ + adds r0, r1\n\ + ldr r0, [r0]\n\ + movs r1, 0x80\n\ + lsls r1, 5\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _08052C1C\n\ +_08052B7E:\n\ + ldr r3, =gBattlescriptCurrInstr\n\ + ldr r2, [r3]\n\ + ldrb r1, [r2, 0x1]\n\ + ldrb r0, [r2, 0x2]\n\ + lsls r0, 8\n\ + orrs r1, r0\n\ + ldrb r0, [r2, 0x3]\n\ + lsls r0, 16\n\ + orrs r1, r0\n\ + ldrb r0, [r2, 0x4]\n\ + lsls r0, 24\n\ + orrs r1, r0\n\ + str r1, [r3]\n\ + b _08052D08\n\ + .pool\n\ +_08052BB4:\n\ + mov r0, r12\n\ + strb r5, [r0]\n\ + mov r1, r10\n\ + ldrb r0, [r1]\n\ + muls r0, r2\n\ + adds r0, r7\n\ + adds r0, 0x22\n\ + strb r5, [r0]\n\ + ldr r1, =gBattleTextBuff1\n\ + movs r0, 0xFD\n\ + strb r0, [r1]\n\ + movs r0, 0x3\n\ + strb r0, [r1, 0x1]\n\ + strb r5, [r1, 0x2]\n\ + movs r0, 0xFF\n\ + strb r0, [r1, 0x3]\n\ + ldr r1, =gBattlescriptCurrInstr\n\ + b _08052C0A\n\ + .pool\n\ +_08052BE0:\n\ + mov r0, r8\n\ + adds r0, 0x1\n\ + adds r0, r3\n\ + ldrb r2, [r0]\n\ + strb r2, [r4]\n\ + mov r4, r10\n\ + ldrb r0, [r4]\n\ + muls r0, r6\n\ + ldr r7, =gBattleMons\n\ + adds r0, r7\n\ + adds r0, 0x22\n\ + strb r2, [r0]\n\ + ldr r1, =gBattleTextBuff1\n\ + movs r0, 0xFD\n\ + strb r0, [r1]\n\ + movs r0, 0x3\n\ + strb r0, [r1, 0x1]\n\ + strb r2, [r1, 0x2]\n\ + movs r0, 0xFF\n\ + strb r0, [r1, 0x3]\n\ + mov r1, r12\n\ +_08052C0A:\n\ + ldr r0, [r1]\n\ + adds r0, 0x5\n\ + str r0, [r1]\n\ + b _08052D08\n\ + .pool\n\ +_08052C1C:\n\ + movs r4, 0\n\ + mov r8, r4\n\ + movs r7, 0x7F\n\ + mov r9, r7\n\ +_08052C24:\n\ + bl Random\n\ + mov r4, r9\n\ + ands r4, r0\n\ + cmp r4, 0x70\n\ + bhi _08052C24\n\ + lsls r0, r4, 1\n\ + adds r4, r0, r4\n\ + ldr r6, =gTypeEffectiveness\n\ + adds r3, r4, r6\n\ + ldr r1, =gUnknown_02024258\n\ + ldr r2, =gBankAttacker\n\ + ldrb r5, [r2]\n\ + lsls r0, r5, 1\n\ + adds r0, r1\n\ + ldrb r1, [r3]\n\ + mov r10, r2\n\ + ldrh r0, [r0]\n\ + cmp r1, r0\n\ + bne _08052C80\n\ + adds r0, r4, 0x2\n\ + adds r0, r6\n\ + ldrb r0, [r0]\n\ + cmp r0, 0x5\n\ + bhi _08052C80\n\ + ldr r7, =gBattleMons\n\ + movs r2, 0x58\n\ + adds r0, r5, 0\n\ + muls r0, r2\n\ + adds r3, r0, r7\n\ + movs r0, 0x21\n\ + adds r0, r3\n\ + mov r12, r0\n\ + adds r0, r4, 0x1\n\ + adds r0, r6\n\ + ldrb r5, [r0]\n\ + mov r1, r12\n\ + ldrb r0, [r1]\n\ + adds r1, r5, 0\n\ + cmp r0, r1\n\ + beq _08052C80\n\ + adds r0, r3, 0\n\ + adds r0, 0x22\n\ + ldrb r0, [r0]\n\ + cmp r0, r1\n\ + bne _08052BB4\n\ +_08052C80:\n\ + movs r7, 0x1\n\ + add r8, r7\n\ + ldr r0, =0x000003e7\n\ + cmp r8, r0\n\ + ble _08052C24\n\ + movs r0, 0\n\ + mov r8, r0\n\ + ldr r1, =gBattlescriptCurrInstr\n\ + mov r12, r1\n\ + ldr r3, =gTypeEffectiveness\n\ + adds r0, r4, 0x1\n\ + adds r0, r3\n\ + mov r9, r0\n\ + adds r5, r3, 0\n\ +_08052C9C:\n\ + ldrb r1, [r5]\n\ + cmp r1, 0xFF\n\ + bgt _08052CA6\n\ + cmp r1, 0xFE\n\ + bge _08052CE0\n\ +_08052CA6:\n\ + mov r4, r10\n\ + ldrb r2, [r4]\n\ + lsls r0, r2, 1\n\ + ldr r7, =gUnknown_02024258\n\ + adds r0, r7\n\ + ldrh r0, [r0]\n\ + cmp r1, r0\n\ + bne _08052CE0\n\ + ldrb r0, [r5, 0x2]\n\ + cmp r0, 0x5\n\ + bhi _08052CE0\n\ + movs r6, 0x58\n\ + adds r0, r2, 0\n\ + muls r0, r6\n\ + ldr r1, =gBattleMons\n\ + adds r2, r0, r1\n\ + adds r4, r2, 0\n\ + adds r4, 0x21\n\ + ldrb r0, [r4]\n\ + mov r7, r9\n\ + ldrb r1, [r7]\n\ + cmp r0, r1\n\ + beq _08052CE0\n\ + adds r0, r2, 0\n\ + adds r0, 0x22\n\ + ldrb r0, [r0]\n\ + cmp r0, r1\n\ + beq _08052CE0\n\ + b _08052BE0\n\ +_08052CE0:\n\ + adds r5, 0x3\n\ + movs r0, 0x3\n\ + add r8, r0\n\ + ldr r0, =0x0000014f\n\ + cmp r8, r0\n\ + bls _08052C9C\n\ + mov r1, r12\n\ + ldr r2, [r1]\n\ + ldrb r1, [r2, 0x1]\n\ + ldrb r0, [r2, 0x2]\n\ + lsls r0, 8\n\ + orrs r1, r0\n\ + ldrb r0, [r2, 0x3]\n\ + lsls r0, 16\n\ + orrs r1, r0\n\ + ldrb r0, [r2, 0x4]\n\ + lsls r0, 24\n\ + orrs r1, r0\n\ + mov r4, r12\n\ + str r1, [r4]\n\ +_08052D08:\n\ + pop {r3-r5}\n\ + mov r8, r3\n\ + mov r9, r4\n\ + mov r10, r5\n\ + pop {r4-r7}\n\ + pop {r0}\n\ + bx r0\n\ + .pool\n\ + .syntax divided"); +} +#endif // NONMATCHING + +static void atkA7_setalwayshitflag(void) +{ + gStatuses3[gBankTarget] &= ~(STATUS3_ALWAYS_HITS); + gStatuses3[gBankTarget] |= 0x10; + gDisableStructs[gBankTarget].bankWithSureHit = gBankAttacker; + gBattlescriptCurrInstr++; +} + +static void atkA8_copymovepermanently(void) // sketch +{ + gLastUsedMove = 0xFFFF; + + if (!(gBattleMons[gBankAttacker].status2 & STATUS2_TRANSFORMED) + && gUnknownMovesUsedByBanks[gBankTarget] != MOVE_STRUGGLE + && gUnknownMovesUsedByBanks[gBankTarget] != 0 + && gUnknownMovesUsedByBanks[gBankTarget] != 0xFFFF + && gUnknownMovesUsedByBanks[gBankTarget] != MOVE_SKETCH) + { + s32 i; + + for (i = 0; i < 4; i++) + { + if (gBattleMons[gBankAttacker].moves[i] == MOVE_SKETCH) + continue; + if (gBattleMons[gBankAttacker].moves[i] == gUnknownMovesUsedByBanks[gBankTarget]) + break; + } + + if (i != 4) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else // sketch worked + { + struct MovePpInfo movePpData; + + gBattleMons[gBankAttacker].moves[gCurrMovePos] = gUnknownMovesUsedByBanks[gBankTarget]; + gBattleMons[gBankAttacker].pp[gCurrMovePos] = gBattleMoves[gUnknownMovesUsedByBanks[gBankTarget]].pp; + gActiveBank = gBankAttacker; + + for (i = 0; i < 4; i++) + { + movePpData.move[i] = gBattleMons[gBankAttacker].moves[i]; + movePpData.pp[i] = gBattleMons[gBankAttacker].pp[i]; + } + movePpData.ppBonuses = gBattleMons[gBankAttacker].ppBonuses; + + EmitSetMonData(0, REQUEST_MOVES_PP_BATTLE, 0, sizeof(struct MovePpInfo), &movePpData); + MarkBufferBankForExecution(gActiveBank); + + PREPARE_MOVE_BUFFER(gBattleTextBuff1, gUnknownMovesUsedByBanks[gBankTarget]) + + gBattlescriptCurrInstr += 5; + } + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static bool8 IsTwoTurnsMove(u16 move) +{ + if (gBattleMoves[move].effect == EFFECT_SKULL_BASH + || gBattleMoves[move].effect == EFFECT_RAZOR_WIND + || gBattleMoves[move].effect == EFFECT_SKY_ATTACK + || gBattleMoves[move].effect == EFFECT_SOLARBEAM + || gBattleMoves[move].effect == EFFECT_FLY + || gBattleMoves[move].effect == EFFECT_BIDE) + return TRUE; + else + return FALSE; +} + +static bool8 IsInvalidForSleepTalkOrAssist(u16 move) +{ + if (move == 0 || move == MOVE_SLEEP_TALK || move == MOVE_ASSIST + || move == MOVE_MIRROR_MOVE || move == MOVE_METRONOME) + return TRUE; + else + return FALSE; +} + +static u8 AttacksThisTurn(u8 bank, u16 move) // Note: returns 1 if it's a charging turn, otherwise 2 +{ + // first argument is unused + if (gBattleMoves[move].effect == EFFECT_SOLARBEAM + && (gBattleWeather & WEATHER_SUN_ANY)) + return 2; + + if (gBattleMoves[move].effect == EFFECT_SKULL_BASH + || gBattleMoves[move].effect == EFFECT_RAZOR_WIND + || gBattleMoves[move].effect == EFFECT_SKY_ATTACK + || gBattleMoves[move].effect == EFFECT_SOLARBEAM + || gBattleMoves[move].effect == EFFECT_FLY + || gBattleMoves[move].effect == EFFECT_BIDE) + { + if ((gHitMarker & HITMARKER_x8000000)) + return 1; + } + return 2; +} + +static void atkA9_sleeptalk_choose_move(void) +{ + s32 i; + u8 unusableMovesBits = 0; + + for (i = 0; i < 4; i++) + { + if (IsInvalidForSleepTalkOrAssist(gBattleMons[gBankAttacker].moves[i]) + || gBattleMons[gBankAttacker].moves[i] == MOVE_FOCUS_PUNCH + || gBattleMons[gBankAttacker].moves[i] == MOVE_UPROAR + || IsTwoTurnsMove(gBattleMons[gBankAttacker].moves[i])) + { + unusableMovesBits |= gBitTable[i]; + } + + } + + unusableMovesBits = CheckMoveLimitations(gBankAttacker, unusableMovesBits, ~(MOVE_LIMITATION_PP)); + if (unusableMovesBits == 0xF) // all 4 moves cannot be chosen + { + gBattlescriptCurrInstr += 5; + } + else // at least one move can be chosen + { + u32 movePosition; + + do + { + movePosition = Random() & 3; + } while ((gBitTable[movePosition] & unusableMovesBits)); + + gRandomMove = gBattleMons[gBankAttacker].moves[movePosition]; + gCurrMovePos = movePosition; + gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); + gBankTarget = GetMoveTarget(gRandomMove, 0); + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkAA_set_destinybond(void) +{ + gBattleMons[gBankAttacker].status2 |= STATUS2_DESTINY_BOND; + gBattlescriptCurrInstr++; +} + +static void DestinyBondFlagUpdate(void) +{ + u8 sideAttacker = GetBankSide(gBankAttacker); + u8 sideTarget = GetBankSide(gBankTarget); + if (gBattleMons[gBankTarget].status2 & STATUS2_DESTINY_BOND + && sideAttacker != sideTarget + && !(gHitMarker & HITMARKER_GRUDGE)) + { + gHitMarker |= HITMARKER_DESTINYBOND; + } +} + +static void atkAB_DestinyBondFlagUpdate(void) +{ + DestinyBondFlagUpdate(); + gBattlescriptCurrInstr++; +} + +static void atkAC_remaininghptopower(void) +{ + s32 i; + s32 hpFraction = GetScaledHPFraction(gBattleMons[gBankAttacker].hp, gBattleMons[gBankAttacker].maxHP, 48); + + for (i = 0; i < (s32) sizeof(sFlailHpScaleToPowerTable); i += 2) + { + if (hpFraction <= sFlailHpScaleToPowerTable[i]) + break; + } + + gDynamicBasePower = sFlailHpScaleToPowerTable[i + 1]; + gBattlescriptCurrInstr++; +} + +static void atkAD_spite_ppreduce(void) +{ + if (gLastUsedMovesByBanks[gBankTarget] != 0 + && gLastUsedMovesByBanks[gBankTarget] != 0xFFFF) + { + s32 i; + + for (i = 0; i < 4; i++) + { + if (gLastUsedMovesByBanks[gBankTarget] == gBattleMons[gBankTarget].moves[i]) + break; + } + + if (i != 4 && gBattleMons[gBankTarget].pp[i] > 1) + { + s32 ppToDeduct = (Random() & 3) + 2; + if (gBattleMons[gBankTarget].pp[i] < ppToDeduct) + ppToDeduct = gBattleMons[gBankTarget].pp[i]; + + PREPARE_MOVE_BUFFER(gBattleTextBuff1, gLastUsedMovesByBanks[gBankTarget]) + + ConvertIntToDecimalStringN(gBattleTextBuff2, ppToDeduct, 0, 1); + + PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff2, 1, ppToDeduct) + + gBattleMons[gBankTarget].pp[i] -= ppToDeduct; + gActiveBank = gBankTarget; + + if (!(gDisableStructs[gActiveBank].unk18_b & gBitTable[i]) + && !(gBattleMons[gActiveBank].status2 & STATUS2_TRANSFORMED)) + { + EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + i, 0, 1, &gBattleMons[gActiveBank].pp[i]); + MarkBufferBankForExecution(gActiveBank); + } + + gBattlescriptCurrInstr += 5; + + if (gBattleMons[gBankTarget].pp[i] == 0) + CancelMultiTurnMoves(gBankTarget); + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkAE_heal_party_status(void) +{ + u32 zero = 0; + u8 toHeal = 0; + + if (gCurrentMove == MOVE_HEAL_BELL) + { + struct Pokemon* party; + s32 i; + + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + + if (GetBankSide(gBankAttacker) == SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + if (gBattleMons[gBankAttacker].ability != ABILITY_SOUNDPROOF) + { + gBattleMons[gBankAttacker].status1 = 0; + gBattleMons[gBankAttacker].status2 &= ~(STATUS2_NIGHTMARE); + } + else + { + RecordAbilityBattle(gBankAttacker, gBattleMons[gBankAttacker].ability); + gBattleCommunication[MULTISTRING_CHOOSER] |= 1; + } + + gActiveBank = gBattleScripting.bank = GetBankByIdentity(GetBankIdentity(gBankAttacker) ^ BIT_MON); + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && !(gAbsentBankFlags & gBitTable[gActiveBank])) + { + if (gBattleMons[gActiveBank].ability != ABILITY_SOUNDPROOF) + { + gBattleMons[gActiveBank].status1 = 0; + gBattleMons[gActiveBank].status2 &= ~(STATUS2_NIGHTMARE); + } + else + { + RecordAbilityBattle(gActiveBank, gBattleMons[gActiveBank].ability); + gBattleCommunication[MULTISTRING_CHOOSER] |= 2; + } + } + + for (i = 0; i < 6; i++) + { + u16 species = GetMonData(&party[i], MON_DATA_SPECIES2); + u8 abilityBit = GetMonData(&party[i], MON_DATA_ALT_ABILITY); + + if (species != 0 && species != SPECIES_EGG) + { + u8 ability; + + if (gBattlePartyID[gBankAttacker] == i) + ability = gBattleMons[gBankAttacker].ability; + else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && gBattlePartyID[gActiveBank] == i + && !(gAbsentBankFlags & gBitTable[gActiveBank])) + ability = gBattleMons[gActiveBank].ability; + else + ability = GetAbilityBySpecies(species, abilityBit); + + if (ability != ABILITY_SOUNDPROOF) + toHeal |= (1 << i); + } + } + } + else // Aromatherapy + { + gBattleCommunication[MULTISTRING_CHOOSER] = 4; + toHeal = 0x3F; + + gBattleMons[gBankAttacker].status1 = 0; + gBattleMons[gBankAttacker].status2 &= ~(STATUS2_NIGHTMARE); + + gActiveBank = GetBankByIdentity(GetBankIdentity(gBankAttacker) ^ 2); + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && !(gAbsentBankFlags & gBitTable[gActiveBank])) + { + gBattleMons[gActiveBank].status1 = 0; + gBattleMons[gActiveBank].status2 &= ~(STATUS2_NIGHTMARE); + } + + } + + if (toHeal) + { + gActiveBank = gBankAttacker; + EmitSetMonData(0, REQUEST_STATUS_BATTLE, toHeal, 4, &zero); + MarkBufferBankForExecution(gActiveBank); + } + + gBattlescriptCurrInstr++; +} + +static void atkAF_cursetarget(void) +{ + if (gBattleMons[gBankTarget].status2 & STATUS2_CURSED) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gBattleMons[gBankTarget].status2 |= STATUS2_CURSED; + gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 2; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + + gBattlescriptCurrInstr += 5; + } +} + +static void atkB0_set_spikes(void) +{ + u8 targetSide = GetBankSide(gBankAttacker) ^ BIT_SIDE; + + if (gSideTimers[targetSide].spikesAmount == 3) + { + gSpecialStatuses[gBankAttacker].flag20 = 1; + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gSideAffecting[targetSide] |= SIDE_STATUS_SPIKES; + gSideTimers[targetSide].spikesAmount++; + gBattlescriptCurrInstr += 5; + } +} + +static void atkB1_set_foresight(void) +{ + gBattleMons[gBankTarget].status2 |= STATUS2_FORESIGHT; + gBattlescriptCurrInstr++; +} + +static void atkB2_setperishsong(void) +{ + s32 i; + s32 notAffectedCount = 0; + + for (i = 0; i < gNoOfAllBanks; i++) + { + if (gStatuses3[i] & STATUS3_PERISH_SONG + || gBattleMons[i].ability == ABILITY_SOUNDPROOF) + { + notAffectedCount++; + } + else + { + gStatuses3[i] |= STATUS3_PERISH_SONG; + gDisableStructs[i].perishSong1 = 3; + gDisableStructs[i].perishSong2 = 3; + } + } + + PressurePPLoseOnUsingPerishSong(gBankAttacker); + + if (notAffectedCount == gNoOfAllBanks) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + else + gBattlescriptCurrInstr += 5; +} + +static void atkB3_rolloutdamagecalculation(void) +{ + if (gBattleMoveFlags & MOVESTATUS_NOEFFECT) + { + CancelMultiTurnMoves(gBankAttacker); + gBattlescriptCurrInstr = BattleScript_PauseEffectivenessSoundResultMsgEndMove; + } + else + { + s32 i; + + if (!(gBattleMons[gBankAttacker].status2 & STATUS2_MULTIPLETURNS)) // first hit + { + gDisableStructs[gBankAttacker].rolloutTimer1 = 5; + gDisableStructs[gBankAttacker].rolloutTimer2 = 5; + gBattleMons[gBankAttacker].status2 |= STATUS2_MULTIPLETURNS; + gLockedMoves[gBankAttacker] = gCurrentMove; + } + if (--gDisableStructs[gBankAttacker].rolloutTimer1 == 0) // last hit + { + gBattleMons[gBankAttacker].status2 &= ~(STATUS2_MULTIPLETURNS); + } + + gDynamicBasePower = gBattleMoves[gCurrentMove].power; + + for (i = 1; i < (5 - gDisableStructs[gBankAttacker].rolloutTimer1); i++) + gDynamicBasePower *= 2; + + if (gBattleMons[gBankAttacker].status2 & STATUS2_DEFENSE_CURL) + gDynamicBasePower *= 2; + + gBattlescriptCurrInstr++; + } +} + +static void atkB4_jumpifconfusedandstatmaxed(void) +{ + if (gBattleMons[gBankTarget].status2 & STATUS2_CONFUSION + && gBattleMons[gBankTarget].statStages[gBattlescriptCurrInstr[1]] == 0xC) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + else + gBattlescriptCurrInstr += 6; +} + +static void atkB5_furycuttercalc(void) +{ + if (gBattleMoveFlags & MOVESTATUS_NOEFFECT) + { + gDisableStructs[gBankAttacker].furyCutterCounter = 0; + gBattlescriptCurrInstr = BattleScript_PauseEffectivenessSoundResultMsgEndMove; + } + else + { + s32 i; + + if (gDisableStructs[gBankAttacker].furyCutterCounter != 5) + gDisableStructs[gBankAttacker].furyCutterCounter++; + + gDynamicBasePower = gBattleMoves[gCurrentMove].power; + + for (i = 1; i < gDisableStructs[gBankAttacker].furyCutterCounter; i++) + gDynamicBasePower *= 2; + + gBattlescriptCurrInstr++; + } +} + +static void atkB6_happinesstodamagecalculation(void) +{ + if (gBattleMoves[gCurrentMove].effect == EFFECT_RETURN) + gDynamicBasePower = 10 * (gBattleMons[gBankAttacker].friendship) / 25; + else // EFFECT_FRUSTRATION + gDynamicBasePower = 10 * (255 - gBattleMons[gBankAttacker].friendship) / 25; + + gBattlescriptCurrInstr++; +} + +static void atkB7_presentdamagecalculation(void) +{ + s32 rand = Random() & 0xFF; + + if (rand < 102) + gDynamicBasePower = 40; + else if (rand < 178) + gDynamicBasePower = 80; + else if (rand < 204) + gDynamicBasePower = 120; + else + { + gBattleMoveDamage = gBattleMons[gBankTarget].maxHP / 4; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + gBattleMoveDamage *= -1; + } + if (rand < 204) + gBattlescriptCurrInstr = BattleScript_PresentDamageTarget; + else if (gBattleMons[gBankTarget].maxHP == gBattleMons[gBankTarget].hp) + gBattlescriptCurrInstr = BattleScript_AlreadyAtFullHp; + else + { + gBattleMoveFlags &= ~(MOVESTATUS_NOTAFFECTED); + gBattlescriptCurrInstr = BattleScript_PresentHealTarget; + } +} + +static void atkB8_set_safeguard(void) +{ + if (gSideAffecting[GET_BANK_SIDE(gBankAttacker)] & SIDE_STATUS_SAFEGUARD) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + else + { + gSideAffecting[GET_BANK_SIDE(gBankAttacker)] |= SIDE_STATUS_SAFEGUARD; + gSideTimers[GET_BANK_SIDE(gBankAttacker)].safeguardTimer = 5; + gSideTimers[GET_BANK_SIDE(gBankAttacker)].safeguardBank = gBankAttacker; + gBattleCommunication[MULTISTRING_CHOOSER] = 5; + } + + gBattlescriptCurrInstr++; +} + +static void atkB9_magnitudedamagecalculation(void) +{ + s32 magnitude = Random() % 100; + + if (magnitude < 5) + { + gDynamicBasePower = 10; + magnitude = 4; + } + else if (magnitude < 15) + { + gDynamicBasePower = 30; + magnitude = 5; + } + else if (magnitude < 35) + { + gDynamicBasePower = 50; + magnitude = 6; + } + else if (magnitude < 65) + { + gDynamicBasePower = 70; + magnitude = 7; + } + else if (magnitude < 85) + { + gDynamicBasePower = 90; + magnitude = 8; + } + else if (magnitude < 95) + { + gDynamicBasePower = 110; + magnitude = 9; + } + else + { + gDynamicBasePower = 150; + magnitude = 10; + } + + + PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff1, 2, magnitude) + + for (gBankTarget = 0; gBankTarget < gNoOfAllBanks; gBankTarget++) + { + if (gBankTarget == gBankAttacker) + continue; + if (!(gAbsentBankFlags & gBitTable[gBankTarget])) // a valid target was found + break; + } + + gBattlescriptCurrInstr++; +} + +static void atkBA_jumpifnopursuitswitchdmg(void) +{ + if (gMultiHitCounter == 1) + { + if (GetBankSide(gBankAttacker) == SIDE_PLAYER) + gBankTarget = GetBankByIdentity(IDENTITY_OPPONENT_MON1); + else + gBankTarget = GetBankByIdentity(IDENTITY_PLAYER_MON1); + } + else + { + if (GetBankSide(gBankAttacker) == SIDE_PLAYER) + gBankTarget = GetBankByIdentity(IDENTITY_OPPONENT_MON2); + else + gBankTarget = GetBankByIdentity(IDENTITY_PLAYER_MON2); + } + + if (gActionForBanks[gBankTarget] == 0 + && gBankAttacker == *(gBattleStruct->moveTarget + gBankTarget) + && !(gBattleMons[gBankTarget].status1 & (STATUS_SLEEP | STATUS_FREEZE)) + && gBattleMons[gBankAttacker].hp + && !gDisableStructs[gBankTarget].truantCounter + && gChosenMovesByBanks[gBankTarget] == MOVE_PURSUIT) + { + s32 i; + + for (i = 0; i < gNoOfAllBanks; i++) + { + if (gTurnOrder[i] == gBankTarget) + gUnknown_0202407A[i] = 11; + } + + gCurrentMove = MOVE_PURSUIT; + gCurrMovePos = gUnknown_020241E9 = *(gBattleStruct->chosenMovesIds + gBankTarget); + gBattlescriptCurrInstr += 5; + gBattleScripting.animTurn = 1; + gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkBB_setsunny(void) +{ + if (gBattleWeather & WEATHER_SUN_ANY) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + } + else + { + gBattleWeather = WEATHER_SUN_TEMPORARY; + gBattleCommunication[MULTISTRING_CHOOSER] = 4; + gWishFutureKnock.weatherDuration = 5; + } + + gBattlescriptCurrInstr++; +} + +static void atkBC_maxattackhalvehp(void) // belly drum +{ + u32 halfHp = gBattleMons[gBankAttacker].maxHP / 2; + + if (!(gBattleMons[gBankAttacker].maxHP / 2)) + halfHp = 1; + + if (gBattleMons[gBankAttacker].statStages[STAT_STAGE_ATK] < 12 + && gBattleMons[gBankAttacker].hp > halfHp) + { + gBattleMons[gBankAttacker].statStages[STAT_STAGE_ATK] = 12; + gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 2; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkBD_copyfoestats(void) // psych up +{ + s32 i; + + for (i = 0; i < BATTLE_STATS_NO; i++) + { + gBattleMons[gBankAttacker].statStages[i] = gBattleMons[gBankTarget].statStages[i]; + } + + gBattlescriptCurrInstr += 5; // Has an unused jump ptr(possibly for a failed attempt) parameter. +} + +static void atkBE_rapidspinfree(void) +{ + if (gBattleMons[gBankAttacker].status2 & STATUS2_WRAPPED) + { + gBattleScripting.bank = gBankTarget; + gBattleMons[gBankAttacker].status2 &= ~(STATUS2_WRAPPED); + gBankTarget = *(gBattleStruct->wrappedBy + gBankAttacker); + + gBattleTextBuff1[0] = B_BUFF_PLACEHOLDER_BEGIN; + gBattleTextBuff1[1] = B_BUFF_MOVE; + gBattleTextBuff1[2] = *(gBattleStruct->wrappedMove + gBankAttacker * 2 + 0); + gBattleTextBuff1[3] = *(gBattleStruct->wrappedMove + gBankAttacker * 2 + 1); + gBattleTextBuff1[4] = B_BUFF_EOS; + + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_WrapFree; + } + else if (gStatuses3[gBankAttacker] & STATUS3_LEECHSEED) + { + gStatuses3[gBankAttacker] &= ~(STATUS3_LEECHSEED); + gStatuses3[gBankAttacker] &= ~(STATUS3_LEECHSEED_BANK); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_LeechSeedFree; + } + else if (gSideAffecting[GetBankSide(gBankAttacker)] & SIDE_STATUS_SPIKES) + { + gSideAffecting[GetBankSide(gBankAttacker)] &= ~(SIDE_STATUS_SPIKES); + gSideTimers[GetBankSide(gBankAttacker)].spikesAmount = 0; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_SpikesFree; + } + else + { + gBattlescriptCurrInstr++; + } +} + +static void atkBF_set_defense_curl(void) +{ + gBattleMons[gBankAttacker].status2 |= STATUS2_DEFENSE_CURL; + gBattlescriptCurrInstr++; +} + +static void atkC0_recoverbasedonsunlight(void) +{ + gBankTarget = gBankAttacker; + + if (gBattleMons[gBankAttacker].hp != gBattleMons[gBankAttacker].maxHP) + { + if (gBattleWeather == 0 || !WEATHER_HAS_EFFECT) + gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 2; + else if (gBattleWeather & WEATHER_SUN_ANY) + gBattleMoveDamage = 20 * gBattleMons[gBankAttacker].maxHP / 30; + else // not sunny weather + gBattleMoveDamage = gBattleMons[gBankAttacker].maxHP / 4; + + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + gBattleMoveDamage *= -1; + + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +#ifdef NONMATCHING +static void atkC1_hidden_power(void) +{ + s32 powerBits; + s32 typeBits; + + powerBits = ((gBattleMons[gBankAttacker].hpIV & 2) >> 1) + | ((gBattleMons[gBankAttacker].attackIV & 2) << 0) + | ((gBattleMons[gBankAttacker].defenseIV & 2) << 1) + | ((gBattleMons[gBankAttacker].speedIV & 2) << 2) + | ((gBattleMons[gBankAttacker].spAttackIV & 2) << 3) + | ((gBattleMons[gBankAttacker].spDefenseIV & 2) << 4); + + typeBits = ((gBattleMons[gBankAttacker].hpIV & 1) << 0) + | ((gBattleMons[gBankAttacker].attackIV & 1) << 1) + | ((gBattleMons[gBankAttacker].defenseIV & 1) << 2) + | ((gBattleMons[gBankAttacker].speedIV & 1) << 3) + | ((gBattleMons[gBankAttacker].spAttackIV & 1) << 4) + | ((gBattleMons[gBankAttacker].spDefenseIV & 1) << 5); + + gDynamicBasePower = (40 * powerBits) / 63 + 30; + + gBattleStruct->dynamicMoveType = (15 * typeBits) / 63 + 1; + if (gBattleStruct->dynamicMoveType > 8) + gBattleStruct->dynamicMoveType++; + gBattleStruct->dynamicMoveType |= 0xC0; + + gBattlescriptCurrInstr++; +} + +#else +__attribute__((naked)) +static void atkC1_hidden_power(void) +{ + asm(".syntax unified\n\ + push {r4-r7,lr}\n\ + mov r7, r10\n\ + mov r6, r9\n\ + mov r5, r8\n\ + push {r5-r7}\n\ + ldr r2, =gBattleMons\n\ + ldr r0, =gBankAttacker\n\ + ldrb r1, [r0]\n\ + movs r0, 0x58\n\ + adds r4, r1, 0\n\ + muls r4, r0\n\ + adds r4, r2\n\ + ldrb r0, [r4, 0x14]\n\ + mov r10, r0\n\ + mov r7, r10\n\ + lsls r7, 27\n\ + adds r0, r7, 0\n\ + lsrs r0, 27\n\ + mov r10, r0\n\ + movs r1, 0x2\n\ + mov r2, r10\n\ + ands r2, r1\n\ + asrs r2, 1\n\ + ldrh r7, [r4, 0x14]\n\ + mov r9, r7\n\ + mov r0, r9\n\ + lsls r0, 22\n\ + mov r9, r0\n\ + lsrs r3, r0, 27\n\ + adds r0, r1, 0\n\ + ands r0, r3\n\ + orrs r2, r0\n\ + ldrb r7, [r4, 0x15]\n\ + mov r8, r7\n\ + mov r0, r8\n\ + lsls r0, 25\n\ + mov r8, r0\n\ + lsrs r3, r0, 27\n\ + adds r0, r1, 0\n\ + ands r0, r3\n\ + lsls r0, 1\n\ + orrs r2, r0\n\ + ldr r6, [r4, 0x14]\n\ + lsls r6, 12\n\ + lsrs r3, r6, 27\n\ + adds r0, r1, 0\n\ + ands r0, r3\n\ + lsls r0, 2\n\ + orrs r2, r0\n\ + ldrh r5, [r4, 0x16]\n\ + lsls r5, 23\n\ + lsrs r3, r5, 27\n\ + adds r0, r1, 0\n\ + ands r0, r3\n\ + lsls r0, 3\n\ + orrs r2, r0\n\ + ldrb r3, [r4, 0x17]\n\ + lsls r3, 26\n\ + lsrs r0, r3, 27\n\ + ands r1, r0\n\ + lsls r1, 4\n\ + orrs r2, r1\n\ + movs r1, 0x1\n\ + adds r4, r1, 0\n\ + mov r7, r10\n\ + ands r4, r7\n\ + mov r0, r9\n\ + lsrs r0, 27\n\ + mov r9, r0\n\ + adds r0, r1, 0\n\ + mov r7, r9\n\ + ands r0, r7\n\ + lsls r0, 1\n\ + orrs r4, r0\n\ + mov r0, r8\n\ + lsrs r0, 27\n\ + mov r8, r0\n\ + adds r0, r1, 0\n\ + mov r7, r8\n\ + ands r0, r7\n\ + lsls r0, 2\n\ + orrs r4, r0\n\ + lsrs r6, 27\n\ + adds r0, r1, 0\n\ + ands r0, r6\n\ + lsls r0, 3\n\ + orrs r4, r0\n\ + lsrs r5, 27\n\ + adds r0, r1, 0\n\ + ands r0, r5\n\ + lsls r0, 4\n\ + orrs r4, r0\n\ + lsrs r3, 27\n\ + ands r1, r3\n\ + lsls r1, 5\n\ + orrs r4, r1\n\ + ldr r5, =gDynamicBasePower\n\ + lsls r0, r2, 2\n\ + adds r0, r2\n\ + lsls r0, 3\n\ + movs r1, 0x3F\n\ + bl __divsi3\n\ + adds r0, 0x1E\n\ + strh r0, [r5]\n\ + ldr r6, =gBattleStruct\n\ + ldr r5, [r6]\n\ + lsls r0, r4, 4\n\ + subs r0, r4\n\ + movs r1, 0x3F\n\ + bl __divsi3\n\ + adds r0, 0x1\n\ + strb r0, [r5, 0x13]\n\ + ldr r1, [r6]\n\ + ldrb r0, [r1, 0x13]\n\ + cmp r0, 0x8\n\ + bls _080544F0\n\ + adds r0, 0x1\n\ + strb r0, [r1, 0x13]\n\ +_080544F0:\n\ + ldr r2, [r6]\n\ + ldrb r0, [r2, 0x13]\n\ + movs r1, 0xC0\n\ + orrs r0, r1\n\ + strb r0, [r2, 0x13]\n\ + ldr r1, =gBattlescriptCurrInstr\n\ + ldr r0, [r1]\n\ + adds r0, 0x1\n\ + str r0, [r1]\n\ + pop {r3-r5}\n\ + mov r8, r3\n\ + mov r9, r4\n\ + mov r10, r5\n\ + pop {r4-r7}\n\ + pop {r0}\n\ + bx r0\n\ + .pool\n\ + .syntax divided"); +} +#endif // NONMATCHING + +static void atkC2_selectnexttarget(void) +{ + for (gBankTarget = 0; gBankTarget < gNoOfAllBanks; gBankTarget++) + { + if (gBankTarget == gBankAttacker) + continue; + if (!(gAbsentBankFlags & gBitTable[gBankTarget])) + break; + } + gBattlescriptCurrInstr++; +} + +static void atkC3_setfutureattack(void) +{ + if (gWishFutureKnock.futureSightCounter[gBankTarget] != 0) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gSideAffecting[GET_BANK_SIDE(gBankTarget)] |= SIDE_STATUS_FUTUREATTACK; + gWishFutureKnock.futureSightMove[gBankTarget] = gCurrentMove; + gWishFutureKnock.futureSightAttacker[gBankTarget] = gBankAttacker; + gWishFutureKnock.futureSightCounter[gBankTarget] = 3; + gWishFutureKnock.futureSightDmg[gBankTarget] = CalculateBaseDamage(&gBattleMons[gBankAttacker], &gBattleMons[gBankTarget], gCurrentMove, + gSideAffecting[GET_BANK_SIDE(gBankTarget)], 0, + 0, gBankAttacker, gBankTarget); + + if (gProtectStructs[gBankAttacker].helpingHand) + gWishFutureKnock.futureSightDmg[gBankTarget] = gWishFutureKnock.futureSightDmg[gBankTarget] * 15 / 10; + + if (gCurrentMove == MOVE_DOOM_DESIRE) + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + + gBattlescriptCurrInstr += 5; + } +} + +static void atkC4_beat_up(void) +{ + struct Pokemon* party; + + if (GetBankSide(gBankAttacker) == SIDE_PLAYER) + party = gPlayerParty; + else + party = gEnemyParty; + + if (gBattleMons[gBankTarget].hp == 0) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + u8 beforeLoop = gBattleCommunication[0]; + for (;gBattleCommunication[0] < 6; gBattleCommunication[0]++) + { + if (GetMonData(&party[gBattleCommunication[0]], MON_DATA_HP) + && GetMonData(&party[gBattleCommunication[0]], MON_DATA_SPECIES2) + && GetMonData(&party[gBattleCommunication[0]], MON_DATA_SPECIES2) != SPECIES_EGG + && !GetMonData(&party[gBattleCommunication[0]], MON_DATA_STATUS)) + break; + } + if (gBattleCommunication[0] < 6) + { + PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBankAttacker, gBattleCommunication[0]) + + gBattlescriptCurrInstr += 9; + + gBattleMoveDamage = gBaseStats[GetMonData(&party[gBattleCommunication[0]], MON_DATA_SPECIES)].baseAttack; + gBattleMoveDamage *= gBattleMoves[gCurrentMove].power; + gBattleMoveDamage *= (GetMonData(&party[gBattleCommunication[0]], MON_DATA_LEVEL) * 2 / 5 + 2); + gBattleMoveDamage /= gBaseStats[gBattleMons[gBankTarget].species].baseDefense; + gBattleMoveDamage = (gBattleMoveDamage / 50) + 2; + if (gProtectStructs[gBankAttacker].helpingHand) + gBattleMoveDamage = gBattleMoveDamage * 15 / 10; + + gBattleCommunication[0]++; + } + else if (beforeLoop != 0) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + else + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 5); + } +} + +static void atkC5_setsemiinvulnerablebit(void) +{ + switch (gCurrentMove) + { + case MOVE_FLY: + case MOVE_BOUNCE: + gStatuses3[gBankAttacker] |= STATUS3_ON_AIR; + break; + case MOVE_DIG: + gStatuses3[gBankAttacker] |= STATUS3_UNDERGROUND; + break; + case MOVE_DIVE: + gStatuses3[gBankAttacker] |= STATUS3_UNDERWATER; + break; + } + + gBattlescriptCurrInstr++; +} + +static void atkC6_clearsemiinvulnerablebit(void) +{ + switch (gCurrentMove) + { + case MOVE_FLY: + case MOVE_BOUNCE: + gStatuses3[gBankAttacker] &= ~STATUS3_ON_AIR; + break; + case MOVE_DIG: + gStatuses3[gBankAttacker] &= ~STATUS3_UNDERGROUND; + break; + case MOVE_DIVE: + gStatuses3[gBankAttacker] &= ~STATUS3_UNDERWATER; + break; + } + + gBattlescriptCurrInstr++; +} + +static void atkC7_setminimize(void) +{ + if (gHitMarker & HITMARKER_OBEYS) + gStatuses3[gBankAttacker] |= STATUS3_MINIMIZED; + + gBattlescriptCurrInstr++; +} + +static void atkC8_sethail(void) +{ + if (gBattleWeather & WEATHER_HAIL_ANY) + { + gBattleMoveFlags |= MOVESTATUS_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + } + else + { + gBattleWeather = WEATHER_HAIL; + gBattleCommunication[MULTISTRING_CHOOSER] = 5; + gWishFutureKnock.weatherDuration = 5; + } + + gBattlescriptCurrInstr++; +} + +static void atkC9_jumpifattackandspecialattackcannotfall(void) // memento +{ + if (gBattleMons[gBankTarget].statStages[STAT_STAGE_ATK] == 0 + && gBattleMons[gBankTarget].statStages[STAT_STAGE_SPATK] == 0 + && gBattleCommunication[6] != 1) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gActiveBank = gBankAttacker; + gBattleMoveDamage = gBattleMons[gActiveBank].hp; + EmitHealthBarUpdate(0, 0x7FFF); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr += 5; + } +} + +static void atkCA_setforcedtarget(void) // follow me +{ + gSideTimers[GetBankSide(gBankAttacker)].followmeTimer = 1; + gSideTimers[GetBankSide(gBankAttacker)].followmeTarget = gBankAttacker; + gBattlescriptCurrInstr++; +} + +static void atkCB_setcharge(void) +{ + gStatuses3[gBankAttacker] |= STATUS3_CHARGED_UP; + gDisableStructs[gBankAttacker].chargeTimer1 = 2; + gDisableStructs[gBankAttacker].chargeTimer2 = 2; + gBattlescriptCurrInstr++; +} + +static void atkCC_callterrainattack(void) // nature power +{ + gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); + gCurrentMove = sNaturePowerMoves[gBattleTerrain]; + gBankTarget = GetMoveTarget(gCurrentMove, 0); + BattleScriptPush(gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]); + gBattlescriptCurrInstr++; +} + +static void atkCD_cureifburnedparalysedorpoisoned(void) // refresh +{ + if (gBattleMons[gBankAttacker].status1 & (STATUS_POISON | STATUS_BURN | STATUS_PARALYSIS | STATUS_TOXIC_POISON)) + { + gBattleMons[gBankAttacker].status1 = 0; + gBattlescriptCurrInstr += 5; + gActiveBank = gBankAttacker; + EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBank].status1); + MarkBufferBankForExecution(gActiveBank); + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkCE_settorment(void) +{ + if (gBattleMons[gBankTarget].status2 & STATUS2_TORMENT) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gBattleMons[gBankTarget].status2 |= STATUS2_TORMENT; + gBattlescriptCurrInstr += 5; + } +} + +static void atkCF_jumpifnodamage(void) +{ + if (gProtectStructs[gBankAttacker].physicalDmg || gProtectStructs[gBankAttacker].specialDmg) + gBattlescriptCurrInstr += 5; + else + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); +} + +static void atkD0_settaunt(void) +{ + if (gDisableStructs[gBankTarget].tauntTimer1 == 0) + { + gDisableStructs[gBankTarget].tauntTimer1 = 2; + gDisableStructs[gBankTarget].tauntTimer2 = 2; + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkD1_set_helpinghand(void) +{ + gBankTarget = GetBankByIdentity(GetBankIdentity(gBankAttacker) ^ BIT_MON); + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && !(gAbsentBankFlags & gBitTable[gBankTarget]) + && !gProtectStructs[gBankAttacker].helpingHand + && !gProtectStructs[gBankTarget].helpingHand) + { + gProtectStructs[gBankTarget].helpingHand = 1; + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkD2_swap_items(void) // trick +{ + // opponent can't swap items with player in regular battles + if (gBattleTypeFlags & BATTLE_TYPE_x4000000 + || (GetBankSide(gBankAttacker) == SIDE_OPPONENT + && !(gBattleTypeFlags & (BATTLE_TYPE_LINK + | BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_FRONTIER + | BATTLE_TYPE_SECRET_BASE + | BATTLE_TYPE_x2000000)))) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + u8 sideAttacker = GetBankSide(gBankAttacker); + u8 sideTarget = GetBankSide(gBankTarget); + + // you can't swap items if they were knocked off in regular battles + if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK + | BATTLE_TYPE_EREADER_TRAINER + | BATTLE_TYPE_FRONTIER + | BATTLE_TYPE_SECRET_BASE + | BATTLE_TYPE_x2000000)) + && (gWishFutureKnock.knockedOffPokes[sideAttacker] & gBitTable[gBattlePartyID[gBankAttacker]] + || gWishFutureKnock.knockedOffPokes[sideTarget] & gBitTable[gBattlePartyID[gBankTarget]])) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + // can't swap if two pokemon don't have an item + // or if either of them is an enigma berry or a mail + else if ((gBattleMons[gBankAttacker].item == 0 && gBattleMons[gBankTarget].item == 0) + || gBattleMons[gBankAttacker].item == ITEM_ENIGMA_BERRY + || gBattleMons[gBankTarget].item == ITEM_ENIGMA_BERRY + || IS_ITEM_MAIL(gBattleMons[gBankAttacker].item) + || IS_ITEM_MAIL(gBattleMons[gBankTarget].item)) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + // check if ability prevents swapping + else if (gBattleMons[gBankTarget].ability == ABILITY_STICKY_HOLD) + { + gBattlescriptCurrInstr = BattleScript_StickyHoldActivates; + gLastUsedAbility = gBattleMons[gBankTarget].ability; + RecordAbilityBattle(gBankTarget, gLastUsedAbility); + } + // took a while, but all checks passed and items can be safely swapped + else + { + u16 oldItemAtk, *newItemAtk; + + newItemAtk = &gBattleStruct->changedItems[gBankAttacker]; + oldItemAtk = gBattleMons[gBankAttacker].item; + *newItemAtk = gBattleMons[gBankTarget].item; + + gBattleMons[gBankAttacker].item = 0; + gBattleMons[gBankTarget].item = oldItemAtk; + + gActiveBank = gBankAttacker; + EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, newItemAtk); + MarkBufferBankForExecution(gBankAttacker); + + gActiveBank = gBankTarget; + EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gBankTarget].item); + MarkBufferBankForExecution(gBankTarget); + + *(u8*)((u8*)(&gBattleStruct->choicedMove[gBankTarget]) + 0) = 0; + *(u8*)((u8*)(&gBattleStruct->choicedMove[gBankTarget]) + 1) = 0; + + *(u8*)((u8*)(&gBattleStruct->choicedMove[gBankAttacker]) + 0) = 0; + *(u8*)((u8*)(&gBattleStruct->choicedMove[gBankAttacker]) + 1) = 0; + + gBattlescriptCurrInstr += 5; + + PREPARE_ITEM_BUFFER(gBattleTextBuff1, *newItemAtk) + PREPARE_ITEM_BUFFER(gBattleTextBuff2, oldItemAtk) + + if (oldItemAtk != 0 && *newItemAtk != 0) + gBattleCommunication[MULTISTRING_CHOOSER] = 2; // attacker's item -> <- target's item + else if (oldItemAtk == 0 && *newItemAtk != 0) + gBattleCommunication[MULTISTRING_CHOOSER] = 0; // nothing -> <- target's item + else + gBattleCommunication[MULTISTRING_CHOOSER] = 1; // attacker's item -> <- nothing + } + } +} + +static void atkD3_copy_ability(void) // role play +{ + if (gBattleMons[gBankTarget].ability != 0 + && gBattleMons[gBankTarget].ability != ABILITY_WONDER_GUARD) + { + gBattleMons[gBankAttacker].ability = gBattleMons[gBankTarget].ability; + gLastUsedAbility = gBattleMons[gBankTarget].ability; + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkD4_wish_effect(void) +{ + switch (gBattlescriptCurrInstr[1]) + { + case 0: // use wish + if (gWishFutureKnock.wishCounter[gBankAttacker] == 0) + { + gWishFutureKnock.wishCounter[gBankAttacker] = 2; + gWishFutureKnock.wishUserID[gBankAttacker] = gBattlePartyID[gBankAttacker]; + gBattlescriptCurrInstr += 6; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + } + break; + case 1: // heal effect + PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBankTarget, gWishFutureKnock.wishUserID[gBankTarget]) + + gBattleMoveDamage = gBattleMons[gBankTarget].maxHP / 2; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + gBattleMoveDamage *= -1; + + if (gBattleMons[gBankTarget].hp == gBattleMons[gBankTarget].maxHP) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + else + gBattlescriptCurrInstr += 6; + + break; + } +} + +static void atkD5_setroots(void) // ingrain +{ + if (gStatuses3[gBankAttacker] & STATUS3_ROOTED) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gStatuses3[gBankAttacker] |= STATUS3_ROOTED; + gBattlescriptCurrInstr += 5; + } +} + +static void atkD6_doubledamagedealtifdamaged(void) +{ + if ((gProtectStructs[gBankAttacker].physicalDmg + && gProtectStructs[gBankAttacker].physicalBank == gBankTarget) + || (gProtectStructs[gBankAttacker].specialDmg + && gProtectStructs[gBankAttacker].specialBank == gBankTarget)) + { + gBattleScripting.dmgMultiplier = 2; + } + + gBattlescriptCurrInstr++; +} + +static void atkD7_setyawn(void) +{ + if (gStatuses3[gBankTarget] & STATUS3_YAWN + || gBattleMons[gBankTarget].status1 & STATUS_ANY) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gStatuses3[gBankTarget] |= 0x1000; + gBattlescriptCurrInstr += 5; + } +} + +static void atkD8_setdamagetohealthdifference(void) +{ + if (gBattleMons[gBankTarget].hp <= gBattleMons[gBankAttacker].hp) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gBattleMoveDamage = gBattleMons[gBankTarget].hp - gBattleMons[gBankAttacker].hp; + gBattlescriptCurrInstr += 5; + } +} + +static void atkD9_scaledamagebyhealthratio(void) +{ + if (gDynamicBasePower == 0) + { + u8 power = gBattleMoves[gCurrentMove].power; + gDynamicBasePower = gBattleMons[gBankAttacker].hp * power / gBattleMons[gBankAttacker].maxHP; + if (gDynamicBasePower == 0) + gDynamicBasePower = 1; + } + gBattlescriptCurrInstr++; +} + +static void atkDA_abilityswap(void) // skill swap +{ + if ((gBattleMons[gBankAttacker].ability == 0 + && gBattleMons[gBankTarget].ability == 0) + || gBattleMons[gBankAttacker].ability == ABILITY_WONDER_GUARD + || gBattleMons[gBankTarget].ability == ABILITY_WONDER_GUARD + || gBattleMoveFlags & MOVESTATUS_NOEFFECT) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + u8 abilityAtk = gBattleMons[gBankAttacker].ability; + gBattleMons[gBankAttacker].ability = gBattleMons[gBankTarget].ability; + gBattleMons[gBankTarget].ability = abilityAtk; + + gBattlescriptCurrInstr += 5; + } +} + +static void atkDB_imprisoneffect(void) +{ + if ((gStatuses3[gBankAttacker] & STATUS3_IMPRISONED_OTHERS)) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + u8 bank, sideAttacker; + + sideAttacker = GetBankSide(gBankAttacker); + PressurePPLoseOnUsingImprision(gBankAttacker); + for (bank = 0; bank < gNoOfAllBanks; bank++) + { + if (sideAttacker != GetBankSide(bank)) + { + s32 attackerMoveId; + for (attackerMoveId = 0; attackerMoveId < 4; attackerMoveId++) + { + s32 i; + for (i = 0; i < 4; i++) + { + if (gBattleMons[gBankAttacker].moves[attackerMoveId] == gBattleMons[bank].moves[i] + && gBattleMons[gBankAttacker].moves[attackerMoveId] != MOVE_NONE) + break; + } + if (i != 4) + break; + } + if (attackerMoveId != 4) + { + gStatuses3[gBankAttacker] |= STATUS3_IMPRISONED_OTHERS; + gBattlescriptCurrInstr += 5; + break; + } + } + } + if (bank == gNoOfAllBanks) // In Generation 3 games, Imprison fails if the user doesn't share any moves with any of the foes + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkDC_setgrudge(void) +{ + if (gStatuses3[gBankAttacker] & STATUS3_GRUDGE) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gStatuses3[gBankAttacker] |= STATUS3_GRUDGE; + gBattlescriptCurrInstr += 5; + } +} + +static void atkDD_weightdamagecalculation(void) +{ + s32 i; + for (i = 0; sWeightToDamageTable[i] != 0xFFFF; i += 2) + { + if (sWeightToDamageTable[i] > GetPokedexHeightWeight(SpeciesToNationalPokedexNum(gBattleMons[gBankTarget].species), 1)) + break; + } + + if (sWeightToDamageTable[i] != 0xFFFF) + gDynamicBasePower = sWeightToDamageTable[i + 1]; + else + gDynamicBasePower = 120; + + gBattlescriptCurrInstr++; +} + +static void atkDE_asistattackselect(void) +{ + s32 chooseableMovesNo = 0; + struct Pokemon* party; + s32 monId, moveId; + u16* movesArray = gBattleStruct->assistPossibleMoves; + + if (GET_BANK_SIDE(gBankAttacker) != SIDE_PLAYER) + party = gEnemyParty; + else + party = gPlayerParty; + + for (monId = 0; monId < 6; monId++) + { + if (monId == gBattlePartyID[gBankAttacker]) + continue; + if (GetMonData(&party[monId], MON_DATA_SPECIES2) == SPECIES_NONE) + continue; + if (GetMonData(&party[monId], MON_DATA_SPECIES2) == SPECIES_EGG) + continue; + + for (moveId = 0; moveId < 4; moveId++) + { + s32 i = 0; + u16 move = GetMonData(&party[monId], MON_DATA_MOVE1 + moveId); + + if (IsInvalidForSleepTalkOrAssist(move)) + continue; + + for (; sMovesForbiddenToCopy[i] != ASSIST_FORBIDDEN_END && move != sMovesForbiddenToCopy[i]; i++); + + if (sMovesForbiddenToCopy[i] != ASSIST_FORBIDDEN_END) + continue; + if (move == MOVE_NONE) + continue; + + movesArray[chooseableMovesNo] = move; + chooseableMovesNo++; + } + } + if (chooseableMovesNo) + { + gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); + gRandomMove = movesArray[((Random() & 0xFF) * chooseableMovesNo) >> 8]; + gBankTarget = GetMoveTarget(gRandomMove, 0); + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkDF_setmagiccoat(void) +{ + gBankTarget = gBankAttacker; + gSpecialStatuses[gBankAttacker].flag20 = 1; + if (gCurrentMoveTurn == gNoOfAllBanks - 1) // moves last turn + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gProtectStructs[gBankAttacker].bounceMove = 1; + gBattlescriptCurrInstr += 5; + } +} + +static void atkE0_setstealstatchange(void) // snatch +{ + gSpecialStatuses[gBankAttacker].flag20 = 1; + if (gCurrentMoveTurn == gNoOfAllBanks - 1) // moves last turn + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + gProtectStructs[gBankAttacker].stealMove = 1; + gBattlescriptCurrInstr += 5; + } +} + +static void atkE1_intimidate_string_loader(void) +{ + u8 side; + + gBattleScripting.bank = gBattleStruct->intimidateBank; + side = GetBankSide(gBattleScripting.bank); + + PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gBattleMons[gBattleScripting.bank].ability) + + for (;gBankTarget < gNoOfAllBanks; gBankTarget++) + { + if (GetBankSide(gBankTarget) == side) + continue; + if (!(gAbsentBankFlags & gBitTable[gBankTarget])) + break; + } + + if (gBankTarget >= gNoOfAllBanks) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + else + gBattlescriptCurrInstr += 5; +} + +static void atkE2_switchout_abilities(void) +{ + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + + switch (gBattleMons[gActiveBank].ability) + { + case ABILITY_NATURAL_CURE: + gBattleMons[gActiveBank].status1 = 0; + EmitSetMonData(0, REQUEST_STATUS_BATTLE, gBitTable[*(gBattleStruct->field_58 + gActiveBank)], 4, &gBattleMons[gActiveBank].status1); + MarkBufferBankForExecution(gActiveBank); + break; + } + + gBattlescriptCurrInstr += 2; +} + +static void atkE3_jumpifhasnohp(void) +{ + gActiveBank = GetBattleBank(gBattlescriptCurrInstr[1]); + + if (gBattleMons[gActiveBank].hp == 0) + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 2); + else + gBattlescriptCurrInstr += 6; +} + +static void atkE4_getsecretpowereffect(void) +{ + switch (gBattleTerrain) + { + case BATTLE_TERRAIN_GRASS: + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_POISON; + break; + case BATTLE_TERRAIN_LONG_GRASS: + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_SLEEP; + break; + case BATTLE_TERRAIN_SAND: + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_ACC_MINUS_1; + break; + case BATTLE_TERRAIN_UNDERWATER: + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_DEF_MINUS_1; + break; + case BATTLE_TERRAIN_WATER: + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_ATK_MINUS_1; + break; + case BATTLE_TERRAIN_POND: + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_SPD_MINUS_1; + break; + case BATTLE_TERRAIN_ROCK: + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_CONFUSION; + break; + case BATTLE_TERRAIN_CAVE: + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_FLINCH; + break; + default: + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_PARALYSIS; + break; + } + gBattlescriptCurrInstr++; +} + +static void atkE5_pickup(void) +{ + if (!InBattlePike()) + { + s32 i; + u16 species, heldItem; + u8 ability; + + if (InBattlePyramid()) + { + for (i = 0; i < 6; i++) + { + species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2); + heldItem = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM); + + if (GetMonData(&gPlayerParty[i], MON_DATA_ALT_ABILITY)) + ability = gBaseStats[species].ability2; + else + ability = gBaseStats[species].ability1; + + if (ability == ABILITY_PICKUP + && species != 0 + && species != SPECIES_EGG + && heldItem == ITEM_NONE + && (Random() % 10) == 0) + { + heldItem = GetBattlePyramidPickupItemId(); + SetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM, &heldItem); + } + } + } + else + { + for (i = 0; i < 6; i++) + { + species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2); + heldItem = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM); + + if (GetMonData(&gPlayerParty[i], MON_DATA_ALT_ABILITY)) + ability = gBaseStats[species].ability2; + else + ability = gBaseStats[species].ability1; + + if (ability == ABILITY_PICKUP + && species != 0 + && species != SPECIES_EGG + && heldItem == ITEM_NONE + && (Random() % 10) == 0) + { + s32 j; + s32 rand = Random() % 100; + u8 lvlDivBy10 = (GetMonData(&gPlayerParty[i], MON_DATA_LEVEL) - 1) / 10; + if (lvlDivBy10 > 9) + lvlDivBy10 = 9; + + for (j = 0; j < 9; j++) + { + if (sPickupProbabilities[j] > rand) + { + SetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM, &sPickupItems[lvlDivBy10 + j]); + break; + } + else if (rand == 99 || rand == 98) + { + SetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM, &sRarePickupItems[lvlDivBy10 + (99 - rand)]); + break; + } + } + } + } + } + } + + gBattlescriptCurrInstr++; +} + +static void atkE6_castform_change_animation(void) +{ + gActiveBank = gBattleScripting.bank; + + if (gBattleMons[gActiveBank].status2 & STATUS2_SUBSTITUTE) + *(&gBattleStruct->formToChangeInto) |= 0x80; + + EmitBattleAnimation(0, B_ANIM_CASTFORM_CHANGE, gBattleStruct->formToChangeInto); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr++; +} + +static void atkE7_castform_data_change(void) +{ + u8 form; + + gBattlescriptCurrInstr++; + form = CastformDataTypeChange(gBattleScripting.bank); + if (form) + { + BattleScriptPushCursorAndCallback(BattleScript_CastformChange); + *(&gBattleStruct->formToChangeInto) = form - 1; + } +} + +static void atkE8_settypebasedhalvers(void) // water and mud sport +{ + bool8 worked = FALSE; + + if (gBattleMoves[gCurrentMove].effect == EFFECT_MUD_SPORT) + { + if (!(gStatuses3[gBankAttacker] & STATUS3_MUDSPORT)) + { + gStatuses3[gBankAttacker] |= STATUS3_MUDSPORT; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + worked = TRUE; + } + } + else // water sport + { + if (!(gStatuses3[gBankAttacker] & STATUS3_WATERSPORT)) + { + gStatuses3[gBankAttacker] |= STATUS3_WATERSPORT; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + worked = TRUE; + } + } + + if (worked) + gBattlescriptCurrInstr += 5; + else + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); +} + +static void atkE9_setweatherballtype(void) +{ + if (WEATHER_HAS_EFFECT) + { + if (gBattleWeather & WEATHER_ANY) + gBattleScripting.dmgMultiplier = 2; + if (gBattleWeather & WEATHER_RAIN_ANY) + *(&gBattleStruct->dynamicMoveType) = TYPE_WATER | 0x80; + else if (gBattleWeather & WEATHER_SANDSTORM_ANY) + *(&gBattleStruct->dynamicMoveType) = TYPE_ROCK | 0x80; + else if (gBattleWeather & WEATHER_SUN_ANY) + *(&gBattleStruct->dynamicMoveType) = TYPE_FIRE | 0x80; + else if (gBattleWeather & WEATHER_HAIL_ANY) + *(&gBattleStruct->dynamicMoveType) = TYPE_ICE | 0x80; + else + *(&gBattleStruct->dynamicMoveType) = TYPE_NORMAL | 0x80; + } + + gBattlescriptCurrInstr++; +} + +static void atkEA_recycleitem(void) +{ + u16 *usedHeldItem; + + gActiveBank = gBankAttacker; + usedHeldItem = &gBattleStruct->usedHeldItems[gActiveBank]; + if (*usedHeldItem != 0 && gBattleMons[gActiveBank].item == 0) + { + gLastUsedItem = *usedHeldItem; + *usedHeldItem = 0; + gBattleMons[gActiveBank].item = gLastUsedItem; + + EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gActiveBank].item); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkEB_settypetoterrain(void) +{ + if (gBattleMons[gBankAttacker].type1 != sTerrainToType[gBattleTerrain] + && gBattleMons[gBankAttacker].type2 != sTerrainToType[gBattleTerrain]) + { + gBattleMons[gBankAttacker].type1 = sTerrainToType[gBattleTerrain]; + gBattleMons[gBankAttacker].type2 = sTerrainToType[gBattleTerrain]; + + PREPARE_TYPE_BUFFER(gBattleTextBuff1, sTerrainToType[gBattleTerrain]) + + gBattlescriptCurrInstr += 5; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkEC_pursuit_sth(void) +{ + gActiveBank = GetBankByIdentity(GetBankIdentity(gBankAttacker) ^ BIT_MON); + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && !(gAbsentBankFlags & gBitTable[gActiveBank]) + && gActionForBanks[gActiveBank] == 0 + && gChosenMovesByBanks[gActiveBank] == MOVE_PURSUIT) + { + gUnknown_0202407A[gActiveBank] = 11; + gCurrentMove = MOVE_PURSUIT; + gBattlescriptCurrInstr += 5; + gBattleScripting.animTurn = 1; + gBattleScripting.field_20 = gBankAttacker; + gBankAttacker = gActiveBank; + } + else + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } +} + +static void atkED_802B4B4(void) +{ + gEffectBank = gBankAttacker; + + if (gBankAttacker == gBankTarget) + gBankAttacker = gBankTarget = gBattleScripting.bank; + else + gBankTarget = gBattleScripting.bank; + + gBattleScripting.bank = gEffectBank; + gBattlescriptCurrInstr++; +} + +static void atkEE_removelightscreenreflect(void) // brick break +{ + u8 opposingSide = GetBankSide(gBankAttacker) ^ BIT_SIDE; + + if (gSideTimers[opposingSide].reflectTimer || gSideTimers[opposingSide].lightscreenTimer) + { + gSideAffecting[opposingSide] &= ~(SIDE_STATUS_REFLECT); + gSideAffecting[opposingSide] &= ~(SIDE_STATUS_LIGHTSCREEN); + gSideTimers[opposingSide].reflectTimer = 0; + gSideTimers[opposingSide].lightscreenTimer = 0; + gBattleScripting.animTurn = 1; + gBattleScripting.animTargetsHit = 1; + } + else + { + gBattleScripting.animTurn = 0; + gBattleScripting.animTargetsHit = 0; + } + + gBattlescriptCurrInstr++; +} + +static void atkEF_pokeball_catch_calculation(void) +{ + u8 ballMultiplier = 0; + + if (gBattleExecBuffer) + return; + + gActiveBank = gBankAttacker; + gBankTarget = gBankAttacker ^ BIT_SIDE; + + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + { + EmitBallThrow(0, BALL_TRAINER_BLOCK); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr = BattleScript_TrainerBallBlock; + } + else if (gBattleTypeFlags & BATTLE_TYPE_WALLY_TUTORIAL) + { + EmitBallThrow(0, BALL_3_SHAKES_SUCCESS); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr = BattleScript_WallyBallThrow; + } + else + { + u32 odds; + u8 catchRate; + + if (gLastUsedItem == ITEM_SAFARI_BALL) + catchRate = gBattleStruct->field_7C * 1275 / 100; + else + catchRate = gBaseStats[gBattleMons[gBankTarget].species].catchRate; + + if (gLastUsedItem > ITEM_SAFARI_BALL) + { + switch (gLastUsedItem) + { + case ITEM_NET_BALL: + if (gBattleMons[gBankTarget].type1 == TYPE_WATER + || gBattleMons[gBankTarget].type2 == TYPE_WATER + || gBattleMons[gBankTarget].type1 == TYPE_BUG + || gBattleMons[gBankTarget].type2 == TYPE_BUG) + ballMultiplier = 30; + else + ballMultiplier = 10; + break; + case ITEM_DIVE_BALL: + if (sav1_map_get_light_level() == 5) + ballMultiplier = 35; + else + ballMultiplier = 10; + break; + case ITEM_NEST_BALL: + if (gBattleMons[gBankTarget].level <= 39) + { + ballMultiplier = 40 - gBattleMons[gBankTarget].level; + if (ballMultiplier <= 9) + ballMultiplier = 10; + } + else + { + ballMultiplier = 10; + } + break; + case ITEM_REPEAT_BALL: + if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gBankTarget].species), FLAG_GET_CAUGHT)) + ballMultiplier = 30; + else + ballMultiplier = 10; + break; + case ITEM_TIMER_BALL: + ballMultiplier = gBattleResults.battleTurnCounter + 10; + if (ballMultiplier > 40) + ballMultiplier = 40; + break; + case ITEM_LUXURY_BALL: + case ITEM_PREMIER_BALL: + ballMultiplier = 10; + break; + } + } + else + ballMultiplier = sBallCatchBonuses[gLastUsedItem - 2]; + + odds = (catchRate * ballMultiplier / 10) + * (gBattleMons[gBankTarget].maxHP * 3 - gBattleMons[gBankTarget].hp * 2) + / (3 * gBattleMons[gBankTarget].maxHP); + + if (gBattleMons[gBankTarget].status1 & (STATUS_SLEEP | STATUS_FREEZE)) + odds *= 2; + if (gBattleMons[gBankTarget].status1 & (STATUS_POISON | STATUS_BURN | STATUS_PARALYSIS | STATUS_TOXIC_POISON)) + odds = (odds * 15) / 10; + + if (gLastUsedItem != ITEM_SAFARI_BALL) + { + if (gLastUsedItem == ITEM_MASTER_BALL) + { + gBattleResults.unk5_1 = 1; + } + else + { + if (gBattleResults.catchAttempts[gLastUsedItem - ITEM_ULTRA_BALL] < 0xFF) + gBattleResults.catchAttempts[gLastUsedItem - ITEM_ULTRA_BALL]++; + } + } + + if (odds > 254) // mon caught + { + EmitBallThrow(0, BALL_3_SHAKES_SUCCESS); + MarkBufferBankForExecution(gActiveBank); + gBattlescriptCurrInstr = BattleScript_SuccessBallThrow; + SetMonData(&gEnemyParty[gBattlePartyID[gBankTarget]], MON_DATA_POKEBALL, &gLastUsedItem); + + if (CalculatePlayerPartyCount() == 6) + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + else // mon may be caught, calculate shakes + { + u8 shakes; + + odds = Sqrt(Sqrt(16711680 / odds)); + odds = 1048560 / odds; + + for (shakes = 0; shakes < 4 && Random() < odds; shakes++); + + if (gLastUsedItem == ITEM_MASTER_BALL) + shakes = BALL_3_SHAKES_SUCCESS; // why calculate the shakes before that check? + + EmitBallThrow(0, shakes); + MarkBufferBankForExecution(gActiveBank); + + if (shakes == BALL_3_SHAKES_SUCCESS) // mon caught, copy of the code above + { + gBattlescriptCurrInstr = BattleScript_SuccessBallThrow; + SetMonData(&gEnemyParty[gBattlePartyID[gBankTarget]], MON_DATA_POKEBALL, &gLastUsedItem); + + if (CalculatePlayerPartyCount() == 6) + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + else // not caught + { + gBattleCommunication[MULTISTRING_CHOOSER] = shakes; + gBattlescriptCurrInstr = BattleScript_ShakeBallThrow; + } + } + } +} + +static void atkF0_give_caught_mon(void) +{ + if (GiveMonToPlayer(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]]) != MON_GIVEN_TO_PARTY) + { + if (!sub_813B21C()) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + StringCopy(gStringVar1, GetBoxNamePtr(VarGet(VAR_STORAGE_UNKNOWN))); + GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_NICKNAME, gStringVar2); + } + else + { + StringCopy(gStringVar1, GetBoxNamePtr(VarGet(VAR_STORAGE_UNKNOWN))); + GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_NICKNAME, gStringVar2); + StringCopy(gStringVar3, GetBoxNamePtr(get_unknown_box_id())); + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + } + + if (FlagGet(SYS_PC_LANETTE)) + gBattleCommunication[MULTISTRING_CHOOSER]++; + } + + gBattleResults.caughtMonSpecies = GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_SPECIES, NULL); + GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_NICKNAME, gBattleResults.caughtMonNick); + gBattleResults.caughtMonBall = GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_POKEBALL, NULL); + + gBattlescriptCurrInstr++; +} + +static void atkF1_set_caught_mon_dex_flags(void) +{ + u16 species = GetMonData(&gEnemyParty[0], MON_DATA_SPECIES, NULL); + u32 personality = GetMonData(&gEnemyParty[0], MON_DATA_PERSONALITY, NULL); + + if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_GET_CAUGHT)) + { + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + else + { + HandleSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_SET_CAUGHT, personality); + gBattlescriptCurrInstr += 5; + } +} + +static void atkF2_display_dex_info(void) +{ + u16 species = GetMonData(&gEnemyParty[0], MON_DATA_SPECIES, NULL); + + switch (gBattleCommunication[0]) + { + case 0: + BeginNormalPaletteFade(-1, 0, 0, 0x10, 0); + gBattleCommunication[0]++; + break; + case 1: + if (!gPaletteFade.active) + { + FreeAllWindowBuffers(); + gBattleCommunication[TASK_ID] = CreateDexDisplayMonDataTask(SpeciesToNationalPokedexNum(species), + gBattleMons[gBankTarget].otId, + gBattleMons[gBankTarget].personality); + gBattleCommunication[0]++; + } + break; + case 2: + if (!gPaletteFade.active + && gMain.callback2 == BattleMainCB2 + && !gTasks[gBattleCommunication[TASK_ID]].isActive) + { + SetVBlankCallback(VBlankCB_Battle); + gBattleCommunication[0]++; + } + break; + case 3: + c2_berry_program_update_menu(); + sub_8035AA4(); + gBattle_BG3_X = 0x100; + gBattleCommunication[0]++; + break; + case 4: + if (!IsDma3ManagerBusyWithBgCopy()) + { + BeginNormalPaletteFade(0xFFFF, 0, 0x10, 0, 0); + ShowBg(0); + ShowBg(3); + gBattleCommunication[0]++; + } + break; + case 5: + if (!gPaletteFade.active) + gBattlescriptCurrInstr++; + break; + } +} + +void sub_8056A3C(u8 xStart, u8 yStart, u8 xEnd, u8 yEnd, u8 flags) +{ + s32 destY, destX; + u16 var = 0; + + for (destY = yStart; destY <= yEnd; destY++) + { + for (destX = xStart; destX <= xEnd; destX++) + { + if (destY == yStart) + { + if (destX == xStart) + var = 0x1022; + else if (destX == xEnd) + var = 0x1024; + else + var = 0x1023; + } + else if (destY == yEnd) + { + if (destX == xStart) + var = 0x1028; + else if (destX == xEnd) + var = 0x102A; + else + var = 0x1029; + } + else + { + if (destX == xStart) + var = 0x1025; + else if (destX == xEnd) + var = 0x1027; + else + var = 0x1026; + } + + if (flags & 1) + var = 0; + + if (flags & 0x80) + CopyToBgTilemapBufferRect_ChangePalette(1, &var, destX, destY, 1, 1, 0x11); + else + CopyToBgTilemapBufferRect_ChangePalette(0, &var, destX, destY, 1, 1, 0x11); + } + } +} + +void BattleCreateCursorAt(u8 cursorPosition) +{ + u16 src[2]; + src[0] = 1; + src[1] = 2; + + CopyToBgTilemapBufferRect_ChangePalette(0, src, 0x19, 9 + (2 * cursorPosition), 1, 2, 0x11); + CopyBgTilemapBufferToVram(0); +} + +void BattleDestroyCursorAt(u8 cursorPosition) +{ + u16 src[2]; + src[0] = 0x1016; + src[1] = 0x1016; + + CopyToBgTilemapBufferRect_ChangePalette(0, src, 0x19, 9 + (2 * cursorPosition), 1, 2, 0x11); + CopyBgTilemapBufferToVram(0); +} + +static void atkF3_nickname_caught_poke(void) +{ + switch (gBattleCommunication[MULTIUSE_STATE]) + { + case 0: + sub_8056A3C(0x18, 8, 0x1D, 0xD, 0); + sub_814F9EC(gText_BattleYesNoChoice, 0xC); + gBattleCommunication[MULTIUSE_STATE]++; + gBattleCommunication[CURSOR_POSITION] = 0; + BattleCreateCursorAt(0); + break; + case 1: + if (gMain.newKeys & DPAD_UP && gBattleCommunication[CURSOR_POSITION] != 0) + { + PlaySE(SE_SELECT); + BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); + gBattleCommunication[CURSOR_POSITION] = 0; + BattleCreateCursorAt(0); + } + if (gMain.newKeys & DPAD_DOWN && gBattleCommunication[CURSOR_POSITION] == 0) + { + PlaySE(SE_SELECT); + BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]); + gBattleCommunication[CURSOR_POSITION] = 1; + BattleCreateCursorAt(1); + } + if (gMain.newKeys & A_BUTTON) + { + PlaySE(SE_SELECT); + if (gBattleCommunication[CURSOR_POSITION] == 0) + { + gBattleCommunication[MULTIUSE_STATE]++; + BeginFastPaletteFade(3); + } + else + { + gBattleCommunication[MULTIUSE_STATE] = 4; + } + } + else if (gMain.newKeys & B_BUTTON) + { + PlaySE(SE_SELECT); + gBattleCommunication[MULTIUSE_STATE] = 4; + } + break; + case 2: + if (!gPaletteFade.active) + { + GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_NICKNAME, gBattleStruct->caughtMonNick); + FreeAllWindowBuffers(); + + DoNamingScreen(NAMING_SCREEN_CAUGHT_MON, gBattleStruct->caughtMonNick, + GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_SPECIES), + GetMonGender(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]]), + GetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_PERSONALITY, NULL), + BattleMainCB2); + + gBattleCommunication[MULTIUSE_STATE]++; + } + break; + case 3: + if (gMain.callback2 == BattleMainCB2 && !gPaletteFade.active ) + { + SetMonData(&gEnemyParty[gBattlePartyID[gBankAttacker ^ BIT_SIDE]], MON_DATA_NICKNAME, gBattleStruct->caughtMonNick); + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + } + break; + case 4: + if (CalculatePlayerPartyCount() == 6) + gBattlescriptCurrInstr += 5; + else + gBattlescriptCurrInstr = BSScriptReadPtr(gBattlescriptCurrInstr + 1); + break; + } +} + +static void atkF4_subattackerhpbydmg(void) +{ + gBattleMons[gBankAttacker].hp -= gBattleMoveDamage; + gBattlescriptCurrInstr++; +} + +static void atkF5_removeattackerstatus1(void) +{ + gBattleMons[gBankAttacker].status1 = 0; + gBattlescriptCurrInstr++; +} + +static void atkF6_802BF48(void) +{ + gFightStateTracker = 0xC; +} + +static void atkF7_802BF54(void) +{ + gFightStateTracker = 0xC; + gCurrentMoveTurn = gNoOfAllBanks; +} + +static void atkF8_trainer_slide_back(void) +{ + gActiveBank = GetBankByIdentity(gBattlescriptCurrInstr[1]); + EmitTrainerSlideBack(0); + MarkBufferBankForExecution(gActiveBank); + + gBattlescriptCurrInstr += 2; +} -- cgit v1.2.3 From 4dad58648fe65b7df90da45972518222853b2e98 Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Thu, 28 Sep 2017 19:34:13 +0200 Subject: take revo suggestion --- src/battle_script_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 2e6b3dbae..e0cb3e941 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -11043,7 +11043,7 @@ static void atkEF_pokeball_catch_calculation(void) ballMultiplier = 10; break; case ITEM_NEST_BALL: - if (gBattleMons[gBankTarget].level <= 39) + if (gBattleMons[gBankTarget].level < 40) { ballMultiplier = 40 - gBattleMons[gBankTarget].level; if (ballMultiplier <= 9) -- cgit v1.2.3