pokeemerald/src/battle_2.c
2017-12-03 19:19:11 +01:00

5613 lines
186 KiB
C

#include "global.h"
#include "battle.h"
#include "recorded_battle.h"
#include "main.h"
#include "load_save.h"
#include "gpu_regs.h"
#include "unknown_task.h"
#include "battle_setup.h"
#include "battle_scripts.h"
#include "pokemon.h"
#include "palette.h"
#include "task.h"
#include "event_data.h"
#include "species.h"
#include "berry.h"
#include "text.h"
#include "item.h"
#include "items.h"
#include "hold_effects.h"
#include "link.h"
#include "bg.h"
#include "dma3.h"
#include "string_util.h"
#include "malloc.h"
#include "event_data.h"
#include "m4a.h"
#include "window.h"
#include "rng.h"
#include "songs.h"
#include "sound.h"
#include "battle_message.h"
#include "sprite.h"
#include "util.h"
#include "trig.h"
#include "battle_ai_script_commands.h"
#include "battle_move_effects.h"
#include "battle_controllers.h"
#include "pokedex.h"
#include "abilities.h"
#include "moves.h"
#include "trainer_classes.h"
#include "evolution_scene.h"
#include "roamer.h"
#include "tv.h"
#include "safari_zone.h"
#include "battle_string_ids.h"
#include "data2.h"
struct UnknownStruct6
{
u16 unk0[0xA0];
u8 fillerA0[0x640];
u16 unk780[0xA0];
};
struct UnknownPokemonStruct2
{
/*0x00*/ u16 species;
/*0x02*/ u16 heldItem;
/*0x04*/ u8 nickname[POKEMON_NAME_LENGTH + 1];
/*0x0F*/ u8 level;
/*0x10*/ u16 hp;
/*0x12*/ u16 maxhp;
/*0x14*/ u32 status;
/*0x18*/ u32 personality;
/*0x1C*/ u8 gender;
/*0x1D*/ u8 language;
};
extern u8 gBattleCommunication[];
extern u8 gBattleTerrain;
extern u16 gBattle_BG0_X;
extern u16 gBattle_BG0_Y;
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 u16 gBattle_BG3_Y;
extern u16 gPartnerTrainerId;
extern u16 gBattle_WIN0H;
extern u16 gBattle_WIN0V;
extern u16 gBattle_WIN1H;
extern u16 gBattle_WIN1V;
extern u16 gTrainerBattleOpponent_A;
extern u16 gTrainerBattleOpponent_B;
extern struct BattleEnigmaBerry gEnigmaBerries[BATTLE_BANKS_COUNT];
extern void (*gPreBattleCallback1)(void);
extern void (*gBattleMainFunc)(void);
extern void (*gCB2_AfterEvolution)(void);
extern struct UnknownPokemonStruct2 gUnknown_02022FF8[3]; // what is it used for?
extern struct UnknownPokemonStruct2* gUnknown_02023058; // what is it used for?
extern u8 gUnknown_02039B28[]; // possibly a struct?
extern struct UnknownStruct6 gUnknown_02038C28; // todo: identify & document
extern struct MusicPlayerInfo gMPlay_SE1;
extern struct MusicPlayerInfo gMPlay_SE2;
extern u8 gDecompressionBuffer[];
extern u16 gUnknown_020243FC;
extern u8 gHealthBoxesIds[BATTLE_BANKS_COUNT];
extern void (*gBattleBankFunc[BATTLE_BANKS_COUNT])(void);
extern u8 gBattleBufferA[BATTLE_BANKS_COUNT][0x200];
extern u8 gBattleBufferB[BATTLE_BANKS_COUNT][0x200];
extern u8 gStringBank;
extern u32 gUnknown_02022F88;
extern u32 gHitMarker;
extern u16 gBattlePartyID[BATTLE_BANKS_COUNT];
extern u8 gBattleMonForms[BATTLE_BANKS_COUNT];
extern u8 gBankSpriteIds[BATTLE_BANKS_COUNT];
extern u16 gPaydayMoney;
extern u16 gBattleWeather;
extern u16 gPauseCounterBattle;
extern u16 gRandomTurnNumber;
extern u8 gActiveBank;
extern u8 gNoOfAllBanks;
extern u8 gBankAttacker;
extern u8 gBankTarget;
extern u8 gLeveledUpInBattle;
extern u8 gAbsentBankFlags;
extern u32 gBattleExecBuffer;
extern u8 gMultiHitCounter;
extern u8 gBattleMoveFlags;
extern s32 gBattleMoveDamage;
extern const u8* gPalaceSelectionBattleScripts[BATTLE_BANKS_COUNT];
extern u16 gLastPrintedMoves[BATTLE_BANKS_COUNT];
extern u16 gLastMoves[BATTLE_BANKS_COUNT];
extern u16 gLastLandedMoves[BATTLE_BANKS_COUNT];
extern u16 gLastHitByType[BATTLE_BANKS_COUNT];
extern u16 gLastResultingMoves[BATTLE_BANKS_COUNT];
extern u16 gLockedMoves[BATTLE_BANKS_COUNT];
extern u8 gLastHitBy[BATTLE_BANKS_COUNT];
extern u8 gUnknown_02024284[BATTLE_BANKS_COUNT];
extern u32 gStatuses3[BATTLE_BANKS_COUNT];
extern u16 gSideAffecting[2];
extern u16 gCurrentMove;
extern u8 gActionSelectionCursor[BATTLE_BANKS_COUNT];
extern u8 gMoveSelectionCursor[BATTLE_BANKS_COUNT];
extern struct BattlePokemon gBattleMons[BATTLE_BANKS_COUNT];
extern u8 gBanksByTurnOrder[BATTLE_BANKS_COUNT];
extern u8 gActionForBanks[BATTLE_BANKS_COUNT];
extern u16 gChosenMovesByBanks[BATTLE_BANKS_COUNT];
extern u8 gCurrentActionFuncId;
extern u8 gLastUsedAbility;
extern u8 gUnknown_0203CF00[];
extern const u8* gSelectionBattleScripts[BATTLE_BANKS_COUNT];
extern const u8* gBattlescriptCurrInstr;
extern u8 gActionsByTurnOrder[BATTLE_BANKS_COUNT];
extern u8 gCurrentTurnActionNumber;
extern u16 gDynamicBasePower;
extern u8 gCritMultiplier;
extern u8 gCurrMovePos;
extern u8 gUnknown_020241E9;
extern u16 gChosenMove;
extern const struct BattleMove gBattleMoves[];
extern const u16 gUnknown_08C004E0[]; // battle textbox palette
extern const struct BgTemplate gUnknown_0831AA08[];
extern const struct WindowTemplate * const gUnknown_0831ABA0[];
extern const u8 gUnknown_0831ACE0[];
extern const u8 gStatStageRatios[][2];
extern const u8 * const gBattleScriptsForMoveEffects[];
extern const u8 * const gBattlescriptsForBallThrow[];
extern const u8 * const gBattlescriptsForRunningByItem[];
extern const u8 * const gUnknown_082DBD3C[];
extern const u8 * const gBattlescriptsForSafariActions[];
// strings
extern const u8 gText_LinkStandby3[];
extern const u8 gText_RecordBattleToPass[];
extern const u8 gText_BattleYesNoChoice[];
extern const u8 gText_BattleRecordCouldntBeSaved[];
extern const u8 gText_BattleRecordedOnPass[];
extern const u8 gText_ShedinjaJapaneseName[];
extern const u8 gText_EmptyString3[];
extern const u8 gText_Poison[];
extern const u8 gText_Sleep[];
extern const u8 gText_Paralysis[];
extern const u8 gText_Burn[];
extern const u8 gText_Ice[];
extern const u8 gText_Confusion[];
extern const u8 gText_Love[];
// functions
extern void dp12_8087EA4(void);
extern void sub_80356D0(void);
extern void GetFrontierTrainerName(u8* dst, u16 trainerId); // battle tower
extern void sub_8166188(void); // battle tower, sets link battle mons level but why?
extern void sub_8165B88(u8* dst, u16 trainerId); // battle tower, gets language
extern void PadNameString(u8* dst, u8 arg2); //
extern void sub_81B9150(void);
extern void sub_800AC34(void);
extern void sub_80B3AF8(u8 taskId); // cable club
extern void sub_8076918(u8 bank);
extern void SetHealthboxSpriteVisible(u8 healthoxSpriteId);
extern void sub_81A56B4(void); // battle frontier 2
extern u8 sub_81A9E28(void); // battle frontier 2
extern void sub_81A56E8(u8 bank); // battle frontier 2
extern void sub_81B8FB0(u8, u8); // party menu
extern u8 pokemon_order_func(u8); // party menu
extern bool8 InBattlePyramid(void);
// this file's functions
static void CB2_InitBattleInternal(void);
static void CB2_PreInitMultiBattle(void);
static void CB2_PreInitIngamePlayerPartnerBattle(void);
static void CB2_HandleStartMultiPartnerBattle(void);
static void CB2_HandleStartMultiBattle(void);
static void CB2_HandleStartBattle(void);
static void TryCorrectShedinjaLanguage(struct Pokemon *mon);
static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 firstTrainer);
static void BattleMainCB1(void);
static void sub_8038538(struct Sprite *sprite);
static void sub_8038F14(void);
static void sub_8038F34(void);
static void sub_80392A8(void);
static void sub_803937C(void);
static void sub_803939C(void);
static void sub_803980C(struct Sprite *sprite);
static void sub_8039838(struct Sprite *sprite);
static void sub_8039894(struct Sprite *sprite);
static void sub_80398D0(struct Sprite *sprite);
static void sub_8039A48(struct Sprite *sprite);
static void sub_8039AF4(struct Sprite *sprite);
static void SpriteCallbackDummy_3(struct Sprite *sprite);
static void oac_poke_ally_(struct Sprite *sprite);
static void SpecialStatusesClear(void);
static void TurnValuesCleanUp(bool8 var0);
static void SpriteCB_HealthBoxBounce(struct Sprite *sprite);
static void BattleStartClearSetData(void);
static void BattleIntroGetMonsData(void);
static void BattleIntroPrepareBackgroundSlide(void);
static void BattleIntroDrawTrainersOrMonsSprites(void);
static void BattleIntroDrawPartySummaryScreens(void);
static void BattleIntroPrintTrainerWantsToBattle(void);
static void BattleIntroPrintWildMonAttacked(void);
static void BattleIntroPrintOpponentSendsOut(void);
static void BattleIntroPrintPlayerSendsOut(void);
static void BattleIntroOpponent1SendsOutMonAnimation(void);
static void BattleIntroOpponent2SendsOutMonAnimation(void);
static void BattleIntroRecordMonsToDex(void);
static void BattleIntroPlayer1SendsOutMonAnimation(void);
static void TryDoEventsBeforeFirstTurn(void);
static void HandleTurnActionSelectionState(void);
static void RunTurnActionsFunctions(void);
static void SetActionsAndBanksTurnOrder(void);
static void sub_803CDF8(void);
static bool8 sub_803CDB8(void);
static void CheckFocusPunch_ClearVarsBeforeTurnStarts(void);
static void FreeResetData_ReturnToOvOrDoEvolutions(void);
static void ReturnFromBattleToOverworld(void);
static void TryEvolvePokemon(void);
static void WaitForEvoSceneToFinish(void);
static void HandleEndTurn_ContinueBattle(void);
static void HandleEndTurn_BattleWon(void);
static void HandleEndTurn_BattleLost(void);
static void HandleEndTurn_RanFromBattle(void);
static void HandleEndTurn_MonFled(void);
static void HandleEndTurn_FinishBattle(void);
static void HandleAction_UseMove(void);
static void HandleAction_Switch(void);
static void HandleAction_UseItem(void);
static void HandleAction_Run(void);
static void HandleAction_WatchesCarefully(void);
static void HandleAction_SafariZoneBallThrow(void);
static void HandleAction_ThrowPokeblock(void);
static void HandleAction_GoNear(void);
static void HandleAction_SafriZoneRun(void);
static void HandleAction_Action9(void);
static void HandleAction_Action11(void);
static void HandleAction_NothingIsFainted(void);
static void HandleAction_ActionFinished(void);
// rom const data
static void (* const sTurnActionsFuncsTable[])(void) =
{
HandleAction_UseMove, // ACTION_USE_MOVE
HandleAction_UseItem, // ACTION_USE_ITEM
HandleAction_Switch, // ACTION_SWITCH
HandleAction_Run, // ACTION_RUN
HandleAction_WatchesCarefully, // ACTION_WATCHES_CAREFULLY
HandleAction_SafariZoneBallThrow, // ACTION_SAFARI_ZONE_BALL
HandleAction_ThrowPokeblock, // ACTION_POKEBLOCK_CASE
HandleAction_GoNear, // ACTION_GO_NEAR
HandleAction_SafriZoneRun, // ACTION_SAFARI_ZONE_RUN
HandleAction_Action9, // ACTION_9
HandleAction_RunBattleScript, // ACTION_RUN_BATTLESCRIPT
HandleAction_Action11, // not sure about this one
HandleAction_ActionFinished, // ACTION_FINISHED
HandleAction_NothingIsFainted, // ACTION_NOTHING_FAINTED
};
static void (* const sEndTurnFuncsTable[])(void) =
{
HandleEndTurn_ContinueBattle, // battle outcome 0
HandleEndTurn_BattleWon, // BATTLE_WON
HandleEndTurn_BattleLost, // BATTLE_LOST
HandleEndTurn_BattleLost, // BATTLE_DREW
HandleEndTurn_RanFromBattle, // BATTLE_RAN
HandleEndTurn_FinishBattle, // BATTLE_PLAYER_TELEPORTED
HandleEndTurn_MonFled, // BATTLE_POKE_FLED
HandleEndTurn_FinishBattle, // BATTLE_CAUGHT
HandleEndTurn_FinishBattle, // battle outcome 8
HandleEndTurn_FinishBattle, // BATTLE_FORFEITED
HandleEndTurn_FinishBattle, // BATTLE_OPPONENT_TELEPORTED
};
const u8 gStatusConditionString_PoisonJpn[8] = _("どく$$$$$");
const u8 gStatusConditionString_SleepJpn[8] = _("ねむり$$$$");
const u8 gStatusConditionString_ParalysisJpn[8] = _("まひ$$$$$");
const u8 gStatusConditionString_BurnJpn[8] = _("やけど$$$$");
const u8 gStatusConditionString_IceJpn[8] = _("こおり$$$$");
const u8 gStatusConditionString_ConfusionJpn[8] = _("こんらん$$$");
const u8 gStatusConditionString_LoveJpn[8] = _("メロメロ$$$");
const u8 * const gStatusConditionStringsTable[7][2] =
{
{gStatusConditionString_PoisonJpn, gText_Poison},
{gStatusConditionString_SleepJpn, gText_Sleep},
{gStatusConditionString_ParalysisJpn, gText_Paralysis},
{gStatusConditionString_BurnJpn, gText_Burn},
{gStatusConditionString_IceJpn, gText_Ice},
{gStatusConditionString_ConfusionJpn, gText_Confusion},
{gStatusConditionString_LoveJpn, gText_Love}
};
static const u8 sUnknown_0831BCE0[][3] = {{0, 0, 0}, {3, 5, 0}, {2, 3, 0}, {1, 2, 0}, {1, 1, 0}};
static const u8 sUnknown_0831BCEF[] = {4, 3, 2, 1};
static const u8 sUnknown_0831BCF3[] = {4, 4, 4, 4};
void CB2_InitBattle(void)
{
MoveSaveBlocks_ResetHeap();
AllocateBattleResources();
AllocateBattleSpritesData();
AllocateMonSpritesGfx();
sub_8185F84();
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
{
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED)
{
CB2_InitBattleInternal();
}
else if (!(gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER))
{
HandleLinkBattleSetup();
SetMainCallback2(CB2_PreInitMultiBattle);
}
else
{
SetMainCallback2(CB2_PreInitIngamePlayerPartnerBattle);
}
gBattleCommunication[MULTIUSE_STATE] = 0;
}
else
{
CB2_InitBattleInternal();
}
}
static void CB2_InitBattleInternal(void)
{
s32 i;
SetHBlankCallback(NULL);
SetVBlankCallback(NULL);
CpuFill32(0, (void*)(VRAM), VRAM_SIZE);
SetGpuReg(REG_OFFSET_MOSAIC, 0);
SetGpuReg(REG_OFFSET_WIN0H, 240);
SetGpuReg(REG_OFFSET_WIN0V, 0x5051);
SetGpuReg(REG_OFFSET_WININ, 0);
SetGpuReg(REG_OFFSET_WINOUT, 0);
gBattle_WIN0H = 240;
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gPartnerTrainerId != STEVEN_PARTNER_ID)
{
gBattle_WIN0V = 159;
gBattle_WIN1H = 240;
gBattle_WIN1V = 32;
}
else
{
gBattle_WIN0V = 0x5051;
dp12_8087EA4();
for (i = 0; i < 80; i++)
{
gUnknown_02038C28.unk0[i] = 0xF0;
gUnknown_02038C28.unk780[i] = 0xF0;
}
for (i = 80; i < 160; i++)
{
#ifndef NONMATCHING
asm(""::"r"(i)); // needed to match
#endif // NONMATCHING
gUnknown_02038C28.unk0[i] = 0xFF10;
gUnknown_02038C28.unk780[i] = 0xFF10;
}
sub_80BA038(gUnknown_0831AC70);
}
ResetPaletteFade();
gBattle_BG0_X = 0;
gBattle_BG0_Y = 0;
gBattle_BG1_X = 0;
gBattle_BG1_Y = 0;
gBattle_BG2_X = 0;
gBattle_BG2_Y = 0;
gBattle_BG3_X = 0;
gBattle_BG3_Y = 0;
gBattleTerrain = BattleSetup_GetTerrainId();
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED)
gBattleTerrain = BATTLE_TERRAIN_INSIDE;
sub_80356D0();
LoadBattleTextboxAndBackground();
ResetSpriteData();
ResetTasks();
LoadBattleEntryBackground();
FreeAllSpritePalettes();
gReservedSpritePaletteCount = 4;
SetVBlankCallback(VBlankCB_Battle);
SetUpBattleVarsAndBirchZigzagoon();
if (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER)
SetMainCallback2(CB2_HandleStartMultiPartnerBattle);
else if (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
SetMainCallback2(CB2_HandleStartMultiPartnerBattle);
else if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
SetMainCallback2(CB2_HandleStartMultiBattle);
else
SetMainCallback2(CB2_HandleStartBattle);
if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED)))
{
CreateNPCTrainerParty(&gEnemyParty[0], gTrainerBattleOpponent_A, TRUE);
if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
CreateNPCTrainerParty(&gEnemyParty[3], gTrainerBattleOpponent_B, FALSE);
SetWildMonHeldItem();
}
gMain.inBattle = TRUE;
gSaveBlock2Ptr->field_CA9_b = 0;
for (i = 0; i < 6; i++)
AdjustFriendship(&gPlayerParty[i], 3);
gBattleCommunication[MULTIUSE_STATE] = 0;
}
static void sub_8036A5C(void)
{
u16 r6 = 0;
u16 species = 0;
u16 hp = 0;
u32 status = 0;
s32 i;
for (i = 0; i < PARTY_SIZE; i++)
{
species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2);
hp = GetMonData(&gPlayerParty[i], MON_DATA_HP);
status = GetMonData(&gPlayerParty[i], MON_DATA_STATUS);
if (species == SPECIES_NONE)
continue;
if (species != SPECIES_EGG && hp != 0 && status == 0)
r6 |= 1 << i * 2;
if (species == SPECIES_NONE)
continue;
if (hp != 0 && (species == SPECIES_EGG || status != 0))
r6 |= 2 << i * 2;
if (species == SPECIES_NONE)
continue;
if (species != SPECIES_EGG && hp == 0)
r6 |= 3 << i * 2;
}
gBattleStruct->field_182 = r6;
*(&gBattleStruct->field_183) = r6 >> 8;
gBattleStruct->field_183 |= FlagGet(FLAG_SYS_FRONTIER_PASS) << 7;
}
static void SetPlayerBerryDataInBattleStruct(void)
{
s32 i;
struct BattleStruct *battleStruct = gBattleStruct;
struct BattleEnigmaBerry *battleBerry = &battleStruct->battleEnigmaBerry;
if (IsEnigmaBerryValid() == TRUE)
{
for (i = 0; i < BERRY_NAME_COUNT - 1; i++)
battleBerry->name[i] = gSaveBlock1Ptr->enigmaBerry.berry.name[i];
battleBerry->name[i] = EOS;
for (i = 0; i < BERRY_ITEM_EFFECT_COUNT; i++)
battleBerry->itemEffect[i] = gSaveBlock1Ptr->enigmaBerry.itemEffect[i];
battleBerry->holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect;
battleBerry->holdEffectParam = gSaveBlock1Ptr->enigmaBerry.holdEffectParam;
}
else
{
const struct Berry* berryData = GetBerryInfo(ItemIdToBerryType(ITEM_ENIGMA_BERRY));
for (i = 0; i < BERRY_NAME_COUNT - 1; i++)
battleBerry->name[i] = berryData->name[i];
battleBerry->name[i] = EOS;
for (i = 0; i < BERRY_ITEM_EFFECT_COUNT; i++)
battleBerry->itemEffect[i] = 0;
battleBerry->holdEffect = HOLD_EFFECT_NONE;
battleBerry->holdEffectParam = 0;
}
}
static void SetAllPlayersBerryData(void)
{
s32 i;
s32 j;
if (!(gBattleTypeFlags & BATTLE_TYPE_LINK))
{
if (IsEnigmaBerryValid() == TRUE)
{
for (i = 0; i < BERRY_NAME_COUNT - 1; i++)
{
gEnigmaBerries[0].name[i] = gSaveBlock1Ptr->enigmaBerry.berry.name[i];
gEnigmaBerries[2].name[i] = gSaveBlock1Ptr->enigmaBerry.berry.name[i];
}
gEnigmaBerries[0].name[i] = EOS;
gEnigmaBerries[2].name[i] = EOS;
for (i = 0; i < BERRY_ITEM_EFFECT_COUNT; i++)
{
gEnigmaBerries[0].itemEffect[i] = gSaveBlock1Ptr->enigmaBerry.itemEffect[i];
gEnigmaBerries[2].itemEffect[i] = gSaveBlock1Ptr->enigmaBerry.itemEffect[i];
}
gEnigmaBerries[0].holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect;
gEnigmaBerries[2].holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect;
gEnigmaBerries[0].holdEffectParam = gSaveBlock1Ptr->enigmaBerry.holdEffectParam;
gEnigmaBerries[2].holdEffectParam = gSaveBlock1Ptr->enigmaBerry.holdEffectParam;
}
else
{
const struct Berry* berryData = GetBerryInfo(ItemIdToBerryType(ITEM_ENIGMA_BERRY));
for (i = 0; i < BERRY_NAME_COUNT - 1; i++)
{
gEnigmaBerries[0].name[i] = berryData->name[i];
gEnigmaBerries[2].name[i] = berryData->name[i];
}
gEnigmaBerries[0].name[i] = EOS;
gEnigmaBerries[2].name[i] = EOS;
for (i = 0; i < BERRY_ITEM_EFFECT_COUNT; i++)
{
gEnigmaBerries[0].itemEffect[i] = 0;
gEnigmaBerries[2].itemEffect[i] = 0;
}
gEnigmaBerries[0].holdEffect = 0;
gEnigmaBerries[2].holdEffect = 0;
gEnigmaBerries[0].holdEffectParam = 0;
gEnigmaBerries[2].holdEffectParam = 0;
}
}
else
{
s32 numPlayers;
struct BattleEnigmaBerry *src;
u8 r4;
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
{
if (gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER)
numPlayers = 2;
else
numPlayers = 4;
for (i = 0; i < numPlayers; i++)
{
src = (struct BattleEnigmaBerry *)(gBlockRecvBuffer[i] + 2);
r4 = gLinkPlayers[i].lp_field_18;
for (j = 0; j < BERRY_NAME_COUNT - 1; j++)
gEnigmaBerries[r4].name[j] = src->name[j];
gEnigmaBerries[r4].name[j] = EOS;
for (j = 0; j < BERRY_ITEM_EFFECT_COUNT; j++)
gEnigmaBerries[r4].itemEffect[j] = src->itemEffect[j];
gEnigmaBerries[r4].holdEffect = src->holdEffect;
gEnigmaBerries[r4].holdEffectParam = src->holdEffectParam;
}
}
else
{
for (i = 0; i < 2; i++)
{
src = (struct BattleEnigmaBerry *)(gBlockRecvBuffer[i] + 2);
for (j = 0; j < BERRY_NAME_COUNT - 1; j++)
{
gEnigmaBerries[i].name[j] = src->name[j];
gEnigmaBerries[i + 2].name[j] = src->name[j];
}
gEnigmaBerries[i].name[j] = EOS;
gEnigmaBerries[i + 2].name[j] = EOS;
for (j = 0; j < BERRY_ITEM_EFFECT_COUNT; j++)
{
gEnigmaBerries[i].itemEffect[j] = src->itemEffect[j];
gEnigmaBerries[i + 2].itemEffect[j] = src->itemEffect[j];
}
gEnigmaBerries[i].holdEffect = src->holdEffect;
gEnigmaBerries[i + 2].holdEffect = src->holdEffect;
gEnigmaBerries[i].holdEffectParam = src->holdEffectParam;
gEnigmaBerries[i + 2].holdEffectParam = src->holdEffectParam;
}
}
}
}
static void sub_8036EB8(u8 arg0, u8 arg1)
{
u8 var = 0;
if (gBlockRecvBuffer[0][0] == 256)
{
if (arg1 == 0)
gBattleTypeFlags |= BATTLE_TYPE_WILD | BATTLE_TYPE_TRAINER;
else
gBattleTypeFlags |= BATTLE_TYPE_TRAINER;
var++;
}
if (var == 0)
{
s32 i;
for (i = 0; i < arg0; i++)
{
if (gBlockRecvBuffer[0][0] != gBlockRecvBuffer[i][0])
break;
}
if (i == arg0)
{
if (arg1 == 0)
gBattleTypeFlags |= BATTLE_TYPE_WILD | BATTLE_TYPE_TRAINER;
else
gBattleTypeFlags |= BATTLE_TYPE_TRAINER;
var++;
}
if (var == 0)
{
for (i = 0; i < arg0; i++)
{
if (gBlockRecvBuffer[i][0] == 0x300)
{
if (i != arg1 && i < arg1)
break;
}
if (gBlockRecvBuffer[i][0] > 0x300 && i != arg1)
break;
}
if (i == arg0)
gBattleTypeFlags |= BATTLE_TYPE_WILD | BATTLE_TYPE_TRAINER;
else
gBattleTypeFlags |= BATTLE_TYPE_TRAINER;
}
}
}
static void CB2_HandleStartBattle(void)
{
u8 playerMultiplayerId;
u8 enemyMultiplayerId;
RunTasks();
AnimateSprites();
BuildOamBuffer();
playerMultiplayerId = GetMultiplayerId();
gBattleScripting.multiplayerId = playerMultiplayerId;
enemyMultiplayerId = playerMultiplayerId ^ BIT_SIDE;
switch (gBattleCommunication[MULTIUSE_STATE])
{
case 0:
if (!IsDma3ManagerBusyWithBgCopy())
{
ShowBg(0);
ShowBg(1);
ShowBg(2);
ShowBg(3);
sub_805EF14();
gBattleCommunication[MULTIUSE_STATE] = 1;
}
if (gLinkVSyncDisabled)
sub_800E0E8();
break;
case 1:
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
{
if (gReceivedRemoteLinkPlayers != 0)
{
if (sub_800A520())
{
*(&gBattleStruct->field_180) = 0;
*(&gBattleStruct->field_181) = 3;
sub_8036A5C();
SetPlayerBerryDataInBattleStruct();
if (gTrainerBattleOpponent_A == TRAINER_OPPONENT_C00)
{
gLinkPlayers[0].lp_field_18 = 0;
gLinkPlayers[1].lp_field_18 = 1;
}
SendBlock(bitmask_all_link_players_but_self(), &gBattleStruct->field_180, 32);
gBattleCommunication[MULTIUSE_STATE] = 2;
}
if (gLinkVSyncDisabled)
sub_800DFB4(0, 0);
}
}
else
{
if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED))
gBattleTypeFlags |= BATTLE_TYPE_WILD;
gBattleCommunication[MULTIUSE_STATE] = 15;
SetAllPlayersBerryData();
}
break;
case 2:
if ((GetBlockReceivedStatus() & 3) == 3)
{
u8 taskId;
ResetBlockReceivedFlags();
sub_8036EB8(2, playerMultiplayerId);
SetAllPlayersBerryData();
taskId = CreateTask(task00_0800F6FC, 0);
gTasks[taskId].data[1] = 0x10E;
gTasks[taskId].data[2] = 0x5A;
gTasks[taskId].data[5] = 0;
gTasks[taskId].data[3] = gBattleStruct->field_182 | (gBattleStruct->field_183 << 8);
gTasks[taskId].data[4] = gBlockRecvBuffer[enemyMultiplayerId][1];
sub_8185F90(gBlockRecvBuffer[playerMultiplayerId][1]);
sub_8185F90(gBlockRecvBuffer[enemyMultiplayerId][1]);
sub_8068AA4();
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 3:
if (sub_800A520())
{
SendBlock(bitmask_all_link_players_but_self(), gPlayerParty, sizeof(struct Pokemon) * 2);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 4:
if ((GetBlockReceivedStatus() & 3) == 3)
{
ResetBlockReceivedFlags();
memcpy(gEnemyParty, gBlockRecvBuffer[enemyMultiplayerId], sizeof(struct Pokemon) * 2);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 7:
if (sub_800A520())
{
SendBlock(bitmask_all_link_players_but_self(), gPlayerParty + 2, sizeof(struct Pokemon) * 2);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 8:
if ((GetBlockReceivedStatus() & 3) == 3)
{
ResetBlockReceivedFlags();
memcpy(gEnemyParty + 2, gBlockRecvBuffer[enemyMultiplayerId], sizeof(struct Pokemon) * 2);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 11:
if (sub_800A520())
{
SendBlock(bitmask_all_link_players_but_self(), gPlayerParty + 4, sizeof(struct Pokemon) * 2);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 12:
if ((GetBlockReceivedStatus() & 3) == 3)
{
ResetBlockReceivedFlags();
memcpy(gEnemyParty + 4, gBlockRecvBuffer[enemyMultiplayerId], sizeof(struct Pokemon) * 2);
TryCorrectShedinjaLanguage(&gEnemyParty[0]);
TryCorrectShedinjaLanguage(&gEnemyParty[1]);
TryCorrectShedinjaLanguage(&gEnemyParty[2]);
TryCorrectShedinjaLanguage(&gEnemyParty[3]);
TryCorrectShedinjaLanguage(&gEnemyParty[4]);
TryCorrectShedinjaLanguage(&gEnemyParty[5]);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 15:
sub_8032768();
sub_8184E58();
gBattleCommunication[SPRITES_INIT_STATE1] = 0;
gBattleCommunication[SPRITES_INIT_STATE2] = 0;
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
{
s32 i;
for (i = 0; i < 2 && (gLinkPlayers[i].version & 0xFF) == VERSION_EMERALD; i++);
if (i == 2)
gBattleCommunication[MULTIUSE_STATE] = 16;
else
gBattleCommunication[MULTIUSE_STATE] = 18;
}
else
{
gBattleCommunication[MULTIUSE_STATE] = 18;
}
break;
case 16:
if (sub_800A520())
{
SendBlock(bitmask_all_link_players_but_self(), &gRecordedBattleRngSeed, sizeof(gRecordedBattleRngSeed));
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 17:
if ((GetBlockReceivedStatus() & 3) == 3)
{
ResetBlockReceivedFlags();
if (!(gBattleTypeFlags & BATTLE_TYPE_WILD))
memcpy(&gRecordedBattleRngSeed, gBlockRecvBuffer[enemyMultiplayerId], sizeof(gRecordedBattleRngSeed));
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 18:
if (BattleInitAllSprites(&gBattleCommunication[SPRITES_INIT_STATE1], &gBattleCommunication[SPRITES_INIT_STATE2]))
{
gPreBattleCallback1 = gMain.callback1;
gMain.callback1 = BattleMainCB1;
SetMainCallback2(BattleMainCB2);
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
{
gBattleTypeFlags |= BATTLE_TYPE_20;
}
}
break;
case 5:
case 9:
case 13:
gBattleCommunication[MULTIUSE_STATE]++;
gBattleCommunication[1] = 1;
case 6:
case 10:
case 14:
if (--gBattleCommunication[1] == 0)
gBattleCommunication[MULTIUSE_STATE]++;
break;
}
}
static void CB2_HandleStartMultiPartnerBattle(void)
{
u8 playerMultiplayerId;
u8 enemyMultiplayerId;
RunTasks();
AnimateSprites();
BuildOamBuffer();
playerMultiplayerId = GetMultiplayerId();
gBattleScripting.multiplayerId = playerMultiplayerId;
enemyMultiplayerId = playerMultiplayerId ^ BIT_SIDE;
switch (gBattleCommunication[MULTIUSE_STATE])
{
case 0:
if (!IsDma3ManagerBusyWithBgCopy())
{
ShowBg(0);
ShowBg(1);
ShowBg(2);
ShowBg(3);
sub_805EF14();
gBattleCommunication[MULTIUSE_STATE] = 1;
}
if (gLinkVSyncDisabled)
sub_800E0E8();
// fall through
case 1:
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
{
if (gReceivedRemoteLinkPlayers != 0)
{
u8 language;
gLinkPlayers[0].lp_field_18 = 0;
gLinkPlayers[1].lp_field_18 = 2;
gLinkPlayers[2].lp_field_18 = 1;
gLinkPlayers[3].lp_field_18 = 3;
GetFrontierTrainerName(gLinkPlayers[2].name, gTrainerBattleOpponent_A);
GetFrontierTrainerName(gLinkPlayers[3].name, gTrainerBattleOpponent_B);
sub_8165B88(&language, gTrainerBattleOpponent_A);
gLinkPlayers[2].language = language;
sub_8165B88(&language, gTrainerBattleOpponent_B);
gLinkPlayers[3].language = language;
if (sub_800A520())
{
*(&gBattleStruct->field_180) = 0;
*(&gBattleStruct->field_181) = 3;
sub_8036A5C();
SetPlayerBerryDataInBattleStruct();
SendBlock(bitmask_all_link_players_but_self(), &gBattleStruct->field_180, 32);
gBattleCommunication[MULTIUSE_STATE] = 2;
}
if (gLinkVSyncDisabled)
sub_800DFB4(0, 0);
}
}
else
{
if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED))
gBattleTypeFlags |= BATTLE_TYPE_WILD;
gBattleCommunication[MULTIUSE_STATE] = 13;
SetAllPlayersBerryData();
}
break;
case 2:
if ((GetBlockReceivedStatus() & 3) == 3)
{
u8 taskId;
ResetBlockReceivedFlags();
sub_8036EB8(2, playerMultiplayerId);
SetAllPlayersBerryData();
taskId = CreateTask(task00_0800F6FC, 0);
gTasks[taskId].data[1] = 0x10E;
gTasks[taskId].data[2] = 0x5A;
gTasks[taskId].data[5] = 0;
gTasks[taskId].data[3] = 0x145;
gTasks[taskId].data[4] = 0x145;
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 3:
if (sub_800A520())
{
SendBlock(bitmask_all_link_players_but_self(), gPlayerParty, sizeof(struct Pokemon) * 2);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 4:
if ((GetBlockReceivedStatus() & 3) == 3)
{
ResetBlockReceivedFlags();
if (gLinkPlayers[playerMultiplayerId].lp_field_18 != 0)
{
memcpy(gPlayerParty, gBlockRecvBuffer[enemyMultiplayerId], sizeof(struct Pokemon) * 2);
memcpy(gPlayerParty + 3, gBlockRecvBuffer[playerMultiplayerId], sizeof(struct Pokemon) * 2);
}
else
{
memcpy(gPlayerParty, gBlockRecvBuffer[playerMultiplayerId], sizeof(struct Pokemon) * 2);
memcpy(gPlayerParty + 3, gBlockRecvBuffer[enemyMultiplayerId], sizeof(struct Pokemon) * 2);
}
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 5:
if (sub_800A520())
{
SendBlock(bitmask_all_link_players_but_self(), gPlayerParty + 2, sizeof(struct Pokemon));
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 6:
if ((GetBlockReceivedStatus() & 3) == 3)
{
ResetBlockReceivedFlags();
if (gLinkPlayers[playerMultiplayerId].lp_field_18 != 0)
{
memcpy(gPlayerParty + 2, gBlockRecvBuffer[enemyMultiplayerId], sizeof(struct Pokemon));
memcpy(gPlayerParty + 5, gBlockRecvBuffer[playerMultiplayerId], sizeof(struct Pokemon));
}
else
{
memcpy(gPlayerParty + 2, gBlockRecvBuffer[playerMultiplayerId], sizeof(struct Pokemon));
memcpy(gPlayerParty + 5, gBlockRecvBuffer[enemyMultiplayerId], sizeof(struct Pokemon));
}
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 7:
if (sub_800A520())
{
SendBlock(bitmask_all_link_players_but_self(), gEnemyParty, sizeof(struct Pokemon) * 2);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 8:
if ((GetBlockReceivedStatus() & 3) == 3)
{
ResetBlockReceivedFlags();
if (GetMultiplayerId() != 0)
{
memcpy(gEnemyParty, gBlockRecvBuffer[0], sizeof(struct Pokemon) * 2);
}
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 9:
if (sub_800A520())
{
SendBlock(bitmask_all_link_players_but_self(), gEnemyParty + 2, sizeof(struct Pokemon) * 2);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 10:
if ((GetBlockReceivedStatus() & 3) == 3)
{
ResetBlockReceivedFlags();
if (GetMultiplayerId() != 0)
{
memcpy(gEnemyParty + 2, gBlockRecvBuffer[0], sizeof(struct Pokemon) * 2);
}
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 11:
if (sub_800A520())
{
SendBlock(bitmask_all_link_players_but_self(), gEnemyParty + 4, sizeof(struct Pokemon) * 2);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 12:
if ((GetBlockReceivedStatus() & 3) == 3)
{
ResetBlockReceivedFlags();
if (GetMultiplayerId() != 0)
memcpy(gEnemyParty + 4, gBlockRecvBuffer[0], sizeof(struct Pokemon) * 2);
TryCorrectShedinjaLanguage(&gPlayerParty[0]);
TryCorrectShedinjaLanguage(&gPlayerParty[1]);
TryCorrectShedinjaLanguage(&gPlayerParty[2]);
TryCorrectShedinjaLanguage(&gPlayerParty[3]);
TryCorrectShedinjaLanguage(&gPlayerParty[4]);
TryCorrectShedinjaLanguage(&gPlayerParty[5]);
TryCorrectShedinjaLanguage(&gEnemyParty[0]);
TryCorrectShedinjaLanguage(&gEnemyParty[1]);
TryCorrectShedinjaLanguage(&gEnemyParty[2]);
TryCorrectShedinjaLanguage(&gEnemyParty[3]);
TryCorrectShedinjaLanguage(&gEnemyParty[4]);
TryCorrectShedinjaLanguage(&gEnemyParty[5]);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 13:
sub_8032768();
sub_8184E58();
gBattleCommunication[SPRITES_INIT_STATE1] = 0;
gBattleCommunication[SPRITES_INIT_STATE2] = 0;
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
{
gBattleCommunication[MULTIUSE_STATE] = 14;
}
else
{
gBattleCommunication[MULTIUSE_STATE] = 16;
}
break;
case 14:
if (sub_800A520())
{
SendBlock(bitmask_all_link_players_but_self(), &gRecordedBattleRngSeed, sizeof(gRecordedBattleRngSeed));
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 15:
if ((GetBlockReceivedStatus() & 3) == 3)
{
ResetBlockReceivedFlags();
if (!(gBattleTypeFlags & BATTLE_TYPE_WILD))
memcpy(&gRecordedBattleRngSeed, gBlockRecvBuffer[enemyMultiplayerId], sizeof(gRecordedBattleRngSeed));
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 16:
if (BattleInitAllSprites(&gBattleCommunication[SPRITES_INIT_STATE1], &gBattleCommunication[SPRITES_INIT_STATE2]))
{
sub_8166188();
gPreBattleCallback1 = gMain.callback1;
gMain.callback1 = BattleMainCB1;
SetMainCallback2(BattleMainCB2);
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
{
gBattleTypeFlags |= BATTLE_TYPE_20;
}
}
break;
}
}
static void sub_80379F8(u8 arrayIdPlus)
{
s32 i;
for (i = 0; i < 3; i++)
{
gUnknown_02022FF8[i].species = GetMonData(&gPlayerParty[arrayIdPlus + i], MON_DATA_SPECIES);
gUnknown_02022FF8[i].heldItem = GetMonData(&gPlayerParty[arrayIdPlus + i], MON_DATA_HELD_ITEM);
GetMonData(&gPlayerParty[arrayIdPlus + i], MON_DATA_NICKNAME, gUnknown_02022FF8[i].nickname);
gUnknown_02022FF8[i].level = GetMonData(&gPlayerParty[arrayIdPlus + i], MON_DATA_LEVEL);
gUnknown_02022FF8[i].hp = GetMonData(&gPlayerParty[arrayIdPlus + i], MON_DATA_HP);
gUnknown_02022FF8[i].maxhp = GetMonData(&gPlayerParty[arrayIdPlus + i], MON_DATA_MAX_HP);
gUnknown_02022FF8[i].status = GetMonData(&gPlayerParty[arrayIdPlus + i], MON_DATA_STATUS);
gUnknown_02022FF8[i].personality = GetMonData(&gPlayerParty[arrayIdPlus + i], MON_DATA_PERSONALITY);
gUnknown_02022FF8[i].gender = GetMonGender(&gPlayerParty[arrayIdPlus + i]);
StripExtCtrlCodes(gUnknown_02022FF8[i].nickname);
if (GetMonData(&gPlayerParty[arrayIdPlus + i], MON_DATA_LANGUAGE) != LANGUAGE_JAPANESE)
PadNameString(gUnknown_02022FF8[i].nickname, 0);
}
memcpy(gUnknown_02023058, gUnknown_02022FF8, sizeof(gUnknown_02022FF8));
}
static void CB2_PreInitMultiBattle(void)
{
s32 i;
u8 playerMultiplierId;
s32 numPlayers = 4;
u8 r4 = 0xF;
u32* savedBattleTypeFlags;
void (**savedCallback)(void);
if (gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER)
{
numPlayers = 2;
r4 = 3;
}
playerMultiplierId = GetMultiplayerId();
gBattleScripting.multiplayerId = playerMultiplierId;
savedCallback = &gBattleStruct->savedCallback;
savedBattleTypeFlags = &gBattleStruct->savedBattleTypeFlags;
RunTasks();
AnimateSprites();
BuildOamBuffer();
switch (gBattleCommunication[MULTIUSE_STATE])
{
case 0:
if (gReceivedRemoteLinkPlayers != 0 && sub_800A520())
{
gUnknown_02023058 = Alloc(sizeof(struct UnknownPokemonStruct2) * 3);
sub_80379F8(0);
SendBlock(bitmask_all_link_players_but_self(), gUnknown_02023058, sizeof(struct UnknownPokemonStruct2) * 3);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 1:
if ((GetBlockReceivedStatus() & r4) == r4)
{
ResetBlockReceivedFlags();
for (i = 0; i < numPlayers; i++)
{
if (i == playerMultiplierId)
continue;
if (numPlayers == 4)
{
if ((!(gLinkPlayers[i].lp_field_18 & 1) && !(gLinkPlayers[playerMultiplierId].lp_field_18 & 1))
|| (gLinkPlayers[i].lp_field_18 & 1 && gLinkPlayers[playerMultiplierId].lp_field_18 & 1))
{
memcpy(gUnknown_02022FF8, gBlockRecvBuffer[i], sizeof(struct UnknownPokemonStruct2) * 3);
}
}
else
{
memcpy(gUnknown_02022FF8, gBlockRecvBuffer[i], sizeof(struct UnknownPokemonStruct2) * 3);
}
}
gBattleCommunication[MULTIUSE_STATE]++;
*savedCallback = gMain.savedCallback;
*savedBattleTypeFlags = gBattleTypeFlags;
gMain.savedCallback = CB2_PreInitMultiBattle;
sub_81B9150();
}
break;
case 2:
if (sub_800A520() && !gPaletteFade.active)
{
gBattleCommunication[MULTIUSE_STATE]++;
if (gLinkVSyncDisabled)
sub_800ADF8();
else
sub_800AC34();
}
break;
case 3:
if (gLinkVSyncDisabled)
{
if (sub_8010500())
{
gBattleTypeFlags = *savedBattleTypeFlags;
gMain.savedCallback = *savedCallback;
SetMainCallback2(CB2_InitBattleInternal);
Free(gUnknown_02023058);
gUnknown_02023058 = NULL;
}
}
else if (gReceivedRemoteLinkPlayers == 0)
{
gBattleTypeFlags = *savedBattleTypeFlags;
gMain.savedCallback = *savedCallback;
SetMainCallback2(CB2_InitBattleInternal);
Free(gUnknown_02023058);
gUnknown_02023058 = NULL;
}
break;
}
}
static void CB2_PreInitIngamePlayerPartnerBattle(void)
{
u32* savedBattleTypeFlags;
void (**savedCallback)(void);
savedCallback = &gBattleStruct->savedCallback;
savedBattleTypeFlags = &gBattleStruct->savedBattleTypeFlags;
RunTasks();
AnimateSprites();
BuildOamBuffer();
switch (gBattleCommunication[MULTIUSE_STATE])
{
case 0:
gUnknown_02023058 = Alloc(sizeof(struct UnknownPokemonStruct2) * 3);
sub_80379F8(3);
gBattleCommunication[MULTIUSE_STATE]++;
*savedCallback = gMain.savedCallback;
*savedBattleTypeFlags = gBattleTypeFlags;
gMain.savedCallback = CB2_PreInitIngamePlayerPartnerBattle;
sub_81B9150();
break;
case 1:
if (!gPaletteFade.active)
{
gBattleCommunication[MULTIUSE_STATE] = 2;
gBattleTypeFlags = *savedBattleTypeFlags;
gMain.savedCallback = *savedCallback;
SetMainCallback2(CB2_InitBattleInternal);
Free(gUnknown_02023058);
gUnknown_02023058 = NULL;
}
break;
}
}
static void CB2_HandleStartMultiBattle(void)
{
u8 playerMultiplayerId;
s32 id;
u8 var;
playerMultiplayerId = GetMultiplayerId();
gBattleScripting.multiplayerId = playerMultiplayerId;
RunTasks();
AnimateSprites();
BuildOamBuffer();
switch (gBattleCommunication[MULTIUSE_STATE])
{
case 0:
if (!IsDma3ManagerBusyWithBgCopy())
{
ShowBg(0);
ShowBg(1);
ShowBg(2);
ShowBg(3);
sub_805EF14();
gBattleCommunication[MULTIUSE_STATE] = 1;
}
if (gLinkVSyncDisabled)
sub_800E0E8();
break;
case 1:
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
{
if (gReceivedRemoteLinkPlayers != 0)
{
if (sub_800A520())
{
*(&gBattleStruct->field_180) = 0;
*(&gBattleStruct->field_181) = 3;
sub_8036A5C();
SetPlayerBerryDataInBattleStruct();
SendBlock(bitmask_all_link_players_but_self(), &gBattleStruct->field_180, 32);
gBattleCommunication[MULTIUSE_STATE]++;
}
if (gLinkVSyncDisabled)
sub_800DFB4(0, 0);
}
}
else
{
if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED))
gBattleTypeFlags |= BATTLE_TYPE_WILD;
gBattleCommunication[MULTIUSE_STATE] = 7;
SetAllPlayersBerryData();
}
break;
case 2:
if ((GetBlockReceivedStatus() & 0xF) == 0xF)
{
ResetBlockReceivedFlags();
sub_8036EB8(4, playerMultiplayerId);
SetAllPlayersBerryData();
sub_8068AA4();
var = CreateTask(task00_0800F6FC, 0);
gTasks[var].data[1] = 0x10E;
gTasks[var].data[2] = 0x5A;
gTasks[var].data[5] = 0;
gTasks[var].data[3] = 0;
gTasks[var].data[4] = 0;
for (id = 0; id < MAX_LINK_PLAYERS; id++)
{
sub_8185F90(gBlockRecvBuffer[id][1]);
switch (gLinkPlayers[id].lp_field_18)
{
case 0:
gTasks[var].data[3] |= gBlockRecvBuffer[id][1] & 0x3F;
break;
case 1:
gTasks[var].data[4] |= gBlockRecvBuffer[id][1] & 0x3F;
break;
case 2:
gTasks[var].data[3] |= (gBlockRecvBuffer[id][1] & 0x3F) << 6;
break;
case 3:
gTasks[var].data[4] |= (gBlockRecvBuffer[id][1] & 0x3F) << 6;
break;
}
}
ZeroEnemyPartyMons();
gBattleCommunication[MULTIUSE_STATE]++;
}
else
break;
// fall through
case 3:
if (sub_800A520())
{
SendBlock(bitmask_all_link_players_but_self(), gPlayerParty, sizeof(struct Pokemon) * 2);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 4:
if ((GetBlockReceivedStatus() & 0xF) == 0xF)
{
ResetBlockReceivedFlags();
for (id = 0; id < MAX_LINK_PLAYERS; id++)
{
if (id == playerMultiplayerId)
{
switch (gLinkPlayers[id].lp_field_18)
{
case 0:
case 3:
memcpy(gPlayerParty, gBlockRecvBuffer[id], sizeof(struct Pokemon) * 2);
break;
case 1:
case 2:
memcpy(gPlayerParty + 3, gBlockRecvBuffer[id], sizeof(struct Pokemon) * 2);
break;
}
}
else
{
if ((!(gLinkPlayers[id].lp_field_18 & 1) && !(gLinkPlayers[playerMultiplayerId].lp_field_18 & 1))
|| ((gLinkPlayers[id].lp_field_18 & 1) && (gLinkPlayers[playerMultiplayerId].lp_field_18 & 1)))
{
switch (gLinkPlayers[id].lp_field_18)
{
case 0:
case 3:
memcpy(gPlayerParty, gBlockRecvBuffer[id], sizeof(struct Pokemon) * 2);
break;
case 1:
case 2:
memcpy(gPlayerParty + 3, gBlockRecvBuffer[id], sizeof(struct Pokemon) * 2);
break;
}
}
else
{
switch (gLinkPlayers[id].lp_field_18)
{
case 0:
case 3:
memcpy(gEnemyParty, gBlockRecvBuffer[id], sizeof(struct Pokemon) * 2);
break;
case 1:
case 2:
memcpy(gEnemyParty + 3, gBlockRecvBuffer[id], sizeof(struct Pokemon) * 2);
break;
}
}
}
}
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 5:
if (sub_800A520())
{
SendBlock(bitmask_all_link_players_but_self(), gPlayerParty + 2, sizeof(struct Pokemon));
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 6:
if ((GetBlockReceivedStatus() & 0xF) == 0xF)
{
ResetBlockReceivedFlags();
for (id = 0; id < MAX_LINK_PLAYERS; id++)
{
if (id == playerMultiplayerId)
{
switch (gLinkPlayers[id].lp_field_18)
{
case 0:
case 3:
memcpy(gPlayerParty + 2, gBlockRecvBuffer[id], sizeof(struct Pokemon));
break;
case 1:
case 2:
memcpy(gPlayerParty + 5, gBlockRecvBuffer[id], sizeof(struct Pokemon));
break;
}
}
else
{
if ((!(gLinkPlayers[id].lp_field_18 & 1) && !(gLinkPlayers[playerMultiplayerId].lp_field_18 & 1))
|| ((gLinkPlayers[id].lp_field_18 & 1) && (gLinkPlayers[playerMultiplayerId].lp_field_18 & 1)))
{
switch (gLinkPlayers[id].lp_field_18)
{
case 0:
case 3:
memcpy(gPlayerParty + 2, gBlockRecvBuffer[id], sizeof(struct Pokemon));
break;
case 1:
case 2:
memcpy(gPlayerParty + 5, gBlockRecvBuffer[id], sizeof(struct Pokemon));
break;
}
}
else
{
switch (gLinkPlayers[id].lp_field_18)
{
case 0:
case 3:
memcpy(gEnemyParty + 2, gBlockRecvBuffer[id], sizeof(struct Pokemon));
break;
case 1:
case 2:
memcpy(gEnemyParty + 5, gBlockRecvBuffer[id], sizeof(struct Pokemon));
break;
}
}
}
}
TryCorrectShedinjaLanguage(&gPlayerParty[0]);
TryCorrectShedinjaLanguage(&gPlayerParty[1]);
TryCorrectShedinjaLanguage(&gPlayerParty[2]);
TryCorrectShedinjaLanguage(&gPlayerParty[3]);
TryCorrectShedinjaLanguage(&gPlayerParty[4]);
TryCorrectShedinjaLanguage(&gPlayerParty[5]);
TryCorrectShedinjaLanguage(&gEnemyParty[0]);
TryCorrectShedinjaLanguage(&gEnemyParty[1]);
TryCorrectShedinjaLanguage(&gEnemyParty[2]);
TryCorrectShedinjaLanguage(&gEnemyParty[3]);
TryCorrectShedinjaLanguage(&gEnemyParty[4]);
TryCorrectShedinjaLanguage(&gEnemyParty[5]);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 7:
sub_8032768();
sub_8184E58();
gBattleCommunication[SPRITES_INIT_STATE1] = 0;
gBattleCommunication[SPRITES_INIT_STATE2] = 0;
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
{
for (id = 0; id < 4 && (gLinkPlayers[id].version & 0xFF) == 3; id++);
if (id == 4)
gBattleCommunication[MULTIUSE_STATE] = 8;
else
gBattleCommunication[MULTIUSE_STATE] = 10;
}
else
{
gBattleCommunication[MULTIUSE_STATE] = 10;
}
break;
case 8:
if (sub_800A520())
{
u32* ptr = (u32*)(&gBattleStruct->field_180);
ptr[0] = gBattleTypeFlags;
ptr[1] = gRecordedBattleRngSeed; // UB: overwrites berry data
SendBlock(bitmask_all_link_players_but_self(), ptr, 8);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 9:
if ((GetBlockReceivedStatus() & 0xF) == 0xF)
{
ResetBlockReceivedFlags();
for (var = 0; var < 4; var++)
{
u32 blockValue = gBlockRecvBuffer[var][0];
if (blockValue & 4)
{
memcpy(&gRecordedBattleRngSeed, &gBlockRecvBuffer[var][2], sizeof(gRecordedBattleRngSeed));
break;
}
}
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 10:
if (BattleInitAllSprites(&gBattleCommunication[SPRITES_INIT_STATE1], &gBattleCommunication[SPRITES_INIT_STATE2]))
{
gPreBattleCallback1 = gMain.callback1;
gMain.callback1 = BattleMainCB1;
SetMainCallback2(BattleMainCB2);
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
{
gTrainerBattleOpponent_A = TRAINER_OPPONENT_800;
gBattleTypeFlags |= BATTLE_TYPE_20;
}
}
break;
}
}
void BattleMainCB2(void)
{
AnimateSprites();
BuildOamBuffer();
RunTextPrinters();
UpdatePaletteFade();
RunTasks();
if (gMain.heldKeys & B_BUTTON && gBattleTypeFlags & BATTLE_TYPE_RECORDED && sub_8186450())
{
gSpecialVar_Result = gBattleOutcome = BATTLE_PLAYER_TELEPORTED;
ResetPaletteFadeControl();
BeginNormalPaletteFade(-1, 0, 0, 0x10, 0);
SetMainCallback2(CB2_QuitRecordedBattle);
}
}
static void FreeRestoreBattleData(void)
{
gMain.callback1 = gPreBattleCallback1;
gUnknown_02039B28[0x15] = 3;
gMain.inBattle = 0;
ZeroEnemyPartyMons();
m4aSongNumStop(0x5A);
FreeMonSpritesGfx();
FreeBattleSpritesData();
FreeBattleResources();
}
void CB2_QuitRecordedBattle(void)
{
UpdatePaletteFade();
if (!gPaletteFade.active)
{
m4aMPlayStop(&gMPlay_SE1);
m4aMPlayStop(&gMPlay_SE2);
FreeRestoreBattleData();
FreeAllWindowBuffers();
SetMainCallback2(gMain.savedCallback);
}
}
void sub_8038528(struct Sprite* sprite)
{
sprite->data0 = 0;
sprite->callback = sub_8038538;
}
static void sub_8038538(struct Sprite *sprite)
{
u16 *arr = (u16*)(gDecompressionBuffer);
switch (sprite->data0)
{
case 0:
sprite->data0++;
sprite->data1 = 0;
sprite->data2 = 0x281;
sprite->data3 = 0;
sprite->data4 = 1;
// fall through
case 1:
sprite->data4--;
if (sprite->data4 == 0)
{
s32 i;
s32 r2;
s32 r0;
sprite->data4 = 2;
r2 = sprite->data1 + sprite->data3 * 32;
r0 = sprite->data2 - sprite->data3 * 32;
for (i = 0; i < 29; i += 2)
{
arr[r2 + i] = 0x3D;
arr[r0 + i] = 0x3D;
}
sprite->data3++;
if (sprite->data3 == 21)
{
sprite->data0++;
sprite->data1 = 32;
}
}
break;
case 2:
sprite->data1--;
if (sprite->data1 == 20)
SetMainCallback2(CB2_InitBattle);
break;
}
}
static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 firstTrainer)
{
u32 nameHash = 0;
u32 personalityValue;
u8 fixedIV;
s32 i, j;
u8 monsCount;
if (trainerNum == SECRET_BASE_OPPONENT)
return 0;
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && !(gBattleTypeFlags & (BATTLE_TYPE_FRONTIER
| BATTLE_TYPE_EREADER_TRAINER
| BATTLE_TYPE_x4000000)))
{
if (firstTrainer == TRUE)
ZeroEnemyPartyMons();
if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
{
if (gTrainers[trainerNum].partySize > 3)
monsCount = 3;
else
monsCount = gTrainers[trainerNum].partySize;
}
else
{
monsCount = gTrainers[trainerNum].partySize;
}
for (i = 0; i < monsCount; i++)
{
if (gTrainers[trainerNum].doubleBattle == TRUE)
personalityValue = 0x80;
else if (gTrainers[trainerNum].encounterMusic_gender & 0x80)
personalityValue = 0x78;
else
personalityValue = 0x88;
for (j = 0; gTrainers[trainerNum].trainerName[j] != 0xFF; j++)
nameHash += gTrainers[trainerNum].trainerName[j];
switch (gTrainers[trainerNum].partyFlags)
{
case 0:
{
const struct TrainerMonNoItemDefaultMoves *partyData = gTrainers[trainerNum].party.NoItemDefaultMoves;
for (j = 0; gSpeciesNames[partyData[i].species][j] != 0xFF; j++)
nameHash += gSpeciesNames[partyData[i].species][j];
personalityValue += nameHash << 8;
fixedIV = partyData[i].iv * 31 / 255;
CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, OT_ID_RANDOM_NO_SHINY, 0);
break;
}
case PARTY_FLAG_CUSTOM_MOVES:
{
const struct TrainerMonNoItemCustomMoves *partyData = gTrainers[trainerNum].party.NoItemCustomMoves;
for (j = 0; gSpeciesNames[partyData[i].species][j] != 0xFF; j++)
nameHash += gSpeciesNames[partyData[i].species][j];
personalityValue += nameHash << 8;
fixedIV = partyData[i].iv * 31 / 255;
CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, 2, 0);
for (j = 0; j < 4; j++)
{
SetMonData(&party[i], MON_DATA_MOVE1 + j, &partyData[i].moves[j]);
SetMonData(&party[i], MON_DATA_PP1 + j, &gBattleMoves[partyData[i].moves[j]].pp);
}
break;
}
case PARTY_FLAG_HAS_ITEM:
{
const struct TrainerMonItemDefaultMoves *partyData = gTrainers[trainerNum].party.ItemDefaultMoves;
for (j = 0; gSpeciesNames[partyData[i].species][j] != 0xFF; j++)
nameHash += gSpeciesNames[partyData[i].species][j];
personalityValue += nameHash << 8;
fixedIV = partyData[i].iv * 31 / 255;
CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, 2, 0);
SetMonData(&party[i], MON_DATA_HELD_ITEM, &partyData[i].heldItem);
break;
}
case PARTY_FLAG_CUSTOM_MOVES | PARTY_FLAG_HAS_ITEM:
{
const struct TrainerMonItemCustomMoves *partyData = gTrainers[trainerNum].party.ItemCustomMoves;
for (j = 0; gSpeciesNames[partyData[i].species][j] != 0xFF; j++)
nameHash += gSpeciesNames[partyData[i].species][j];
personalityValue += nameHash << 8;
fixedIV = partyData[i].iv * 31 / 255;
CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, 2, 0);
SetMonData(&party[i], MON_DATA_HELD_ITEM, &partyData[i].heldItem);
for (j = 0; j < 4; j++)
{
SetMonData(&party[i], MON_DATA_MOVE1 + j, &partyData[i].moves[j]);
SetMonData(&party[i], MON_DATA_PP1 + j, &gBattleMoves[partyData[i].moves[j]].pp);
}
break;
}
}
}
gBattleTypeFlags |= gTrainers[trainerNum].doubleBattle;
}
return gTrainers[trainerNum].partySize;
}
void sub_8038A04(void) // unused
{
if (REG_VCOUNT < 0xA0 && REG_VCOUNT >= 0x6F)
SetGpuReg(REG_OFFSET_BG0CNT, 0x9800);
}
void VBlankCB_Battle(void)
{
// change gRngSeed every vblank unless the battle could be recorded
if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_FRONTIER | BATTLE_TYPE_RECORDED)))
Random();
SetGpuReg(REG_OFFSET_BG0HOFS, gBattle_BG0_X);
SetGpuReg(REG_OFFSET_BG0VOFS, gBattle_BG0_Y);
SetGpuReg(REG_OFFSET_BG1HOFS, gBattle_BG1_X);
SetGpuReg(REG_OFFSET_BG1VOFS, gBattle_BG1_Y);
SetGpuReg(REG_OFFSET_BG2HOFS, gBattle_BG2_X);
SetGpuReg(REG_OFFSET_BG2VOFS, gBattle_BG2_Y);
SetGpuReg(REG_OFFSET_BG3HOFS, gBattle_BG3_X);
SetGpuReg(REG_OFFSET_BG3VOFS, gBattle_BG3_Y);
SetGpuReg(REG_OFFSET_WIN0H, gBattle_WIN0H);
SetGpuReg(REG_OFFSET_WIN0V, gBattle_WIN0V);
SetGpuReg(REG_OFFSET_WIN1H, gBattle_WIN1H);
SetGpuReg(REG_OFFSET_WIN1V, gBattle_WIN1V);
LoadOam();
ProcessSpriteCopyRequests();
TransferPlttBuffer();
sub_80BA0A8();
}
void nullsub_17(void)
{
}
static void sub_8038B04(struct Sprite *sprite)
{
if (sprite->data0 != 0)
sprite->pos1.x = sprite->data1 + ((sprite->data2 & 0xFF00) >> 8);
else
sprite->pos1.x = sprite->data1 - ((sprite->data2 & 0xFF00) >> 8);
sprite->data2 += 0x180;
if (sprite->affineAnimEnded)
{
FreeSpriteTilesByTag(0x2710);
FreeSpritePaletteByTag(0x2710);
FreeSpriteOamMatrix(sprite);
DestroySprite(sprite);
}
}
void sub_8038B74(struct Sprite *sprite)
{
StartSpriteAffineAnim(sprite, 1);
sprite->callback = sub_8038B04;
PlaySE(SE_BT_START);
}
static void sub_8038B94(u8 taskId)
{
struct Pokemon *sp4 = NULL;
struct Pokemon *sp8 = NULL;
u8 r2 = gBattleScripting.multiplayerId;
u32 r7;
s32 i;
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
{
switch (gLinkPlayers[r2].lp_field_18)
{
case 0:
case 2:
sp4 = gPlayerParty;
sp8 = gEnemyParty;
break;
case 1:
case 3:
sp4 = gEnemyParty;
sp8 = gPlayerParty;
break;
}
}
else
{
sp4 = gPlayerParty;
sp8 = gEnemyParty;
}
r7 = 0;
for (i = 0; i < PARTY_SIZE; i++)
{
u16 species = GetMonData(&sp4[i], MON_DATA_SPECIES2);
u16 hp = GetMonData(&sp4[i], MON_DATA_HP);
u32 status = GetMonData(&sp4[i], MON_DATA_STATUS);
if (species == SPECIES_NONE)
continue;
if (species != SPECIES_EGG && hp != 0 && status == 0)
r7 |= 1 << i * 2;
if (species == 0)
continue;
if (hp != 0 && (species == SPECIES_EGG || status != 0))
r7 |= 2 << i * 2;
if (species == 0)
continue;
if (species != SPECIES_EGG && hp == 0)
r7 |= 3 << i * 2;
}
gTasks[taskId].data[3] = r7;
r7 = 0;
for (i = 0; i < PARTY_SIZE; i++)
{
u16 species = GetMonData(&sp8[i], MON_DATA_SPECIES2);
u16 hp = GetMonData(&sp8[i], MON_DATA_HP);
u32 status = GetMonData(&sp8[i], MON_DATA_STATUS);
if (species == SPECIES_NONE)
continue;
if (species != SPECIES_EGG && hp != 0 && status == 0)
r7 |= 1 << i * 2;
if (species == SPECIES_NONE)
continue;
if (hp != 0 && (species == SPECIES_EGG || status != 0))
r7 |= 2 << i * 2;
if (species == SPECIES_NONE)
continue;
if (species != SPECIES_EGG && hp == 0)
r7 |= 3 << i * 2;
}
gTasks[taskId].data[4] = r7;
}
void sub_8038D64(void)
{
s32 i;
u8 taskId;
SetHBlankCallback(NULL);
SetVBlankCallback(NULL);
gBattleTypeFlags &= ~(BATTLE_TYPE_20);
if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER)
{
SetMainCallback2(gMain.savedCallback);
FreeBattleResources();
FreeBattleSpritesData();
FreeMonSpritesGfx();
}
else
{
CpuFill32(0, (void*)(VRAM), VRAM_SIZE);
SetGpuReg(REG_OFFSET_MOSAIC, 0);
SetGpuReg(REG_OFFSET_WIN0H, 0xF0);
SetGpuReg(REG_OFFSET_WIN0V, 0x5051);
SetGpuReg(REG_OFFSET_WININ, 0);
SetGpuReg(REG_OFFSET_WINOUT, 0);
gBattle_WIN0H = 0xF0;
gBattle_WIN0V = 0x5051;
dp12_8087EA4();
for (i = 0; i < 80; i++)
{
gUnknown_02038C28.unk0[i] = 0xF0;
gUnknown_02038C28.unk780[i] = 0xF0;
}
for (i = 80; i < 160; i++)
{
asm(""::"r"(i)); // Needed to stop the compiler from optimizing out the loop counter
gUnknown_02038C28.unk0[i] = 0xFF10;
gUnknown_02038C28.unk780[i] = 0xFF10;
}
ResetPaletteFade();
gBattle_BG0_X = 0;
gBattle_BG0_Y = 0;
gBattle_BG1_X = 0;
gBattle_BG1_Y = 0;
gBattle_BG2_X = 0;
gBattle_BG2_Y = 0;
gBattle_BG3_X = 0;
gBattle_BG3_Y = 0;
sub_80356D0();
LoadCompressedPalette(gUnknown_08C004E0, 0, 64);
ApplyPlayerChosenFrameToBattleMenu();
ResetSpriteData();
ResetTasks();
LoadBattleEntryBackground();
SetGpuReg(REG_OFFSET_WINOUT, 0x37);
FreeAllSpritePalettes();
gReservedSpritePaletteCount = 4;
SetVBlankCallback(VBlankCB_Battle);
taskId = CreateTask(task00_0800F6FC, 0);
gTasks[taskId].data[1] = 0x10E;
gTasks[taskId].data[2] = 0x5A;
gTasks[taskId].data[5] = 1;
sub_8038B94(taskId);
SetMainCallback2(sub_8038F14);
gBattleCommunication[MULTIUSE_STATE] = 0;
}
}
static void sub_8038F14(void)
{
sub_8038F34();
AnimateSprites();
BuildOamBuffer();
RunTextPrinters();
UpdatePaletteFade();
RunTasks();
}
static void sub_8038F34(void)
{
s32 i;
switch (gBattleCommunication[MULTIUSE_STATE])
{
case 0:
ShowBg(0);
ShowBg(1);
ShowBg(2);
gBattleCommunication[1] = 0xFF;
gBattleCommunication[MULTIUSE_STATE]++;
break;
case 1:
if (--gBattleCommunication[1] == 0)
{
BeginNormalPaletteFade(-1, 0, 0, 0x10, 0);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 2:
if (!gPaletteFade.active)
{
u8 monsCount;
gMain.field_439_x4 = sub_8185FAC();
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
monsCount = 4;
else
monsCount = 2;
for (i = 0; i < monsCount && (gLinkPlayers[i].version & 0xFF) == VERSION_EMERALD; i++);
if (!gSaveBlock2Ptr->field_CA9_b && i == monsCount)
{
if (FlagGet(FLAG_SYS_FRONTIER_PASS))
{
FreeAllWindowBuffers();
SetMainCallback2(sub_80392A8);
}
else if (!gMain.field_439_x4)
{
SetMainCallback2(gMain.savedCallback);
FreeBattleResources();
FreeBattleSpritesData();
FreeMonSpritesGfx();
}
else if (gReceivedRemoteLinkPlayers == 0)
{
CreateTask(sub_80B3AF8, 5);
gBattleCommunication[MULTIUSE_STATE]++;
}
else
{
gBattleCommunication[MULTIUSE_STATE]++;
}
}
else
{
SetMainCallback2(gMain.savedCallback);
FreeBattleResources();
FreeBattleSpritesData();
FreeMonSpritesGfx();
}
}
break;
case 3:
CpuFill32(0, (void*)(VRAM), VRAM_SIZE);
for (i = 0; i < 2; i++)
LoadChosenBattleElement(i);
BeginNormalPaletteFade(-1, 0, 0x10, 0, 0);
gBattleCommunication[MULTIUSE_STATE]++;
break;
case 4:
if (!gPaletteFade.active)
gBattleCommunication[MULTIUSE_STATE]++;
break;
case 5:
if (!FuncIsActiveTask(sub_80B3AF8))
gBattleCommunication[MULTIUSE_STATE]++;
break;
case 6:
if (sub_800A520() == TRUE)
{
sub_800ADF8();
BattleHandleAddTextPrinter(gText_LinkStandby3, 0);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 7:
if (!IsTextPrinterActive(0))
{
if (sub_800A520() == TRUE)
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 8:
if (!gLinkVSyncDisabled)
sub_800AC34();
gBattleCommunication[MULTIUSE_STATE]++;
break;
case 9:
if (!gMain.field_439_x4 || gLinkVSyncDisabled || gReceivedRemoteLinkPlayers != 1)
{
gMain.field_439_x4 = 0;
SetMainCallback2(gMain.savedCallback);
FreeBattleResources();
FreeBattleSpritesData();
FreeMonSpritesGfx();
}
break;
}
}
u32 sub_80391E0(u8 arrayId, u8 caseId)
{
u32 ret = 0;
switch (caseId)
{
case 0:
ret = gUnknown_0831AA08[arrayId].bg;
break;
case 1:
ret = gUnknown_0831AA08[arrayId].charBaseIndex;
break;
case 2:
ret = gUnknown_0831AA08[arrayId].mapBaseIndex;
break;
case 3:
ret = gUnknown_0831AA08[arrayId].screenSize;
break;
case 4:
ret = gUnknown_0831AA08[arrayId].paletteMode;
break;
case 5:
ret = gUnknown_0831AA08[arrayId].priority;
break;
case 6:
ret = gUnknown_0831AA08[arrayId].baseTile;
break;
}
return ret;
}
static void sub_80392A8(void)
{
s32 i;
SetHBlankCallback(NULL);
SetVBlankCallback(NULL);
CpuFill32(0, (void*)(VRAM), VRAM_SIZE);
ResetPaletteFade();
gBattle_BG0_X = 0;
gBattle_BG0_Y = 0;
gBattle_BG1_X = 0;
gBattle_BG1_Y = 0;
gBattle_BG2_X = 0;
gBattle_BG2_Y = 0;
gBattle_BG3_X = 0;
gBattle_BG3_Y = 0;
sub_80356D0();
SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON | DISPCNT_OBJ_1D_MAP);
ApplyPlayerChosenFrameToBattleMenu();
for (i = 0; i < 2; i++)
LoadChosenBattleElement(i);
ResetSpriteData();
ResetTasks();
FreeAllSpritePalettes();
gReservedSpritePaletteCount = 4;
SetVBlankCallback(VBlankCB_Battle);
SetMainCallback2(sub_803937C);
BeginNormalPaletteFade(-1, 0, 0x10, 0, 0);
gBattleCommunication[MULTIUSE_STATE] = 0;
}
static void sub_803937C(void)
{
sub_803939C();
AnimateSprites();
BuildOamBuffer();
RunTextPrinters();
UpdatePaletteFade();
RunTasks();
}
static void sub_803939C(void)
{
switch (gBattleCommunication[MULTIUSE_STATE])
{
case 0:
ShowBg(0);
ShowBg(1);
ShowBg(2);
gBattleCommunication[MULTIUSE_STATE]++;
break;
case 1:
if (gMain.field_439_x4 && gReceivedRemoteLinkPlayers == 0)
CreateTask(sub_80B3AF8, 5);
gBattleCommunication[MULTIUSE_STATE]++;
break;
case 2:
if (!FuncIsActiveTask(sub_80B3AF8))
gBattleCommunication[MULTIUSE_STATE]++;
break;
case 3:
if (!gPaletteFade.active)
{
BattleHandleAddTextPrinter(gText_RecordBattleToPass, 0);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 4:
if (!IsTextPrinterActive(0))
{
HandleBattleWindow(0x18, 8, 0x1D, 0xD, 0);
BattleHandleAddTextPrinter(gText_BattleYesNoChoice, 0xC);
gBattleCommunication[CURSOR_POSITION] = 1;
BattleCreateYesNoCursorAt(1);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 5:
if (gMain.newKeys & DPAD_UP)
{
if (gBattleCommunication[CURSOR_POSITION] != 0)
{
PlaySE(SE_SELECT);
BattleDestroyYesNoCursorAt(gBattleCommunication[CURSOR_POSITION]);
gBattleCommunication[CURSOR_POSITION] = 0;
BattleCreateYesNoCursorAt(0);
}
}
else if (gMain.newKeys & DPAD_DOWN)
{
if (gBattleCommunication[CURSOR_POSITION] == 0)
{
PlaySE(SE_SELECT);
BattleDestroyYesNoCursorAt(gBattleCommunication[CURSOR_POSITION]);
gBattleCommunication[CURSOR_POSITION] = 1;
BattleCreateYesNoCursorAt(1);
}
}
else if (gMain.newKeys & A_BUTTON)
{
PlaySE(SE_SELECT);
if (gBattleCommunication[CURSOR_POSITION] == 0)
{
HandleBattleWindow(0x18, 8, 0x1D, 0xD, WINDOW_CLEAR);
gBattleCommunication[1] = MoveRecordedBattleToSaveData();
gBattleCommunication[MULTIUSE_STATE] = 10;
}
else
{
gBattleCommunication[MULTIUSE_STATE]++;
}
}
else if (gMain.newKeys & B_BUTTON)
{
PlaySE(SE_SELECT);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 6:
if (sub_800A520() == TRUE)
{
HandleBattleWindow(0x18, 8, 0x1D, 0xD, WINDOW_CLEAR);
if (gMain.field_439_x4)
{
sub_800ADF8();
BattleHandleAddTextPrinter(gText_LinkStandby3, 0);
}
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 8:
if (--gBattleCommunication[1] == 0)
{
if (gMain.field_439_x4 && !gLinkVSyncDisabled)
sub_800AC34();
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 9:
if (!gMain.field_439_x4 || gLinkVSyncDisabled || gReceivedRemoteLinkPlayers != 1)
{
gMain.field_439_x4 = 0;
if (!gPaletteFade.active)
{
SetMainCallback2(gMain.savedCallback);
FreeBattleResources();
FreeBattleSpritesData();
FreeMonSpritesGfx();
}
}
break;
case 10:
if (gBattleCommunication[1] == 1)
{
PlaySE(SE_SAVE);
BattleStringExpandPlaceholdersToDisplayedString(gText_BattleRecordedOnPass);
BattleHandleAddTextPrinter(gDisplayedStringBattle, 0);
gBattleCommunication[1] = 0x80;
gBattleCommunication[MULTIUSE_STATE]++;
}
else
{
BattleStringExpandPlaceholdersToDisplayedString(gText_BattleRecordCouldntBeSaved);
BattleHandleAddTextPrinter(gDisplayedStringBattle, 0);
gBattleCommunication[1] = 0x80;
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 11:
if (sub_800A520() == TRUE && !IsTextPrinterActive(0) && --gBattleCommunication[1] == 0)
{
if (gMain.field_439_x4)
{
sub_800ADF8();
BattleHandleAddTextPrinter(gText_LinkStandby3, 0);
}
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
case 12:
case 7:
if (!IsTextPrinterActive(0))
{
if (gMain.field_439_x4)
{
if (sub_800A520() == TRUE)
{
BeginNormalPaletteFade(-1, 0, 0, 0x10, 0);
gBattleCommunication[1] = 0x20;
gBattleCommunication[MULTIUSE_STATE] = 8;
}
}
else
{
BeginNormalPaletteFade(-1, 0, 0, 0x10, 0);
gBattleCommunication[1] = 0x20;
gBattleCommunication[MULTIUSE_STATE] = 8;
}
}
break;
}
}
static void TryCorrectShedinjaLanguage(struct Pokemon *mon)
{
u8 nickname[POKEMON_NAME_LENGTH + 1];
u8 language = LANGUAGE_JAPANESE;
if (GetMonData(mon, MON_DATA_SPECIES) == SPECIES_SHEDINJA
&& GetMonData(mon, MON_DATA_LANGUAGE) != language)
{
GetMonData(mon, MON_DATA_NICKNAME, nickname);
if (StringCompareWithoutExtCtrlCodes(nickname, gText_ShedinjaJapaneseName) == 0)
SetMonData(mon, MON_DATA_LANGUAGE, &language);
}
}
u32 sub_80397C4(u32 setId, u32 tableId)
{
return gUnknown_0831ABA0[setId][tableId].width * 8;
}
#define tBank data0
#define tSpeciesId data2
void oac_poke_opponent(struct Sprite *sprite)
{
sprite->callback = sub_803980C;
StartSpriteAnimIfDifferent(sprite, 0);
BeginNormalPaletteFade(0x20000, 0, 10, 10, 0x2108);
}
static void sub_803980C(struct Sprite *sprite)
{
if ((gUnknown_020243FC & 1) == 0)
{
sprite->pos2.x += 2;
if (sprite->pos2.x == 0)
{
sprite->callback = sub_8039838;
}
}
}
static void sub_8039838(struct Sprite *sprite)
{
if (sprite->animEnded)
{
sub_8076918(sprite->tBank);
SetHealthboxSpriteVisible(gHealthBoxesIds[sprite->tBank]);
sprite->callback = sub_8039894;
StartSpriteAnimIfDifferent(sprite, 0);
BeginNormalPaletteFade(0x20000, 0, 10, 0, 0x2108);
}
}
static void sub_8039894(struct Sprite *sprite)
{
if (!gPaletteFade.active)
{
BattleAnimateFrontSprite(sprite, sprite->tSpeciesId, FALSE, 1);
}
}
void SpriteCallbackDummy_2(struct Sprite *sprite)
{
}
static void sub_80398BC(struct Sprite *sprite) // unused?
{
sprite->data3 = 6;
sprite->data4 = 1;
sprite->callback = sub_80398D0;
}
static void sub_80398D0(struct Sprite *sprite)
{
sprite->data4--;
if (sprite->data4 == 0)
{
sprite->data4 = 8;
sprite->invisible ^= 1;
sprite->data3--;
if (sprite->data3 == 0)
{
sprite->invisible = FALSE;
sprite->callback = SpriteCallbackDummy_2;
gUnknown_02022F88 = 0;
}
}
}
extern const struct MonCoords gMonFrontPicCoords[];
extern const struct MonCoords gCastformFrontSpriteCoords[];
void sub_8039934(struct Sprite *sprite)
{
u8 bank = sprite->tBank;
u16 species;
u8 yOffset;
if (gBattleSpritesDataPtr->bankData[bank].transformSpecies != 0)
species = gBattleSpritesDataPtr->bankData[bank].transformSpecies;
else
species = sprite->tSpeciesId;
GetMonData(&gEnemyParty[gBattlePartyID[bank]], MON_DATA_PERSONALITY); // Unused return value
if (species == SPECIES_UNOWN)
{
u32 personalityValue = GetMonData(&gEnemyParty[gBattlePartyID[bank]], MON_DATA_PERSONALITY);
u16 unownForm = ((((personalityValue & 0x3000000) >> 18) | ((personalityValue & 0x30000) >> 12) | ((personalityValue & 0x300) >> 6) | (personalityValue & 3)) % 0x1C);
u16 unownSpecies;
if (unownForm == 0)
unownSpecies = SPECIES_UNOWN; // Use the A Unown form
else
unownSpecies = NUM_SPECIES + unownForm; // Use one of the other Unown letters
yOffset = gMonFrontPicCoords[unownSpecies].y_offset;
}
else if (species == SPECIES_CASTFORM)
{
yOffset = gCastformFrontSpriteCoords[gBattleMonForms[bank]].y_offset;
}
else if (species > NUM_SPECIES)
{
yOffset = gMonFrontPicCoords[SPECIES_NONE].y_offset;
}
else
{
yOffset = gMonFrontPicCoords[species].y_offset;
}
sprite->data3 = 8 - yOffset / 8;
sprite->data4 = 1;
sprite->callback = sub_8039A48;
}
static void sub_8039A48(struct Sprite *sprite)
{
s32 i;
sprite->data4--;
if (sprite->data4 == 0)
{
sprite->data4 = 2;
sprite->pos2.y += 8;
sprite->data3--;
if (sprite->data3 < 0)
{
FreeSpriteOamMatrix(sprite);
DestroySprite(sprite);
}
else
{
u8 *dst = (u8 *)gMonSpritesGfxPtr->sprites[GetBankIdentity(sprite->tBank)] + (gBattleMonForms[sprite->tBank] << 11) + (sprite->data3 << 8);
for (i = 0; i < 0x100; i++)
*(dst++) = 0;
StartSpriteAnim(sprite, gBattleMonForms[sprite->tBank]);
}
}
}
void sub_8039AD8(struct Sprite *sprite)
{
sprite->data3 = 8;
sprite->data4 = sprite->invisible;
sprite->callback = sub_8039AF4;
}
static void sub_8039AF4(struct Sprite *sprite)
{
sprite->data3--;
if (sprite->data3 == 0)
{
sprite->invisible ^= 1;
sprite->data3 = 8;
}
}
void sub_8039B2C(struct Sprite *sprite)
{
sprite->invisible = sprite->data4;
sprite->data4 = FALSE;
sprite->callback = SpriteCallbackDummy_2;
}
void sub_8039B58(struct Sprite *sprite)
{
if (sprite->affineAnimEnded)
{
if (!(gHitMarker & HITMARKER_NO_ANIMATIONS) || gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000))
{
if (HasTwoFramesAnimation(sprite->tSpeciesId))
StartSpriteAnim(sprite, 1);
}
BattleAnimateFrontSprite(sprite, sprite->tSpeciesId, TRUE, 1);
}
}
void sub_8039BB4(struct Sprite *sprite)
{
sprite->callback = oac_poke_ally_;
}
static void oac_poke_ally_(struct Sprite *sprite)
{
if ((gUnknown_020243FC & 1) == 0)
{
sprite->pos2.x -= 2;
if (sprite->pos2.x == 0)
{
sprite->callback = SpriteCallbackDummy_3;
sprite->data1 = 0;
}
}
}
void sub_80105DC(struct Sprite *sprite)
{
sprite->callback = SpriteCallbackDummy_3;
}
static void SpriteCallbackDummy_3(struct Sprite *sprite)
{
}
void sub_8039C00(struct Sprite *sprite)
{
if (!(gUnknown_020243FC & 1))
{
sprite->pos2.x += sprite->data1;
sprite->pos2.y += sprite->data2;
}
}
void dp11b_obj_instanciate(u8 bank, u8 b, s8 c, s8 d)
{
u8 bounceHealthBoxSpriteId;
u8 spriteId2;
if (b)
{
if (gBattleSpritesDataPtr->healthBoxesData[bank].flag_x2)
return;
}
else
{
if (gBattleSpritesDataPtr->healthBoxesData[bank].flag_x4)
return;
}
bounceHealthBoxSpriteId = CreateInvisibleSpriteWithCallback(SpriteCB_HealthBoxBounce);
if (b == TRUE)
{
spriteId2 = gHealthBoxesIds[bank];
gBattleSpritesDataPtr->healthBoxesData[bank].field_2 = bounceHealthBoxSpriteId;
gBattleSpritesDataPtr->healthBoxesData[bank].flag_x2 = 1;
gSprites[bounceHealthBoxSpriteId].data0 = 0x80;
}
else
{
spriteId2 = gBankSpriteIds[bank];
gBattleSpritesDataPtr->healthBoxesData[bank].field_3 = bounceHealthBoxSpriteId;
gBattleSpritesDataPtr->healthBoxesData[bank].flag_x4 = 1;
gSprites[bounceHealthBoxSpriteId].data0 = 0xC0;
}
gSprites[bounceHealthBoxSpriteId].data1 = c;
gSprites[bounceHealthBoxSpriteId].data2 = d;
gSprites[bounceHealthBoxSpriteId].data3 = spriteId2;
gSprites[bounceHealthBoxSpriteId].data4 = b;
gSprites[spriteId2].pos2.x = 0;
gSprites[spriteId2].pos2.y = 0;
}
void dp11b_obj_free(u8 bank, bool8 b)
{
u8 r4;
if (b == TRUE)
{
if (!gBattleSpritesDataPtr->healthBoxesData[bank].flag_x2)
return;
r4 = gSprites[gBattleSpritesDataPtr->healthBoxesData[bank].field_2].data3;
DestroySprite(&gSprites[gBattleSpritesDataPtr->healthBoxesData[bank].field_2]);
gBattleSpritesDataPtr->healthBoxesData[bank].flag_x2 = 0;
}
else
{
if (!gBattleSpritesDataPtr->healthBoxesData[bank].flag_x4)
return;
r4 = gSprites[gBattleSpritesDataPtr->healthBoxesData[bank].field_3].data3;
DestroySprite(&gSprites[gBattleSpritesDataPtr->healthBoxesData[bank].field_3]);
gBattleSpritesDataPtr->healthBoxesData[bank].flag_x4 = 0;
}
gSprites[r4].pos2.x = 0;
gSprites[r4].pos2.y = 0;
}
static void SpriteCB_HealthBoxBounce(struct Sprite *sprite)
{
u8 spriteId = sprite->data3;
s32 var;
if (sprite->data4 == 1)
var = sprite->data0;
else
var = sprite->data0;
gSprites[spriteId].pos2.y = Sin(var, sprite->data2) + sprite->data2;
sprite->data0 = (sprite->data0 + sprite->data1) & 0xFF;
}
void sub_8039E44(struct Sprite *sprite)
{
if (sprite->affineAnimEnded)
BattleAnimateBackSprite(sprite, sprite->tSpeciesId);
}
void sub_8039E60(struct Sprite *sprite)
{
sub_8039E9C(sprite);
if (sprite->animEnded)
sprite->callback = SpriteCallbackDummy_3;
}
void sub_8039E84(struct Sprite *sprite)
{
StartSpriteAnim(sprite, 1);
sprite->callback = sub_8039E60;
}
void sub_8039E9C(struct Sprite *sprite)
{
if (sprite->animDelayCounter == 0)
sprite->centerToCornerVecX = gUnknown_0831ACE0[sprite->animCmdIndex];
}
void nullsub_20(void)
{
}
void BeginBattleIntro(void)
{
BattleStartClearSetData();
gBattleCommunication[1] = 0;
gBattleMainFunc = BattleIntroGetMonsData;
}
static void BattleMainCB1(void)
{
gBattleMainFunc();
for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++)
gBattleBankFunc[gActiveBank]();
}
static void BattleStartClearSetData(void)
{
s32 i;
u32 j;
u8 *dataPtr;
TurnValuesCleanUp(FALSE);
SpecialStatusesClear();
for (i = 0; i < BATTLE_BANKS_COUNT; i++)
{
gStatuses3[i] = 0;
dataPtr = (u8 *)&gDisableStructs[i];
for (j = 0; j < sizeof(struct DisableStruct); j++)
dataPtr[j] = 0;
gDisableStructs[i].isFirstTurn = 2;
gUnknown_02024284[i] = 0;
gLastMoves[i] = 0;
gLastLandedMoves[i] = 0;
gLastHitByType[i] = 0;
gLastResultingMoves[i] = 0;
gLastHitBy[i] = 0xFF;
gLockedMoves[i] = 0;
gLastPrintedMoves[i] = 0;
gBattleResources->flags->flags[i] = 0;
gPalaceSelectionBattleScripts[i] = 0;
}
for (i = 0; i < 2; i++)
{
gSideAffecting[i] = 0;
dataPtr = (u8 *)&gSideTimers[i];
for (j = 0; j < sizeof(struct SideTimer); j++)
dataPtr[j] = 0;
}
gBankAttacker = 0;
gBankTarget = 0;
gBattleWeather = 0;
dataPtr = (u8 *)&gWishFutureKnock;
for (i = 0; i < sizeof(struct WishFutureKnock); i++)
dataPtr[i] = 0;
gHitMarker = 0;
if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED))
{
if (!(gBattleTypeFlags & BATTLE_TYPE_LINK) && gSaveBlock2Ptr->optionsBattleSceneOff == TRUE)
gHitMarker |= HITMARKER_NO_ANIMATIONS;
}
else if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000)) && GetBattleStyleInRecordedBattle())
gHitMarker |= HITMARKER_NO_ANIMATIONS;
gBattleScripting.battleStyle = gSaveBlock2Ptr->optionsBattleStyle;
gMultiHitCounter = 0;
gBattleOutcome = 0;
gBattleExecBuffer = 0;
gPaydayMoney = 0;
gBattleResources->battleScriptsStack->size = 0;
gBattleResources->battleCallbackStack->size = 0;
for (i = 0; i < BATTLE_COMMUNICATION_ENTRIES_COUNT; i++)
gBattleCommunication[i] = 0;
gPauseCounterBattle = 0;
gBattleMoveDamage = 0;
gUnknown_020243FC = 0;
gBattleScripting.animTurn = 0;
gBattleScripting.animTargetsHit = 0;
gLeveledUpInBattle = 0;
gAbsentBankFlags = 0;
gBattleStruct->runTries = 0;
gBattleStruct->field_79 = 0;
gBattleStruct->field_7A = 0;
*(&gBattleStruct->field_7C) = gBaseStats[GetMonData(&gEnemyParty[0], MON_DATA_SPECIES)].catchRate * 100 / 1275;
gBattleStruct->field_7B = 3;
gBattleStruct->wildVictorySong = 0;
gBattleStruct->moneyMultiplier = 1;
for (i = 0; i < 8; i++)
{
*((u8 *)gBattleStruct->mirrorMoves + i) = 0;
*((u8 *)gBattleStruct->usedHeldItems + i) = 0;
*((u8 *)gBattleStruct->choicedMove + i) = 0;
*((u8 *)gBattleStruct->changedItems + i) = 0;
*(i + 0 * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = 0;
*(i + 1 * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = 0;
*(i + 2 * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = 0;
*(i + 3 * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = 0;
}
for (i = 0; i < BATTLE_BANKS_COUNT; i++)
{
*(gBattleStruct->AI_monToSwitchIntoId + i) = 6;
}
gBattleStruct->field_DF = 0;
gBattleStruct->field_92 = 0;
gRandomTurnNumber = Random();
dataPtr = (u8 *)(&gBattleResults);
for (i = 0; i < sizeof(struct BattleResults); i++)
dataPtr[i] = 0;
gBattleResults.unk5_6 = IsMonShiny(&gEnemyParty[0]);
gBattleStruct->field_2A0 = 0;
gBattleStruct->field_2A1 = 0;
}
void SwitchInClearSetData(void)
{
struct DisableStruct disableStructCopy = gDisableStructs[gActiveBank];
s32 i;
u8 *ptr;
if (gBattleMoves[gCurrentMove].effect != EFFECT_BATON_PASS)
{
for (i = 0; i < BATTLE_STATS_NO; i++)
gBattleMons[gActiveBank].statStages[i] = 6;
for (i = 0; i < gNoOfAllBanks; i++)
{
if ((gBattleMons[i].status2 & STATUS2_ESCAPE_PREVENTION) && gDisableStructs[i].bankPreventingEscape == gActiveBank)
gBattleMons[i].status2 &= ~STATUS2_ESCAPE_PREVENTION;
if ((gStatuses3[i] & STATUS3_ALWAYS_HITS) && gDisableStructs[i].bankWithSureHit == gActiveBank)
{
gStatuses3[i] &= ~STATUS3_ALWAYS_HITS;
gDisableStructs[i].bankWithSureHit = 0;
}
}
}
if (gBattleMoves[gCurrentMove].effect == EFFECT_BATON_PASS)
{
gBattleMons[gActiveBank].status2 &= (STATUS2_CONFUSION | STATUS2_FOCUS_ENERGY | STATUS2_SUBSTITUTE | STATUS2_ESCAPE_PREVENTION | STATUS2_CURSED);
gStatuses3[gActiveBank] &= (STATUS3_LEECHSEED_BANK | STATUS3_LEECHSEED | STATUS3_ALWAYS_HITS | STATUS3_PERISH_SONG | STATUS3_ROOTED | STATUS3_MUDSPORT | STATUS3_WATERSPORT);
for (i = 0; i < gNoOfAllBanks; i++)
{
if (GetBankSide(gActiveBank) != GetBankSide(i)
&& (gStatuses3[i] & STATUS3_ALWAYS_HITS) != 0
&& (gDisableStructs[i].bankWithSureHit == gActiveBank))
{
gStatuses3[i] &= ~STATUS3_ALWAYS_HITS;
gStatuses3[i] |= 0x10;
}
}
}
else
{
gBattleMons[gActiveBank].status2 = 0;
gStatuses3[gActiveBank] = 0;
}
for (i = 0; i < gNoOfAllBanks; i++)
{
if (gBattleMons[i].status2 & STATUS2_INFATUATED_WITH(gActiveBank))
gBattleMons[i].status2 &= ~(STATUS2_INFATUATED_WITH(gActiveBank));
if ((gBattleMons[i].status2 & STATUS2_WRAPPED) && *(gBattleStruct->wrappedBy + i) == gActiveBank)
gBattleMons[i].status2 &= ~(STATUS2_WRAPPED);
}
gActionSelectionCursor[gActiveBank] = 0;
gMoveSelectionCursor[gActiveBank] = 0;
ptr = (u8 *)&gDisableStructs[gActiveBank];
for (i = 0; i < sizeof(struct DisableStruct); i++)
ptr[i] = 0;
if (gBattleMoves[gCurrentMove].effect == EFFECT_BATON_PASS)
{
gDisableStructs[gActiveBank].substituteHP = disableStructCopy.substituteHP;
gDisableStructs[gActiveBank].bankWithSureHit = disableStructCopy.bankWithSureHit;
gDisableStructs[gActiveBank].perishSongTimer1 = disableStructCopy.perishSongTimer1;
gDisableStructs[gActiveBank].perishSongTimer2 = disableStructCopy.perishSongTimer2;
gDisableStructs[gActiveBank].bankPreventingEscape = disableStructCopy.bankPreventingEscape;
}
gBattleMoveFlags = 0;
gDisableStructs[gActiveBank].isFirstTurn = 2;
gDisableStructs[gActiveBank].truantUnknownBit = disableStructCopy.truantUnknownBit;
gLastMoves[gActiveBank] = 0;
gLastLandedMoves[gActiveBank] = 0;
gLastHitByType[gActiveBank] = 0;
gLastResultingMoves[gActiveBank] = 0;
gLastPrintedMoves[gActiveBank] = 0;
gLastHitBy[gActiveBank] = 0xFF;
*(gBattleStruct->mirrorMoves + gActiveBank * 2 + 0) = 0;
*(gBattleStruct->mirrorMoves + gActiveBank * 2 + 1) = 0;
*(0 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = 0;
*(0 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) = 0;
*(1 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = 0;
*(1 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) = 0;
*(2 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = 0;
*(2 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) = 0;
*(3 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = 0;
*(3 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) = 0;
gBattleStruct->field_92 &= ~(gBitTable[gActiveBank]);
for (i = 0; i < gNoOfAllBanks; i++)
{
if (i != gActiveBank && GetBankSide(i) != GetBankSide(gActiveBank))
{
*(gBattleStruct->mirrorMoves + i * 2 + 0) = 0;
*(gBattleStruct->mirrorMoves + i * 2 + 1) = 0;
}
*(i * 8 + gActiveBank * 2 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = 0;
*(i * 8 + gActiveBank * 2 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) = 0;
}
*(u8*)((u8*)(&gBattleStruct->choicedMove[gActiveBank]) + 0) = 0;
*(u8*)((u8*)(&gBattleStruct->choicedMove[gActiveBank]) + 1) = 0;
gBattleResources->flags->flags[gActiveBank] = 0;
gCurrentMove = 0;
gBattleStruct->field_DA = 0xFF;
ClearBankMoveHistory(gActiveBank);
ClearBankAbilityHistory(gActiveBank);
}
void FaintClearSetData(void)
{
s32 i;
u8 *ptr;
for (i = 0; i < BATTLE_STATS_NO; i++)
gBattleMons[gActiveBank].statStages[i] = 6;
gBattleMons[gActiveBank].status2 = 0;
gStatuses3[gActiveBank] = 0;
for (i = 0; i < gNoOfAllBanks; i++)
{
if ((gBattleMons[i].status2 & STATUS2_ESCAPE_PREVENTION) && gDisableStructs[i].bankPreventingEscape == gActiveBank)
gBattleMons[i].status2 &= ~STATUS2_ESCAPE_PREVENTION;
if (gBattleMons[i].status2 & STATUS2_INFATUATED_WITH(gActiveBank))
gBattleMons[i].status2 &= ~(STATUS2_INFATUATED_WITH(gActiveBank));
if ((gBattleMons[i].status2 & STATUS2_WRAPPED) && *(gBattleStruct->wrappedBy + i) == gActiveBank)
gBattleMons[i].status2 &= ~(STATUS2_WRAPPED);
}
gActionSelectionCursor[gActiveBank] = 0;
gMoveSelectionCursor[gActiveBank] = 0;
ptr = (u8 *)&gDisableStructs[gActiveBank];
for (i = 0; i < sizeof(struct DisableStruct); i++)
ptr[i] = 0;
gProtectStructs[gActiveBank].protected = 0;
gProtectStructs[gActiveBank].endured = 0;
gProtectStructs[gActiveBank].onlyStruggle = 0;
gProtectStructs[gActiveBank].helpingHand = 0;
gProtectStructs[gActiveBank].bounceMove = 0;
gProtectStructs[gActiveBank].stealMove = 0;
gProtectStructs[gActiveBank].flag0Unknown = 0;
gProtectStructs[gActiveBank].prlzImmobility = 0;
gProtectStructs[gActiveBank].confusionSelfDmg = 0;
gProtectStructs[gActiveBank].targetNotAffected = 0;
gProtectStructs[gActiveBank].chargingTurn = 0;
gProtectStructs[gActiveBank].fleeFlag = 0;
gProtectStructs[gActiveBank].usedImprisionedMove = 0;
gProtectStructs[gActiveBank].loveImmobility = 0;
gProtectStructs[gActiveBank].usedDisabledMove = 0;
gProtectStructs[gActiveBank].usedTauntedMove = 0;
gProtectStructs[gActiveBank].flag2Unknown = 0;
gProtectStructs[gActiveBank].flinchImmobility = 0;
gProtectStructs[gActiveBank].notFirstStrike = 0;
gDisableStructs[gActiveBank].isFirstTurn = 2;
gLastMoves[gActiveBank] = 0;
gLastLandedMoves[gActiveBank] = 0;
gLastHitByType[gActiveBank] = 0;
gLastResultingMoves[gActiveBank] = 0;
gLastPrintedMoves[gActiveBank] = 0;
gLastHitBy[gActiveBank] = 0xFF;
*(u8*)((u8*)(&gBattleStruct->choicedMove[gActiveBank]) + 0) = 0;
*(u8*)((u8*)(&gBattleStruct->choicedMove[gActiveBank]) + 1) = 0;
*(gBattleStruct->mirrorMoves + gActiveBank * 2 + 0) = 0;
*(gBattleStruct->mirrorMoves + gActiveBank * 2 + 1) = 0;
*(0 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = 0;
*(0 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) = 0;
*(1 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = 0;
*(1 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) = 0;
*(2 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = 0;
*(2 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) = 0;
*(3 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = 0;
*(3 * 2 + gActiveBank * 8 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) = 0;
gBattleStruct->field_92 &= ~(gBitTable[gActiveBank]);
for (i = 0; i < gNoOfAllBanks; i++)
{
if (i != gActiveBank && GetBankSide(i) != GetBankSide(gActiveBank))
{
*(gBattleStruct->mirrorMoves + i * 2 + 0) = 0;
*(gBattleStruct->mirrorMoves + i * 2 + 1) = 0;
}
*(i * 8 + gActiveBank * 2 + (u8*)(gBattleStruct->mirrorMoveArrays) + 0) = 0;
*(i * 8 + gActiveBank * 2 + (u8*)(gBattleStruct->mirrorMoveArrays) + 1) = 0;
}
gBattleResources->flags->flags[gActiveBank] = 0;
gBattleMons[gActiveBank].type1 = gBaseStats[gBattleMons[gActiveBank].species].type1;
gBattleMons[gActiveBank].type2 = gBaseStats[gBattleMons[gActiveBank].species].type2;
ClearBankMoveHistory(gActiveBank);
ClearBankAbilityHistory(gActiveBank);
}
static void BattleIntroGetMonsData(void)
{
switch (gBattleCommunication[MULTIUSE_STATE])
{
case 0:
gActiveBank = gBattleCommunication[1];
EmitGetMonData(0, 0, 0);
MarkBufferBankForExecution(gActiveBank);
gBattleCommunication[MULTIUSE_STATE]++;
break;
case 1:
if (gBattleExecBuffer == 0)
{
gBattleCommunication[1]++;
if (gBattleCommunication[1] == gNoOfAllBanks)
gBattleMainFunc = BattleIntroPrepareBackgroundSlide;
else
gBattleCommunication[MULTIUSE_STATE] = 0;
}
break;
}
}
static void BattleIntroPrepareBackgroundSlide(void)
{
if (gBattleExecBuffer == 0)
{
gActiveBank = GetBankByIdentity(0);
EmitIntroSlide(0, gBattleTerrain);
MarkBufferBankForExecution(gActiveBank);
gBattleMainFunc = BattleIntroDrawTrainersOrMonsSprites;
gBattleCommunication[0] = 0;
gBattleCommunication[1] = 0;
}
}
static void BattleIntroDrawTrainersOrMonsSprites(void)
{
u8 *ptr;
s32 i;
if (gBattleExecBuffer)
return;
for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++)
{
if ((gBattleTypeFlags & BATTLE_TYPE_SAFARI)
&& GetBankSide(gActiveBank) == SIDE_PLAYER)
{
ptr = (u8 *)&gBattleMons[gActiveBank];
for (i = 0; i < sizeof(struct BattlePokemon); i++)
ptr[i] = 0;
}
else
{
u16* hpOnSwitchout;
ptr = (u8 *)&gBattleMons[gActiveBank];
for (i = 0; i < sizeof(struct BattlePokemon); i++)
ptr[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);
hpOnSwitchout = &gBattleStruct->hpOnSwitchout[GetBankSide(gActiveBank)];
*hpOnSwitchout = gBattleMons[gActiveBank].hp;
for (i = 0; i < BATTLE_STATS_NO; i++)
gBattleMons[gActiveBank].statStages[i] = 6;
gBattleMons[gActiveBank].status2 = 0;
}
if (GetBankIdentity(gActiveBank) == IDENTITY_PLAYER_MON1)
{
EmitDrawTrainerPic(0);
MarkBufferBankForExecution(gActiveBank);
}
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER)
{
if (GetBankIdentity(gActiveBank) == IDENTITY_OPPONENT_MON1)
{
EmitDrawTrainerPic(0);
MarkBufferBankForExecution(gActiveBank);
}
if (GetBankSide(gActiveBank) == SIDE_OPPONENT
&& !(gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER
| BATTLE_TYPE_FRONTIER
| BATTLE_TYPE_LINK
| BATTLE_TYPE_x2000000
| BATTLE_TYPE_x4000000)))
{
HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gActiveBank].species), FLAG_SET_SEEN, gBattleMons[gActiveBank].personality);
}
}
else
{
if (GetBankSide(gActiveBank) == SIDE_OPPONENT)
{
if (!(gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER
| BATTLE_TYPE_FRONTIER
| BATTLE_TYPE_LINK
| BATTLE_TYPE_x2000000
| BATTLE_TYPE_x4000000)))
{
HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gActiveBank].species), FLAG_SET_SEEN, gBattleMons[gActiveBank].personality);
}
EmitLoadMonSprite(0);
MarkBufferBankForExecution(gActiveBank);
gBattleResults.lastOpponentSpecies = GetMonData(&gEnemyParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES, NULL);
}
}
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
{
if (GetBankIdentity(gActiveBank) == IDENTITY_PLAYER_MON2
|| GetBankIdentity(gActiveBank) == IDENTITY_OPPONENT_MON2)
{
EmitDrawTrainerPic(0);
MarkBufferBankForExecution(gActiveBank);
}
}
if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS && GetBankIdentity(gActiveBank) == IDENTITY_OPPONENT_MON2)
{
EmitDrawTrainerPic(0);
MarkBufferBankForExecution(gActiveBank);
}
if (gBattleTypeFlags & BATTLE_TYPE_ARENA)
sub_81A56B4();
}
gBattleMainFunc = BattleIntroDrawPartySummaryScreens;
}
static void BattleIntroDrawPartySummaryScreens(void)
{
s32 i;
struct HpAndStatus hpStatus[6];
if (gBattleExecBuffer)
return;
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER)
{
for (i = 0; i < PARTY_SIZE; i++)
{
if (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES2) == SPECIES_NONE
|| GetMonData(&gEnemyParty[i], MON_DATA_SPECIES2) == SPECIES_EGG)
{
hpStatus[i].hp = 0xFFFF;
hpStatus[i].status = 0;
}
else
{
hpStatus[i].hp = GetMonData(&gEnemyParty[i], MON_DATA_HP);
hpStatus[i].status = GetMonData(&gEnemyParty[i], MON_DATA_STATUS);
}
}
gActiveBank = GetBankByIdentity(IDENTITY_OPPONENT_MON1);
EmitDrawPartyStatusSummary(0, hpStatus, 0x80);
MarkBufferBankForExecution(gActiveBank);
for (i = 0; i < PARTY_SIZE; i++)
{
if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) == SPECIES_NONE
|| GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) == SPECIES_EGG)
{
hpStatus[i].hp = 0xFFFF;
hpStatus[i].status = 0;
}
else
{
hpStatus[i].hp = GetMonData(&gPlayerParty[i], MON_DATA_HP);
hpStatus[i].status = GetMonData(&gPlayerParty[i], MON_DATA_STATUS);
}
}
gActiveBank = GetBankByIdentity(IDENTITY_PLAYER_MON1);
EmitDrawPartyStatusSummary(0, hpStatus, 0x80);
MarkBufferBankForExecution(gActiveBank);
gBattleMainFunc = BattleIntroPrintTrainerWantsToBattle;
}
else
{
// The struct gets set here, but nothing is ever done with it since
// wild battles don't show the party summary.
// Still, there's no point in having dead code.
for (i = 0; i < 6; i++)
{
if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) == SPECIES_NONE
|| GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) == SPECIES_EGG)
{
hpStatus[i].hp = 0xFFFF;
hpStatus[i].status = 0;
}
else
{
hpStatus[i].hp = GetMonData(&gPlayerParty[i], MON_DATA_HP);
hpStatus[i].status = GetMonData(&gPlayerParty[i], MON_DATA_STATUS);
}
}
gBattleMainFunc = BattleIntroPrintWildMonAttacked;
}
}
static void BattleIntroPrintTrainerWantsToBattle(void)
{
if (gBattleExecBuffer == 0)
{
gActiveBank = GetBankByIdentity(IDENTITY_OPPONENT_MON1);
PrepareStringBattle(STRINGID_INTROMSG, gActiveBank);
gBattleMainFunc = BattleIntroPrintOpponentSendsOut;
}
}
static void BattleIntroPrintWildMonAttacked(void)
{
if (gBattleExecBuffer == 0)
{
gBattleMainFunc = BattleIntroPrintPlayerSendsOut;
PrepareStringBattle(STRINGID_INTROMSG, 0);
}
}
static void BattleIntroPrintOpponentSendsOut(void)
{
u32 identity;
if (gBattleExecBuffer)
return;
if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED))
identity = IDENTITY_OPPONENT_MON1;
else if (gBattleTypeFlags & BATTLE_TYPE_x2000000)
{
if (gBattleTypeFlags & BATTLE_TYPE_x80000000)
identity = IDENTITY_OPPONENT_MON1;
else
identity = IDENTITY_PLAYER_MON1;
}
else
identity = IDENTITY_OPPONENT_MON1;
PrepareStringBattle(STRINGID_INTROSENDOUT, GetBankByIdentity(identity));
gBattleMainFunc = BattleIntroOpponent1SendsOutMonAnimation;
}
static void BattleIntroOpponent2SendsOutMonAnimation(void)
{
u32 identity;
if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED))
identity = IDENTITY_OPPONENT_MON2;
else if (gBattleTypeFlags & BATTLE_TYPE_x2000000)
{
if (gBattleTypeFlags & BATTLE_TYPE_x80000000)
identity = IDENTITY_OPPONENT_MON2;
else
identity = IDENTITY_PLAYER_MON2;
}
else
identity = IDENTITY_OPPONENT_MON2;
for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++)
{
if (GetBankIdentity(gActiveBank) == identity)
{
EmitIntroTrainerBallThrow(0);
MarkBufferBankForExecution(gActiveBank);
}
}
gBattleMainFunc = BattleIntroRecordMonsToDex;
}
#ifdef NONMATCHING
static void BattleIntroOpponent1SendsOutMonAnimation(void)
{
u32 identity;
if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED))
identity = IDENTITY_OPPONENT_MON1;
else if (gBattleTypeFlags & BATTLE_TYPE_x2000000)
{
if (gBattleTypeFlags & BATTLE_TYPE_x80000000)
identity = IDENTITY_OPPONENT_MON1;
else
identity = IDENTITY_PLAYER_MON1;
}
else
identity = IDENTITY_OPPONENT_MON1;
if (gBattleExecBuffer)
return;
for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++)
{
if (GetBankIdentity(gActiveBank) == identity)
{
EmitIntroTrainerBallThrow(0);
MarkBufferBankForExecution(gActiveBank);
if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS))
{
gBattleMainFunc = BattleIntroOpponent2SendsOutMonAnimation;
return;
}
}
}
gBattleMainFunc = BattleIntroRecordMonsToDex;
}
#else
__attribute__((naked))
static void BattleIntroOpponent1SendsOutMonAnimation(void)
{
asm(".syntax unified\n\
push {r4-r6,lr}\n\
ldr r0, =gBattleTypeFlags\n\
ldr r2, [r0]\n\
movs r0, 0x80\n\
lsls r0, 17\n\
ands r0, r2\n\
cmp r0, 0\n\
beq _0803B298\n\
movs r0, 0x80\n\
lsls r0, 18\n\
ands r0, r2\n\
cmp r0, 0\n\
beq _0803B298\n\
movs r1, 0x80\n\
lsls r1, 24\n\
ands r1, r2\n\
negs r0, r1\n\
orrs r0, r1\n\
lsrs r5, r0, 31\n\
b _0803B29A\n\
.pool\n\
_0803B288:\n\
ldr r1, =gBattleMainFunc\n\
ldr r0, =BattleIntroOpponent2SendsOutMonAnimation\n\
b _0803B2F0\n\
.pool\n\
_0803B298:\n\
movs r5, 0x1\n\
_0803B29A:\n\
ldr r0, =gBattleExecBuffer\n\
ldr r2, [r0]\n\
cmp r2, 0\n\
bne _0803B2F2\n\
ldr r0, =gActiveBank\n\
strb r2, [r0]\n\
ldr r1, =gNoOfAllBanks\n\
adds r4, r0, 0\n\
ldrb r1, [r1]\n\
cmp r2, r1\n\
bcs _0803B2EC\n\
adds r6, r4, 0\n\
_0803B2B2:\n\
ldrb r0, [r4]\n\
bl GetBankIdentity\n\
lsls r0, 24\n\
lsrs r0, 24\n\
cmp r0, r5\n\
bne _0803B2D8\n\
movs r0, 0\n\
bl EmitIntroTrainerBallThrow\n\
ldrb r0, [r4]\n\
bl MarkBufferBankForExecution\n\
ldr r0, =gBattleTypeFlags\n\
ldr r0, [r0]\n\
ldr r1, =0x00008040\n\
ands r0, r1\n\
cmp r0, 0\n\
bne _0803B288\n\
_0803B2D8:\n\
ldrb r0, [r6]\n\
adds r0, 0x1\n\
strb r0, [r6]\n\
ldr r1, =gNoOfAllBanks\n\
lsls r0, 24\n\
lsrs r0, 24\n\
ldr r4, =gActiveBank\n\
ldrb r1, [r1]\n\
cmp r0, r1\n\
bcc _0803B2B2\n\
_0803B2EC:\n\
ldr r1, =gBattleMainFunc\n\
ldr r0, =BattleIntroRecordMonsToDex\n\
_0803B2F0:\n\
str r0, [r1]\n\
_0803B2F2:\n\
pop {r4-r6}\n\
pop {r0}\n\
bx r0\n\
.pool\n\
.syntax divided");
}
#endif // NONMATCHING
static void BattleIntroRecordMonsToDex(void)
{
if (gBattleExecBuffer == 0)
{
for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++)
{
if (GetBankSide(gActiveBank) == SIDE_OPPONENT
&& !(gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER
| BATTLE_TYPE_FRONTIER
| BATTLE_TYPE_LINK
| BATTLE_TYPE_x2000000
| BATTLE_TYPE_x4000000)))
{
HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gActiveBank].species), FLAG_SET_SEEN, gBattleMons[gActiveBank].personality);
}
}
gBattleMainFunc = BattleIntroPrintPlayerSendsOut;
}
}
void sub_803B3AC(void) // unused
{
if (gBattleExecBuffer == 0)
gBattleMainFunc = BattleIntroPrintPlayerSendsOut;
}
static void BattleIntroPrintPlayerSendsOut(void)
{
if (gBattleExecBuffer == 0)
{
u8 identity;
if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED))
identity = IDENTITY_PLAYER_MON1;
else if (gBattleTypeFlags & BATTLE_TYPE_x2000000)
{
if (gBattleTypeFlags & BATTLE_TYPE_x80000000)
identity = IDENTITY_PLAYER_MON1;
else
identity = IDENTITY_OPPONENT_MON1;
}
else
identity = IDENTITY_PLAYER_MON1;
if (!(gBattleTypeFlags & BATTLE_TYPE_SAFARI))
PrepareStringBattle(STRINGID_INTROSENDOUT, GetBankByIdentity(identity));
gBattleMainFunc = BattleIntroPlayer1SendsOutMonAnimation;
}
}
static void BattleIntroPlayer2SendsOutMonAnimation(void)
{
u32 identity;
if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED))
identity = IDENTITY_PLAYER_MON2;
else if (gBattleTypeFlags & BATTLE_TYPE_x2000000)
{
if (gBattleTypeFlags & BATTLE_TYPE_x80000000)
identity = IDENTITY_PLAYER_MON2;
else
identity = IDENTITY_OPPONENT_MON2;
}
else
identity = IDENTITY_PLAYER_MON2;
for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++)
{
if (GetBankIdentity(gActiveBank) == identity)
{
EmitIntroTrainerBallThrow(0);
MarkBufferBankForExecution(gActiveBank);
}
}
gBattleStruct->switchInAbilitiesCounter = 0;
gBattleStruct->switchInItemsCounter = 0;
gBattleStruct->overworldWeatherDone = FALSE;
gBattleMainFunc = TryDoEventsBeforeFirstTurn;
}
static void BattleIntroPlayer1SendsOutMonAnimation(void)
{
u32 identity;
if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED))
identity = IDENTITY_PLAYER_MON1;
else if (gBattleTypeFlags & BATTLE_TYPE_x2000000)
{
if (gBattleTypeFlags & BATTLE_TYPE_x80000000)
identity = IDENTITY_PLAYER_MON1;
else
identity = IDENTITY_OPPONENT_MON1;
}
else
identity = IDENTITY_PLAYER_MON1;
if (gBattleExecBuffer)
return;
for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++)
{
if (GetBankIdentity(gActiveBank) == identity)
{
EmitIntroTrainerBallThrow(0);
MarkBufferBankForExecution(gActiveBank);
if (gBattleTypeFlags & (BATTLE_TYPE_MULTI))
{
gBattleMainFunc = BattleIntroPlayer2SendsOutMonAnimation;
return;
}
}
}
gBattleStruct->switchInAbilitiesCounter = 0;
gBattleStruct->switchInItemsCounter = 0;
gBattleStruct->overworldWeatherDone = FALSE;
gBattleMainFunc = TryDoEventsBeforeFirstTurn;
}
void sub_803B598(void) // unused
{
if (gBattleExecBuffer == 0)
{
for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++)
{
if (GetBankSide(gActiveBank) == SIDE_PLAYER)
{
EmitSwitchInAnim(0, gBattlePartyID[gActiveBank], FALSE);
MarkBufferBankForExecution(gActiveBank);
}
}
gBattleStruct->switchInAbilitiesCounter = 0;
gBattleStruct->switchInItemsCounter = 0;
gBattleStruct->overworldWeatherDone = FALSE;
gBattleMainFunc = TryDoEventsBeforeFirstTurn;
}
}
static void TryDoEventsBeforeFirstTurn(void)
{
s32 i;
s32 j;
u8 effect = 0;
if (gBattleExecBuffer)
return;
if (gBattleStruct->switchInAbilitiesCounter == 0)
{
for (i = 0; i < gNoOfAllBanks; i++)
gBanksByTurnOrder[i] = i;
for (i = 0; i < gNoOfAllBanks - 1; i++)
{
for (j = i + 1; j < gNoOfAllBanks; j++)
{
if (GetWhoStrikesFirst(gBanksByTurnOrder[i], gBanksByTurnOrder[j], TRUE) != 0)
SwapTurnOrder(i, j);
}
}
}
if (!gBattleStruct->overworldWeatherDone
&& AbilityBattleEffects(0, 0, 0, ABILITYEFFECT_SWITCH_IN_WEATHER, 0) != 0)
{
gBattleStruct->overworldWeatherDone = TRUE;
return;
}
// check all switch in abilities happening from the fastest mon to slowest
while (gBattleStruct->switchInAbilitiesCounter < gNoOfAllBanks)
{
if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, gBanksByTurnOrder[gBattleStruct->switchInAbilitiesCounter], 0, 0, 0) != 0)
effect++;
gBattleStruct->switchInAbilitiesCounter++;
if (effect)
return;
}
if (AbilityBattleEffects(ABILITYEFFECT_INTIMIDATE1, 0, 0, 0, 0) != 0)
return;
if (AbilityBattleEffects(ABILITYEFFECT_TRACE, 0, 0, 0, 0) != 0)
return;
// check all switch in items having effect from the fastest mon to slowest
while (gBattleStruct->switchInItemsCounter < gNoOfAllBanks)
{
if (ItemBattleEffects(ITEMEFFECT_ON_SWITCH_IN, gBanksByTurnOrder[gBattleStruct->switchInItemsCounter], 0) != 0)
effect++;
gBattleStruct->switchInItemsCounter++;
if (effect)
return;
}
for (i = 0; i < BATTLE_BANKS_COUNT; i++)
{
*(gBattleStruct->monToSwitchIntoId + i) = 6;
gActionForBanks[i] = ACTION_INIT_VALUE;
gChosenMovesByBanks[i] = MOVE_NONE;
}
TurnValuesCleanUp(FALSE);
SpecialStatusesClear();
*(&gBattleStruct->field_91) = gAbsentBankFlags;
BattleHandleAddTextPrinter(gText_EmptyString3, 0);
gBattleMainFunc = HandleTurnActionSelectionState;
ResetSentPokesToOpponentValue();
for (i = 0; i < BATTLE_COMMUNICATION_ENTRIES_COUNT; i++)
gBattleCommunication[i] = 0;
for (i = 0; i < gNoOfAllBanks; i++)
gBattleMons[i].status2 &= ~(STATUS2_FLINCHED);
*(&gBattleStruct->turnEffectsTracker) = 0;
*(&gBattleStruct->turnEffectsBank) = 0;
*(&gBattleStruct->field_1A0) = 0;
*(&gBattleStruct->field_1A1) = 0;
gBattleScripting.atk49_state = 0;
gBattleStruct->field_4D = 0;
gBattleStruct->turncountersTracker = 0;
gBattleMoveFlags = 0;
gRandomTurnNumber = Random();
if (gBattleTypeFlags & BATTLE_TYPE_ARENA)
{
StopCryAndClearCrySongs();
BattleScriptExecute(BattleScript_82DB8BE);
}
}
static void HandleEndTurn_ContinueBattle(void)
{
s32 i;
if (gBattleExecBuffer == 0)
{
gBattleMainFunc = BattleTurnPassed;
for (i = 0; i < BATTLE_COMMUNICATION_ENTRIES_COUNT; i++)
gBattleCommunication[i] = 0;
for (i = 0; i < gNoOfAllBanks; i++)
{
gBattleMons[i].status2 &= ~(STATUS2_FLINCHED);
if ((gBattleMons[i].status1 & STATUS_SLEEP) && (gBattleMons[i].status2 & STATUS2_MULTIPLETURNS))
CancelMultiTurnMoves(i);
}
gBattleStruct->turnEffectsTracker = 0;
gBattleStruct->turnEffectsBank = 0;
gBattleStruct->field_1A0 = 0;
gBattleStruct->field_1A1 = 0;
gBattleStruct->turncountersTracker = 0;
gBattleMoveFlags = 0;
}
}
void BattleTurnPassed(void)
{
s32 i;
TurnValuesCleanUp(TRUE);
if (gBattleOutcome == 0)
{
if (UpdateTurnCounters() != 0)
return;
if (TurnBasedEffects() != 0)
return;
}
if (sub_8041728() != 0)
return;
gBattleStruct->field_4D = 0;
if (sub_8041364() != 0)
return;
TurnValuesCleanUp(FALSE);
gHitMarker &= ~(HITMARKER_NO_ATTACKSTRING);
gHitMarker &= ~(HITMARKER_UNABLE_TO_USE_MOVE);
gHitMarker &= ~(HITMARKER_x400000);
gHitMarker &= ~(HITMARKER_x100000);
gBattleScripting.animTurn = 0;
gBattleScripting.animTargetsHit = 0;
gBattleScripting.atk49_state = 0;
gBattleMoveDamage = 0;
gBattleMoveFlags = 0;
for (i = 0; i < 5; i++)
gBattleCommunication[i] = 0;
if (gBattleOutcome != 0)
{
gCurrentActionFuncId = 12;
gBattleMainFunc = RunTurnActionsFunctions;
return;
}
if (gBattleResults.battleTurnCounter < 0xFF)
{
gBattleResults.battleTurnCounter++;
gBattleStruct->field_DA++;
}
for (i = 0; i < gNoOfAllBanks; i++)
{
gActionForBanks[i] = ACTION_INIT_VALUE;
gChosenMovesByBanks[i] = MOVE_NONE;
}
for (i = 0; i < 4; i++)
*(gBattleStruct->monToSwitchIntoId + i) = 6;
*(&gBattleStruct->field_91) = gAbsentBankFlags;
BattleHandleAddTextPrinter(gText_EmptyString3, 0);
gBattleMainFunc = HandleTurnActionSelectionState;
gRandomTurnNumber = Random();
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
BattleScriptExecute(BattleScript_82DB881);
else if (gBattleTypeFlags & BATTLE_TYPE_ARENA && gBattleStruct->field_DA == 0)
BattleScriptExecute(BattleScript_82DB8BE);
}
u8 IsRunningFromBattleImpossible(void)
{
u8 holdEffect;
u8 side;
s32 i;
if (gBattleMons[gActiveBank].item == ITEM_ENIGMA_BERRY)
holdEffect = gEnigmaBerries[gActiveBank].holdEffect;
else
holdEffect = ItemId_GetHoldEffect(gBattleMons[gActiveBank].item);
gStringBank = gActiveBank;
if (holdEffect == HOLD_EFFECT_CAN_ALWAYS_RUN)
return 0;
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
return 0;
if (gBattleMons[gActiveBank].ability == ABILITY_RUN_AWAY)
return 0;
side = GetBankSide(gActiveBank);
for (i = 0; i < gNoOfAllBanks; i++)
{
if (side != GetBankSide(i)
&& gBattleMons[i].ability == ABILITY_SHADOW_TAG)
{
gBattleScripting.bank = i;
gLastUsedAbility = gBattleMons[i].ability;
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
return 2;
}
if (side != GetBankSide(i)
&& gBattleMons[gActiveBank].ability != ABILITY_LEVITATE
&& gBattleMons[gActiveBank].type1 != TYPE_FLYING
&& gBattleMons[gActiveBank].type2 != TYPE_FLYING
&& gBattleMons[i].ability == ABILITY_ARENA_TRAP)
{
gBattleScripting.bank = i;
gLastUsedAbility = gBattleMons[i].ability;
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
return 2;
}
}
i = AbilityBattleEffects(ABILITYEFFECT_CHECK_FIELD_EXCEPT_BANK, gActiveBank, ABILITY_MAGNET_PULL, 0, 0);
if (i != 0 && (gBattleMons[gActiveBank].type1 == TYPE_STEEL || gBattleMons[gActiveBank].type2 == TYPE_STEEL))
{
gBattleScripting.bank = i - 1;
gLastUsedAbility = gBattleMons[i - 1].ability;
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
return 2;
}
if ((gBattleMons[gActiveBank].status2 & (STATUS2_ESCAPE_PREVENTION | STATUS2_WRAPPED))
|| (gStatuses3[gActiveBank] & STATUS3_ROOTED))
{
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
return 1;
}
if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE)
{
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
return 1;
}
return 0;
}
void sub_803BDA0(u8 bank)
{
s32 i;
u8 r4;
u8 r1;
// gBattleStruct->field_60[bank][i]
for (i = 0; i < 3; i++)
gUnknown_0203CF00[i] = *(bank * 3 + i + (u8*)(gBattleStruct->field_60));
r4 = pokemon_order_func(gBattlePartyID[bank]);
r1 = pokemon_order_func(*(gBattleStruct->monToSwitchIntoId + bank));
sub_81B8FB0(r4, r1);
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
{
for (i = 0; i < 3; i++)
{
*(bank * 3 + i + (u8*)(gBattleStruct->field_60)) = gUnknown_0203CF00[i];
*((bank ^ BIT_MON) * 3 + i + (u8*)(gBattleStruct->field_60)) = gUnknown_0203CF00[i];
}
}
else
{
for (i = 0; i < 3; i++)
{
*(bank * 3 + i + (u8*)(gBattleStruct->field_60)) = gUnknown_0203CF00[i];
}
}
}
enum
{
STATE_TURN_START_RECORD,
STATE_BEFORE_ACTION_CHOSEN,
STATE_WAIT_ACTION_CHOSEN,
STATE_WAIT_ACTION_CASE_CHOSEN,
STATE_WAIT_ACTION_CONFIRMED_STANDBY,
STATE_WAIT_ACTION_CONFIRMED,
STATE_SELECTION_SCRIPT,
STATE_WAIT_SET_BEFORE_ACTION,
STATE_SELECTION_SCRIPT_MAY_RUN
};
static void HandleTurnActionSelectionState(void)
{
s32 i;
gBattleCommunication[ACTIONS_CONFIRMED_COUNT] = 0;
for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++)
{
u8 identity = GetBankIdentity(gActiveBank);
switch (gBattleCommunication[gActiveBank])
{
case STATE_TURN_START_RECORD: // recorded battle related on start of every turn
RecordedBattle_CopyBankMoves();
gBattleCommunication[gActiveBank] = STATE_BEFORE_ACTION_CHOSEN;
break;
case STATE_BEFORE_ACTION_CHOSEN: // choose an action
*(gBattleStruct->monToSwitchIntoId + gActiveBank) = 6;
if (gBattleTypeFlags & BATTLE_TYPE_MULTI
|| !(identity & BIT_MON)
|| gBattleStruct->field_91 & gBitTable[GetBankByIdentity(identity ^ BIT_MON)]
|| gBattleCommunication[GetBankByIdentity(identity ^ BIT_MON)] == 5)
{
if (gBattleStruct->field_91 & gBitTable[gActiveBank])
{
gActionForBanks[gActiveBank] = ACTION_NOTHING_FAINTED;
if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI))
gBattleCommunication[gActiveBank] = STATE_WAIT_ACTION_CONFIRMED;
else
gBattleCommunication[gActiveBank] = STATE_WAIT_ACTION_CONFIRMED_STANDBY;
}
else
{
if (gBattleMons[gActiveBank].status2 & STATUS2_MULTIPLETURNS
|| gBattleMons[gActiveBank].status2 & STATUS2_RECHARGE)
{
gActionForBanks[gActiveBank] = ACTION_USE_MOVE;
gBattleCommunication[gActiveBank] = STATE_WAIT_ACTION_CONFIRMED_STANDBY;
}
else
{
EmitChooseAction(0, gActionForBanks[0], gBattleBufferB[0][1] | (gBattleBufferB[0][2] << 8));
MarkBufferBankForExecution(gActiveBank);
gBattleCommunication[gActiveBank]++;
}
}
}
break;
case STATE_WAIT_ACTION_CHOSEN: // try to perform an action
if (!(gBattleExecBuffer & ((gBitTable[gActiveBank]) | (0xF0000000) | (gBitTable[gActiveBank] << 4) | (gBitTable[gActiveBank] << 8) | (gBitTable[gActiveBank] << 0xC))))
{
RecordedBattle_SetBankAction(gActiveBank, gBattleBufferB[gActiveBank][1]);
gActionForBanks[gActiveBank] = gBattleBufferB[gActiveBank][1];
switch (gBattleBufferB[gActiveBank][1])
{
case ACTION_USE_MOVE:
if (AreAllMovesUnusable())
{
gBattleCommunication[gActiveBank] = STATE_SELECTION_SCRIPT;
*(gBattleStruct->selectionScriptFinished + gActiveBank) = FALSE;
*(gBattleStruct->stateIdAfterSelScript + gActiveBank) = STATE_WAIT_ACTION_CONFIRMED_STANDBY;
*(gBattleStruct->moveTarget + gActiveBank) = gBattleBufferB[gActiveBank][3];
return;
}
else if (gDisableStructs[gActiveBank].encoredMove != 0)
{
gChosenMovesByBanks[gActiveBank] = gDisableStructs[gActiveBank].encoredMove;
*(gBattleStruct->chosenMovePositions + gActiveBank) = gDisableStructs[gActiveBank].encoredMovePos;
gBattleCommunication[gActiveBank] = STATE_WAIT_ACTION_CONFIRMED_STANDBY;
return;
}
else
{
struct ChooseMoveStruct moveInfo;
moveInfo.species = gBattleMons[gActiveBank].species;
moveInfo.monType1 = gBattleMons[gActiveBank].type1;
moveInfo.monType2 = gBattleMons[gActiveBank].type2;
for (i = 0; i < 4; i++)
{
moveInfo.moves[i] = gBattleMons[gActiveBank].moves[i];
moveInfo.currentPp[i] = gBattleMons[gActiveBank].pp[i];
moveInfo.maxPp[i] = CalculatePPWithBonus(
gBattleMons[gActiveBank].moves[i],
gBattleMons[gActiveBank].ppBonuses,
i);
}
EmitChooseMove(0, (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) != 0, FALSE, &moveInfo);
MarkBufferBankForExecution(gActiveBank);
}
break;
case ACTION_USE_ITEM:
if (gBattleTypeFlags & (BATTLE_TYPE_LINK
| BATTLE_TYPE_FRONTIER_NO_PYRAMID
| BATTLE_TYPE_EREADER_TRAINER
| BATTLE_TYPE_x2000000))
{
RecordedBattle_ClearBankAction(gActiveBank, 1);
gSelectionBattleScripts[gActiveBank] = BattleScript_ActionSelectionItemsCantBeUsed;
gBattleCommunication[gActiveBank] = STATE_SELECTION_SCRIPT;
*(gBattleStruct->selectionScriptFinished + gActiveBank) = FALSE;
*(gBattleStruct->stateIdAfterSelScript + gActiveBank) = STATE_BEFORE_ACTION_CHOSEN;
return;
}
else
{
EmitChooseItem(0, gBattleStruct->field_60[gActiveBank]);
MarkBufferBankForExecution(gActiveBank);
}
break;
case ACTION_SWITCH:
*(gBattleStruct->field_58 + gActiveBank) = gBattlePartyID[gActiveBank];
if (gBattleMons[gActiveBank].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION)
|| gBattleTypeFlags & BATTLE_TYPE_ARENA
|| gStatuses3[gActiveBank] & STATUS3_ROOTED)
{
EmitChoosePokemon(0, 2, 6, ABILITY_NONE, gBattleStruct->field_60[gActiveBank]);
}
else if ((i = AbilityBattleEffects(ABILITYEFFECT_CHECK_OTHER_SIDE, gActiveBank, ABILITY_SHADOW_TAG, 0, 0))
|| ((i = AbilityBattleEffects(ABILITYEFFECT_CHECK_OTHER_SIDE, gActiveBank, ABILITY_ARENA_TRAP, 0, 0))
&& gBattleMons[gActiveBank].type1 != TYPE_FLYING
&& gBattleMons[gActiveBank].type2 != TYPE_FLYING
&& gBattleMons[gActiveBank].ability != ABILITY_LEVITATE)
|| ((i = AbilityBattleEffects(ABILITYEFFECT_CHECK_FIELD_EXCEPT_BANK, gActiveBank, ABILITY_MAGNET_PULL, 0, 0))
&& (gBattleMons[gActiveBank].type1 == TYPE_STEEL
|| gBattleMons[gActiveBank].type2 == TYPE_STEEL)))
{
EmitChoosePokemon(0, ((i - 1) << 4) | 4, 6, gLastUsedAbility, gBattleStruct->field_60[gActiveBank]);
}
else
{
if (gActiveBank == 2 && gActionForBanks[0] == ACTION_SWITCH)
EmitChoosePokemon(0, 0, *(gBattleStruct->monToSwitchIntoId + 0), ABILITY_NONE, gBattleStruct->field_60[gActiveBank]);
else if (gActiveBank == 3 && gActionForBanks[1] == ACTION_SWITCH)
EmitChoosePokemon(0, 0, *(gBattleStruct->monToSwitchIntoId + 1), ABILITY_NONE, gBattleStruct->field_60[gActiveBank]);
else
EmitChoosePokemon(0, 0, 6, ABILITY_NONE, gBattleStruct->field_60[gActiveBank]);
}
MarkBufferBankForExecution(gActiveBank);
break;
case ACTION_SAFARI_ZONE_BALL:
if (IsPlayerPartyAndPokemonStorageFull())
{
gSelectionBattleScripts[gActiveBank] = BattleScript_PrintFullBox;
gBattleCommunication[gActiveBank] = STATE_SELECTION_SCRIPT;
*(gBattleStruct->selectionScriptFinished + gActiveBank) = FALSE;
*(gBattleStruct->stateIdAfterSelScript + gActiveBank) = STATE_BEFORE_ACTION_CHOSEN;
return;
}
break;
case ACTION_POKEBLOCK_CASE:
EmitChooseItem(0, gBattleStruct->field_60[gActiveBank]);
MarkBufferBankForExecution(gActiveBank);
break;
case ACTION_CANCEL_PARTNER:
gBattleCommunication[gActiveBank] = 7;
gBattleCommunication[GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON)] = 1;
RecordedBattle_ClearBankAction(gActiveBank, 1);
if (gBattleMons[GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON)].status2 & STATUS2_MULTIPLETURNS
|| gBattleMons[GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON)].status2 & STATUS2_RECHARGE)
{
EmitCmd50(0);
MarkBufferBankForExecution(gActiveBank);
return;
}
else if (gActionForBanks[GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON)] == ACTION_SWITCH)
{
RecordedBattle_ClearBankAction(GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON), 2);
}
else if (gActionForBanks[GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON)] == ACTION_RUN)
{
RecordedBattle_ClearBankAction(GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON), 1);
}
else if (gActionForBanks[GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON)] == ACTION_USE_MOVE
&& (gProtectStructs[GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON)].onlyStruggle
|| gDisableStructs[GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON)].encoredMove))
{
RecordedBattle_ClearBankAction(GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON), 1);
}
else if (gBattleTypeFlags & BATTLE_TYPE_PALACE
&& gActionForBanks[GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON)] == ACTION_USE_MOVE)
{
gRngValue = gBattlePalaceMoveSelectionRngValue;
RecordedBattle_ClearBankAction(GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON), 1);
}
else
{
RecordedBattle_ClearBankAction(GetBankByIdentity(GetBankIdentity(gActiveBank) ^ BIT_MON), 3);
}
EmitCmd50(0);
MarkBufferBankForExecution(gActiveBank);
return;
}
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER
&& gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_x4000000)
&& gBattleBufferB[gActiveBank][1] == ACTION_RUN)
{
gSelectionBattleScripts[gActiveBank] = BattleScript_AskIfWantsToForfeitMatch;
gBattleCommunication[gActiveBank] = 8;
*(gBattleStruct->selectionScriptFinished + gActiveBank) = FALSE;
*(gBattleStruct->stateIdAfterSelScript + gActiveBank) = STATE_BEFORE_ACTION_CHOSEN;
return;
}
else if (gBattleTypeFlags & BATTLE_TYPE_TRAINER
&& !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000))
&& gBattleBufferB[gActiveBank][1] == ACTION_RUN)
{
BattleScriptExecute(BattleScript_PrintCantRunFromTrainer);
gBattleCommunication[gActiveBank] = 1;
}
else if (IsRunningFromBattleImpossible()
&& gBattleBufferB[gActiveBank][1] == ACTION_RUN)
{
gSelectionBattleScripts[gActiveBank] = BattleScript_PrintCantEscapeFromBattle;
gBattleCommunication[gActiveBank] = STATE_SELECTION_SCRIPT;
*(gBattleStruct->selectionScriptFinished + gActiveBank) = FALSE;
*(gBattleStruct->stateIdAfterSelScript + gActiveBank) = STATE_BEFORE_ACTION_CHOSEN;
return;
}
else
{
gBattleCommunication[gActiveBank]++;
}
}
break;
case STATE_WAIT_ACTION_CASE_CHOSEN:
if (!(gBattleExecBuffer & ((gBitTable[gActiveBank]) | (0xF0000000) | (gBitTable[gActiveBank] << 4) | (gBitTable[gActiveBank] << 8) | (gBitTable[gActiveBank] << 0xC))))
{
switch (gActionForBanks[gActiveBank])
{
case ACTION_USE_MOVE:
switch (gBattleBufferB[gActiveBank][1])
{
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
gActionForBanks[gActiveBank] = gBattleBufferB[gActiveBank][1];
return;
case 15:
gActionForBanks[gActiveBank] = ACTION_SWITCH;
sub_803CDF8();
return;
default:
sub_818603C(2);
if ((gBattleBufferB[gActiveBank][2] | (gBattleBufferB[gActiveBank][3] << 8)) == 0xFFFF)
{
gBattleCommunication[gActiveBank] = 1;
RecordedBattle_ClearBankAction(gActiveBank, 1);
}
else if (TrySetCantSelectMoveBattleScript())
{
RecordedBattle_ClearBankAction(gActiveBank, 1);
gBattleCommunication[gActiveBank] = STATE_SELECTION_SCRIPT;
*(gBattleStruct->selectionScriptFinished + gActiveBank) = FALSE;
gBattleBufferB[gActiveBank][1] = 0;
*(gBattleStruct->stateIdAfterSelScript + gActiveBank) = STATE_WAIT_ACTION_CHOSEN;
return;
}
else
{
if (!(gBattleTypeFlags & BATTLE_TYPE_PALACE))
{
RecordedBattle_SetBankAction(gActiveBank, gBattleBufferB[gActiveBank][2]);
RecordedBattle_SetBankAction(gActiveBank, gBattleBufferB[gActiveBank][3]);
}
*(gBattleStruct->chosenMovePositions + gActiveBank) = gBattleBufferB[gActiveBank][2];
gChosenMovesByBanks[gActiveBank] = gBattleMons[gActiveBank].moves[*(gBattleStruct->chosenMovePositions + gActiveBank)];
*(gBattleStruct->moveTarget + gActiveBank) = gBattleBufferB[gActiveBank][3];
gBattleCommunication[gActiveBank]++;
}
break;
}
break;
case ACTION_USE_ITEM:
if ((gBattleBufferB[gActiveBank][1] | (gBattleBufferB[gActiveBank][2] << 8)) == 0)
{
gBattleCommunication[gActiveBank] = 1;
}
else
{
gLastUsedItem = (gBattleBufferB[gActiveBank][1] | (gBattleBufferB[gActiveBank][2] << 8));
gBattleCommunication[gActiveBank]++;
}
break;
case ACTION_SWITCH:
if (gBattleBufferB[gActiveBank][1] == 6)
{
gBattleCommunication[gActiveBank] = 1;
RecordedBattle_ClearBankAction(gActiveBank, 1);
}
else
{
sub_803CDF8();
gBattleCommunication[gActiveBank]++;
}
break;
case ACTION_RUN:
gHitMarker |= HITMARKER_RUN;
gBattleCommunication[gActiveBank]++;
break;
case ACTION_WATCHES_CAREFULLY:
gBattleCommunication[gActiveBank]++;
break;
case ACTION_SAFARI_ZONE_BALL:
gBattleCommunication[gActiveBank]++;
break;
case ACTION_POKEBLOCK_CASE:
if ((gBattleBufferB[gActiveBank][1] | (gBattleBufferB[gActiveBank][2] << 8)) != 0)
{
gBattleCommunication[gActiveBank]++;
}
else
{
gBattleCommunication[gActiveBank] = STATE_BEFORE_ACTION_CHOSEN;
}
break;
case ACTION_GO_NEAR:
gBattleCommunication[gActiveBank]++;
break;
case ACTION_SAFARI_ZONE_RUN:
gHitMarker |= HITMARKER_RUN;
gBattleCommunication[gActiveBank]++;
break;
case ACTION_9:
gBattleCommunication[gActiveBank]++;
break;
}
}
break;
case STATE_WAIT_ACTION_CONFIRMED_STANDBY:
if (!(gBattleExecBuffer & ((gBitTable[gActiveBank]) | (0xF0000000) | (gBitTable[gActiveBank] << 4) | (gBitTable[gActiveBank] << 8) | (gBitTable[gActiveBank] << 0xC))))
{
i = (sub_803CDB8() != 0);
if (((gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_DOUBLE)) != BATTLE_TYPE_DOUBLE)
|| (identity & BIT_MON)
|| (*(&gBattleStruct->field_91) & gBitTable[GetBankByIdentity(identity ^ BIT_MON)]))
{
EmitLinkStandbyMsg(0, 0, i);
}
else
{
EmitLinkStandbyMsg(0, 1, i);
}
MarkBufferBankForExecution(gActiveBank);
gBattleCommunication[gActiveBank]++;
}
break;
case STATE_WAIT_ACTION_CONFIRMED:
if (!(gBattleExecBuffer & ((gBitTable[gActiveBank]) | (0xF0000000) | (gBitTable[gActiveBank] << 4) | (gBitTable[gActiveBank] << 8) | (gBitTable[gActiveBank] << 0xC))))
{
gBattleCommunication[ACTIONS_CONFIRMED_COUNT]++;
}
break;
case STATE_SELECTION_SCRIPT:
if (*(gBattleStruct->selectionScriptFinished + gActiveBank))
{
gBattleCommunication[gActiveBank] = *(gBattleStruct->stateIdAfterSelScript + gActiveBank);
}
else
{
gBankAttacker = gActiveBank;
gBattlescriptCurrInstr = gSelectionBattleScripts[gActiveBank];
if (!(gBattleExecBuffer & ((gBitTable[gActiveBank]) | (0xF0000000) | (gBitTable[gActiveBank] << 4) | (gBitTable[gActiveBank] << 8) | (gBitTable[gActiveBank] << 0xC))))
{
gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]]();
}
gSelectionBattleScripts[gActiveBank] = gBattlescriptCurrInstr;
}
break;
case STATE_WAIT_SET_BEFORE_ACTION:
if (!(gBattleExecBuffer & ((gBitTable[gActiveBank]) | (0xF0000000) | (gBitTable[gActiveBank] << 4) | (gBitTable[gActiveBank] << 8) | (gBitTable[gActiveBank] << 0xC))))
{
gBattleCommunication[gActiveBank] = 1;
}
break;
case STATE_SELECTION_SCRIPT_MAY_RUN:
if (*(gBattleStruct->selectionScriptFinished + gActiveBank))
{
if (gBattleBufferB[gActiveBank][1] == 13)
{
gHitMarker |= HITMARKER_RUN;
gActionForBanks[gActiveBank] = ACTION_RUN;
gBattleCommunication[gActiveBank] = STATE_WAIT_ACTION_CONFIRMED_STANDBY;
}
else
{
RecordedBattle_ClearBankAction(gActiveBank, 1);
gBattleCommunication[gActiveBank] = *(gBattleStruct->stateIdAfterSelScript + gActiveBank);
}
}
else
{
gBankAttacker = gActiveBank;
gBattlescriptCurrInstr = gSelectionBattleScripts[gActiveBank];
if (!(gBattleExecBuffer & ((gBitTable[gActiveBank]) | (0xF0000000) | (gBitTable[gActiveBank] << 4) | (gBitTable[gActiveBank] << 8) | (gBitTable[gActiveBank] << 0xC))))
{
gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]]();
}
gSelectionBattleScripts[gActiveBank] = gBattlescriptCurrInstr;
}
break;
}
}
// check if everyone chose actions
if (gBattleCommunication[ACTIONS_CONFIRMED_COUNT] == gNoOfAllBanks)
{
sub_818603C(1);
gBattleMainFunc = SetActionsAndBanksTurnOrder;
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
{
for (i = 0; i < gNoOfAllBanks; i++)
{
if (gActionForBanks[i] == ACTION_SWITCH)
sub_80571DC(i, *(gBattleStruct->monToSwitchIntoId + i));
}
}
}
}
static bool8 sub_803CDB8(void)
{
s32 i, var;
for (var = 0, i = 0; i < gNoOfAllBanks; i++)
{
if (gBattleCommunication[i] == 5)
var++;
}
if (var + 1 == gNoOfAllBanks)
return TRUE;
else
return FALSE;
}
static void sub_803CDF8(void)
{
*(gBattleStruct->monToSwitchIntoId + gActiveBank) = gBattleBufferB[gActiveBank][1];
RecordedBattle_SetBankAction(gActiveBank, gBattleBufferB[gActiveBank][1]);
if (gBattleTypeFlags & BATTLE_TYPE_LINK && gBattleTypeFlags & BATTLE_TYPE_MULTI)
{
*(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 ^ BIT_MON) * 3 + (u8*)(gBattleStruct->field_60) + 0) &= (0xF0);
*((gActiveBank ^ BIT_MON) * 3 + (u8*)(gBattleStruct->field_60) + 0) |= (gBattleBufferB[gActiveBank][2] & 0xF0) >> 4;
*((gActiveBank ^ BIT_MON) * 3 + (u8*)(gBattleStruct->field_60) + 2) = gBattleBufferB[gActiveBank][3];
}
}
void SwapTurnOrder(u8 id1, u8 id2)
{
u32 temp = gActionsByTurnOrder[id1];
gActionsByTurnOrder[id1] = gActionsByTurnOrder[id2];
gActionsByTurnOrder[id2] = temp;
temp = gBanksByTurnOrder[id1];
gBanksByTurnOrder[id1] = gBanksByTurnOrder[id2];
gBanksByTurnOrder[id2] = temp;
}
u8 GetWhoStrikesFirst(u8 bank1, u8 bank2, bool8 ignoreChosenMoves)
{
u8 strikesFirst = 0;
u8 speedMultiplierBank1 = 0, speedMultiplierBank2 = 0;
u32 speedBank1 = 0, speedBank2 = 0;
u8 holdEffect = 0;
u8 holdEffectParam = 0;
u16 moveBank1 = 0, moveBank2 = 0;
if (WEATHER_HAS_EFFECT)
{
if ((gBattleMons[bank1].ability == ABILITY_SWIFT_SWIM && gBattleWeather & WEATHER_RAIN_ANY)
|| (gBattleMons[bank1].ability == ABILITY_CHLOROPHYLL && gBattleWeather & WEATHER_SUN_ANY))
speedMultiplierBank1 = 2;
else
speedMultiplierBank1 = 1;
if ((gBattleMons[bank2].ability == ABILITY_SWIFT_SWIM && gBattleWeather & WEATHER_RAIN_ANY)
|| (gBattleMons[bank2].ability == ABILITY_CHLOROPHYLL && gBattleWeather & WEATHER_SUN_ANY))
speedMultiplierBank2 = 2;
else
speedMultiplierBank2 = 1;
}
else
{
speedMultiplierBank1 = 1;
speedMultiplierBank2 = 1;
}
speedBank1 = (gBattleMons[bank1].speed * speedMultiplierBank1)
* (gStatStageRatios[gBattleMons[bank1].statStages[STAT_STAGE_SPEED]][0])
/ (gStatStageRatios[gBattleMons[bank1].statStages[STAT_STAGE_SPEED]][1]);
if (gBattleMons[bank1].item == ITEM_ENIGMA_BERRY)
{
holdEffect = gEnigmaBerries[bank1].holdEffect;
holdEffectParam = gEnigmaBerries[bank1].holdEffectParam;
}
else
{
holdEffect = ItemId_GetHoldEffect(gBattleMons[bank1].item);
holdEffectParam = ItemId_GetHoldEffectParam(gBattleMons[bank1].item);
}
// badge boost
if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000 | BATTLE_TYPE_FRONTIER))
&& FlagGet(FLAG_BADGE03_GET)
&& GetBankSide(bank1) == SIDE_PLAYER)
{
speedBank1 = (speedBank1 * 110) / 100;
}
if (holdEffect == HOLD_EFFECT_MACHO_BRACE)
speedBank1 /= 2;
if (gBattleMons[bank1].status1 & STATUS_PARALYSIS)
speedBank1 /= 4;
if (holdEffect == HOLD_EFFECT_QUICK_CLAW && gRandomTurnNumber < (0xFFFF * holdEffectParam) / 100)
speedBank1 = UINT_MAX;
// check second bank's speed
speedBank2 = (gBattleMons[bank2].speed * speedMultiplierBank2)
* (gStatStageRatios[gBattleMons[bank2].statStages[STAT_STAGE_SPEED]][0])
/ (gStatStageRatios[gBattleMons[bank2].statStages[STAT_STAGE_SPEED]][1]);
if (gBattleMons[bank2].item == ITEM_ENIGMA_BERRY)
{
holdEffect = gEnigmaBerries[bank2].holdEffect;
holdEffectParam = gEnigmaBerries[bank2].holdEffectParam;
}
else
{
holdEffect = ItemId_GetHoldEffect(gBattleMons[bank2].item);
holdEffectParam = ItemId_GetHoldEffectParam(gBattleMons[bank2].item);
}
// badge boost
if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000 | BATTLE_TYPE_FRONTIER))
&& FlagGet(FLAG_BADGE03_GET)
&& GetBankSide(bank2) == SIDE_PLAYER)
{
speedBank2 = (speedBank2 * 110) / 100;
}
if (holdEffect == HOLD_EFFECT_MACHO_BRACE)
speedBank2 /= 2;
if (gBattleMons[bank2].status1 & STATUS_PARALYSIS)
speedBank2 /= 4;
if (holdEffect == HOLD_EFFECT_QUICK_CLAW && gRandomTurnNumber < (0xFFFF * holdEffectParam) / 100)
speedBank2 = UINT_MAX;
if (ignoreChosenMoves)
{
moveBank1 = MOVE_NONE;
moveBank2 = MOVE_NONE;
}
else
{
if (gActionForBanks[bank1] == ACTION_USE_MOVE)
{
if (gProtectStructs[bank1].onlyStruggle)
moveBank1 = MOVE_STRUGGLE;
else
moveBank1 = gBattleMons[bank1].moves[*(gBattleStruct->chosenMovePositions + bank1)];
}
else
moveBank1 = MOVE_NONE;
if (gActionForBanks[bank2] == ACTION_USE_MOVE)
{
if (gProtectStructs[bank2].onlyStruggle)
moveBank2 = MOVE_STRUGGLE;
else
moveBank2 = gBattleMons[bank2].moves[*(gBattleStruct->chosenMovePositions + bank2)];
}
else
moveBank2 = MOVE_NONE;
}
// both move priorities are different than 0
if (gBattleMoves[moveBank1].priority != 0 || gBattleMoves[moveBank2].priority != 0)
{
// both priorities are the same
if (gBattleMoves[moveBank1].priority == gBattleMoves[moveBank2].priority)
{
if (speedBank1 == speedBank2 && Random() & 1)
strikesFirst = 2; // same speeds, same priorities
else if (speedBank1 < speedBank2)
strikesFirst = 1; // bank2 has more speed
// else bank1 has more speed
}
else if (gBattleMoves[moveBank1].priority < gBattleMoves[moveBank2].priority)
strikesFirst = 1; // bank2's move has greater priority
// else bank1's move has greater priority
}
// both priorities are equal to 0
else
{
if (speedBank1 == speedBank2 && Random() & 1)
strikesFirst = 2; // same speeds, same priorities
else if (speedBank1 < speedBank2)
strikesFirst = 1; // bank2 has more speed
// else bank1 has more speed
}
return strikesFirst;
}
static void SetActionsAndBanksTurnOrder(void)
{
s32 var = 0;
s32 i, j;
if (gBattleTypeFlags & BATTLE_TYPE_SAFARI)
{
for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++)
{
gActionsByTurnOrder[var] = gActionForBanks[gActiveBank];
gBanksByTurnOrder[var] = gActiveBank;
var++;
}
}
else
{
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
{
for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++)
{
if (gActionForBanks[gActiveBank] == ACTION_RUN)
{
var = 5;
break;
}
}
}
else
{
if (gActionForBanks[0] == ACTION_RUN)
{
gActiveBank = 0;
var = 5;
}
if (gActionForBanks[2] == ACTION_RUN)
{
gActiveBank = 2;
var = 5;
}
}
if (var == 5)
{
gActionsByTurnOrder[0] = gActionForBanks[gActiveBank];
gBanksByTurnOrder[0] = gActiveBank;
var = 1;
for (i = 0; i < gNoOfAllBanks; i++)
{
if (i != gActiveBank)
{
gActionsByTurnOrder[var] = gActionForBanks[i];
gBanksByTurnOrder[var] = i;
var++;
}
}
gBattleMainFunc = CheckFocusPunch_ClearVarsBeforeTurnStarts;
gBattleStruct->focusPunchBank = 0;
return;
}
else
{
for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++)
{
if (gActionForBanks[gActiveBank] == ACTION_USE_ITEM || gActionForBanks[gActiveBank] == ACTION_SWITCH)
{
gActionsByTurnOrder[var] = gActionForBanks[gActiveBank];
gBanksByTurnOrder[var] = gActiveBank;
var++;
}
}
for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++)
{
if (gActionForBanks[gActiveBank] != ACTION_USE_ITEM && gActionForBanks[gActiveBank] != ACTION_SWITCH)
{
gActionsByTurnOrder[var] = gActionForBanks[gActiveBank];
gBanksByTurnOrder[var] = gActiveBank;
var++;
}
}
for (i = 0; i < gNoOfAllBanks - 1; i++)
{
for (j = i + 1; j < gNoOfAllBanks; j++)
{
u8 bank1 = gBanksByTurnOrder[i];
u8 bank2 = gBanksByTurnOrder[j];
if (gActionsByTurnOrder[i] != ACTION_USE_ITEM
&& gActionsByTurnOrder[j] != ACTION_USE_ITEM
&& gActionsByTurnOrder[i] != ACTION_SWITCH
&& gActionsByTurnOrder[j] != ACTION_SWITCH)
{
if (GetWhoStrikesFirst(bank1, bank2, FALSE))
SwapTurnOrder(i, j);
}
}
}
}
}
gBattleMainFunc = CheckFocusPunch_ClearVarsBeforeTurnStarts;
gBattleStruct->focusPunchBank = 0;
}
static void TurnValuesCleanUp(bool8 var0)
{
s32 i;
u8 *dataPtr;
for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++)
{
if (var0)
{
gProtectStructs[gActiveBank].protected = 0;
gProtectStructs[gActiveBank].endured = 0;
}
else
{
dataPtr = (u8*)(&gProtectStructs[gActiveBank]);
for (i = 0; i < sizeof(struct ProtectStruct); i++)
dataPtr[i] = 0;
if (gDisableStructs[gActiveBank].isFirstTurn)
gDisableStructs[gActiveBank].isFirstTurn--;
if (gDisableStructs[gActiveBank].rechargeCounter)
{
gDisableStructs[gActiveBank].rechargeCounter--;
if (gDisableStructs[gActiveBank].rechargeCounter == 0)
gBattleMons[gActiveBank].status2 &= ~(STATUS2_RECHARGE);
}
}
if (gDisableStructs[gActiveBank].substituteHP == 0)
gBattleMons[gActiveBank].status2 &= ~(STATUS2_SUBSTITUTE);
}
gSideTimers[0].followmeTimer = 0;
gSideTimers[1].followmeTimer = 0;
}
static void SpecialStatusesClear(void)
{
for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++)
{
s32 i;
u8 *dataPtr = (u8*)(&gSpecialStatuses[gActiveBank]);
for (i = 0; i < sizeof(struct SpecialStatus); i++)
dataPtr[i] = 0;
}
}
static void CheckFocusPunch_ClearVarsBeforeTurnStarts(void)
{
if (!(gHitMarker & HITMARKER_RUN))
{
while (gBattleStruct->focusPunchBank < gNoOfAllBanks)
{
gActiveBank = gBankAttacker = gBattleStruct->focusPunchBank;
gBattleStruct->focusPunchBank++;
if (gChosenMovesByBanks[gActiveBank] == MOVE_FOCUS_PUNCH
&& !(gBattleMons[gActiveBank].status1 & STATUS_SLEEP)
&& !(gDisableStructs[gBankAttacker].truantCounter)
&& !(gProtectStructs[gActiveBank].onlyStruggle))
{
BattleScriptExecute(BattleScript_FocusPunchSetUp);
return;
}
}
}
TryClearRageStatuses();
gCurrentTurnActionNumber = 0;
{
// something stupid needed to match
u8 zero;
gCurrentActionFuncId = gActionsByTurnOrder[(zero = 0)];
}
gDynamicBasePower = 0;
gBattleStruct->dynamicMoveType = 0;
gBattleMainFunc = RunTurnActionsFunctions;
gBattleCommunication[3] = 0;
gBattleCommunication[4] = 0;
gBattleScripting.field_16 = 0;
gBattleResources->battleScriptsStack->size = 0;
}
static void RunTurnActionsFunctions(void)
{
if (gBattleOutcome != 0)
gCurrentActionFuncId = 12;
*(&gBattleStruct->field_4B) = gCurrentTurnActionNumber;
sTurnActionsFuncsTable[gCurrentActionFuncId]();
if (gCurrentTurnActionNumber >= gNoOfAllBanks) // everyone did their actions, turn finished
{
gHitMarker &= ~(HITMARKER_x100000);
gBattleMainFunc = sEndTurnFuncsTable[gBattleOutcome & 0x7F];
}
else
{
if (gBattleStruct->field_4B != gCurrentTurnActionNumber) // action turn has been done, clear hitmarker bits for another bank
{
gHitMarker &= ~(HITMARKER_NO_ATTACKSTRING);
gHitMarker &= ~(HITMARKER_UNABLE_TO_USE_MOVE);
}
}
}
static void HandleEndTurn_BattleWon(void)
{
gCurrentActionFuncId = 0;
if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000))
{
gSpecialVar_Result = gBattleOutcome;
gBattleTextBuff1[0] = gBattleOutcome;
gBankAttacker = GetBankByIdentity(IDENTITY_PLAYER_MON1);
gBattlescriptCurrInstr = BattleScript_LinkBattleWonOrLost;
gBattleOutcome &= ~(BATTLE_OUTCOME_BIT_x80);
}
else if (gBattleTypeFlags & BATTLE_TYPE_TRAINER
&& gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_x4000000 | BATTLE_TYPE_EREADER_TRAINER))
{
BattleStopLowHpSound();
gBattlescriptCurrInstr = BattleScript_FrontierTrainerBattleWon;
if (gTrainerBattleOpponent_A == TRAINER_OPPONENT_3FE)
PlayBGM(BGM_KACHI3);
else
PlayBGM(BGM_KACHI1);
}
else if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && !(gBattleTypeFlags & BATTLE_TYPE_LINK))
{
BattleStopLowHpSound();
gBattlescriptCurrInstr = BattleScript_LocalTrainerBattleWon;
switch (gTrainers[gTrainerBattleOpponent_A].trainerClass)
{
case CLASS_ELITE_FOUR:
case CLASS_CHAMPION:
PlayBGM(BGM_KACHI5);
break;
case CLASS_TEAM_AQUA:
case CLASS_TEAM_MAGMA:
case CLASS_AQUA_ADMIN:
case CLASS_AQUA_LEADER:
case CLASS_MAGMA_ADMIN:
case CLASS_MAGMA_LEADER:
PlayBGM(BGM_KACHI4);
break;
case CLASS_LEADER:
PlayBGM(BGM_KACHI3);
break;
default:
PlayBGM(BGM_KACHI1);
break;
}
}
else
{
gBattlescriptCurrInstr = BattleScript_PayDayMoneyAndPickUpItems;
}
gBattleMainFunc = HandleEndTurn_FinishBattle;
}
static void HandleEndTurn_BattleLost(void)
{
gCurrentActionFuncId = 0;
if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000))
{
if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER)
{
if (gBattleOutcome & BATTLE_OUTCOME_BIT_x80)
{
gBattlescriptCurrInstr = BattleScript_82DB9C8;
gBattleOutcome &= ~(BATTLE_OUTCOME_BIT_x80);
gSaveBlock2Ptr->field_CA9_b = 1;
}
else
{
gBattlescriptCurrInstr = BattleScript_82DAA0B;
gBattleOutcome &= ~(BATTLE_OUTCOME_BIT_x80);
}
}
else
{
gBattleTextBuff1[0] = gBattleOutcome;
gBankAttacker = GetBankByIdentity(IDENTITY_PLAYER_MON1);
gBattlescriptCurrInstr = BattleScript_LinkBattleWonOrLost;
gBattleOutcome &= ~(BATTLE_OUTCOME_BIT_x80);
}
}
else
{
gBattlescriptCurrInstr = BattleScript_LocalBattleLost;
}
gBattleMainFunc = HandleEndTurn_FinishBattle;
}
static void HandleEndTurn_RanFromBattle(void)
{
gCurrentActionFuncId = 0;
if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER && gBattleTypeFlags & BATTLE_TYPE_TRAINER)
{
gBattlescriptCurrInstr = BattleScript_82DB9C1;
gBattleOutcome = BATTLE_FORFEITED;
gSaveBlock2Ptr->field_CA9_b = 1;
}
else if (gBattleTypeFlags & BATTLE_TYPE_x4000000)
{
gBattlescriptCurrInstr = BattleScript_82DB9C1;
gBattleOutcome = BATTLE_FORFEITED;
}
else
{
switch (gProtectStructs[gBankAttacker].fleeFlag)
{
default:
gBattlescriptCurrInstr = BattleScript_GotAwaySafely;
break;
case 1:
gBattlescriptCurrInstr = BattleScript_SmokeBallEscape;
break;
case 2:
gBattlescriptCurrInstr = BattleScript_RanAwayUsingMonAbility;
break;
}
}
gBattleMainFunc = HandleEndTurn_FinishBattle;
}
static void HandleEndTurn_MonFled(void)
{
gCurrentActionFuncId = 0;
PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, gBankAttacker, gBattlePartyID[gBankAttacker]);
gBattlescriptCurrInstr = BattleScript_WildMonFled;
gBattleMainFunc = HandleEndTurn_FinishBattle;
}
static void HandleEndTurn_FinishBattle(void)
{
if (gCurrentActionFuncId == 0xB || gCurrentActionFuncId == 0xC)
{
if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK
| BATTLE_TYPE_x2000000
| BATTLE_TYPE_FIRST_BATTLE
| BATTLE_TYPE_SAFARI
| BATTLE_TYPE_EREADER_TRAINER
| BATTLE_TYPE_WALLY_TUTORIAL
| BATTLE_TYPE_FRONTIER)))
{
for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++)
{
if (GetBankSide(gActiveBank) == SIDE_PLAYER)
{
if (gBattleResults.playerMon1Species == SPECIES_NONE)
{
gBattleResults.playerMon1Species = GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES, NULL);
GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_NICKNAME, gBattleResults.playerMon1Name);
}
else
{
gBattleResults.playerMon2Species = GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_SPECIES, NULL);
GetMonData(&gPlayerParty[gBattlePartyID[gActiveBank]], MON_DATA_NICKNAME, gBattleResults.playerMon2Name);
}
}
}
PutPokemonTodayCaughtOnAir();
}
if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK
| BATTLE_TYPE_x2000000
| BATTLE_TYPE_TRAINER
| BATTLE_TYPE_FIRST_BATTLE
| BATTLE_TYPE_SAFARI
| BATTLE_TYPE_FRONTIER
| BATTLE_TYPE_EREADER_TRAINER
| BATTLE_TYPE_WALLY_TUTORIAL))
&& gBattleResults.unk5_6)
{
sub_80EE184();
}
sub_8186444();
BeginFastPaletteFade(3);
FadeOutMapMusic(5);
gBattleMainFunc = FreeResetData_ReturnToOvOrDoEvolutions;
gCB2_AfterEvolution = BattleMainCB2;
}
else
{
if (gBattleExecBuffer == 0)
gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]]();
}
}
static void FreeResetData_ReturnToOvOrDoEvolutions(void)
{
if (!gPaletteFade.active)
{
ResetSpriteData();
if (gLeveledUpInBattle == 0 || gBattleOutcome != BATTLE_WON)
{
gBattleMainFunc = ReturnFromBattleToOverworld;
return;
}
else
{
gBattleMainFunc = TryEvolvePokemon;
}
}
FreeAllWindowBuffers();
if (!(gBattleTypeFlags & BATTLE_TYPE_LINK))
{
FreeMonSpritesGfx();
FreeBattleResources();
FreeBattleSpritesData();
}
}
static void TryEvolvePokemon(void)
{
s32 i;
while (gLeveledUpInBattle != 0)
{
for (i = 0; i < 6; i++)
{
if (gLeveledUpInBattle & gBitTable[i])
{
u16 species;
u8 levelUpBits = gLeveledUpInBattle;
levelUpBits &= ~(gBitTable[i]);
gLeveledUpInBattle = levelUpBits;
species = GetEvolutionTargetSpecies(&gPlayerParty[i], 0, levelUpBits);
if (species != SPECIES_NONE)
{
FreeAllWindowBuffers();
gBattleMainFunc = WaitForEvoSceneToFinish;
EvolutionScene(&gPlayerParty[i], species, TRUE, i);
return;
}
}
}
}
gBattleMainFunc = ReturnFromBattleToOverworld;
}
static void WaitForEvoSceneToFinish(void)
{
if (gMain.callback2 == BattleMainCB2)
gBattleMainFunc = TryEvolvePokemon;
}
static void ReturnFromBattleToOverworld(void)
{
if (!(gBattleTypeFlags & BATTLE_TYPE_LINK))
{
RandomlyGivePartyPokerus(gPlayerParty);
PartySpreadPokerus(gPlayerParty);
}
if (gBattleTypeFlags & BATTLE_TYPE_LINK && gReceivedRemoteLinkPlayers != 0)
return;
gSpecialVar_Result = gBattleOutcome;
gMain.inBattle = 0;
gMain.callback1 = gPreBattleCallback1;
if (gBattleTypeFlags & BATTLE_TYPE_ROAMER)
{
UpdateRoamerHPStatus(&gEnemyParty[0]);
if ((gBattleOutcome & BATTLE_WON) || gBattleOutcome == BATTLE_CAUGHT)
SetRoamerInactive();
}
m4aSongNumStop(0x5A);
SetMainCallback2(gMain.savedCallback);
}
void RunBattleScriptCommands_PopCallbacksStack(void)
{
if (gCurrentActionFuncId == 0xB || gCurrentActionFuncId == 0xC)
{
if (BATTLE_CALLBACKS_STACK->size != 0)
BATTLE_CALLBACKS_STACK->size--;
gBattleMainFunc = BATTLE_CALLBACKS_STACK->function[BATTLE_CALLBACKS_STACK->size];
}
else
{
if (gBattleExecBuffer == 0)
gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]]();
}
}
void RunBattleScriptCommands(void)
{
if (gBattleExecBuffer == 0)
gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]]();
}
static void HandleAction_UseMove(void)
{
u8 side;
u8 var = 4;
gBankAttacker = gBanksByTurnOrder[gCurrentTurnActionNumber];
if (*(&gBattleStruct->field_91) & gBitTable[gBankAttacker])
{
gCurrentActionFuncId = ACTION_FINISHED;
return;
}
gCritMultiplier = 1;
gBattleScripting.dmgMultiplier = 1;
gBattleStruct->atkCancellerTracker = 0;
gBattleMoveFlags = 0;
gMultiHitCounter = 0;
gBattleCommunication[6] = 0;
gCurrMovePos = gUnknown_020241E9 = *(gBattleStruct->chosenMovePositions + gBankAttacker);
// choose move
if (gProtectStructs[gBankAttacker].onlyStruggle)
{
gProtectStructs[gBankAttacker].onlyStruggle = 0;
gCurrentMove = gChosenMove = MOVE_STRUGGLE;
gHitMarker |= HITMARKER_NO_PPDEDUCT;
*(gBattleStruct->moveTarget + gBankAttacker) = GetMoveTarget(MOVE_STRUGGLE, 0);
}
else if (gBattleMons[gBankAttacker].status2 & STATUS2_MULTIPLETURNS || gBattleMons[gBankAttacker].status2 & STATUS2_RECHARGE)
{
gCurrentMove = gChosenMove = gLockedMoves[gBankAttacker];
}
// encore forces you to use the same move
else if (gDisableStructs[gBankAttacker].encoredMove != MOVE_NONE
&& gDisableStructs[gBankAttacker].encoredMove == gBattleMons[gBankAttacker].moves[gDisableStructs[gBankAttacker].encoredMovePos])
{
gCurrentMove = gChosenMove = gDisableStructs[gBankAttacker].encoredMove;
gCurrMovePos = gUnknown_020241E9 = gDisableStructs[gBankAttacker].encoredMovePos;
*(gBattleStruct->moveTarget + gBankAttacker) = GetMoveTarget(gCurrentMove, 0);
}
// check if the encored move wasn't overwritten
else if (gDisableStructs[gBankAttacker].encoredMove != MOVE_NONE
&& gDisableStructs[gBankAttacker].encoredMove != gBattleMons[gBankAttacker].moves[gDisableStructs[gBankAttacker].encoredMovePos])
{
gCurrMovePos = gUnknown_020241E9 = gDisableStructs[gBankAttacker].encoredMovePos;
gCurrentMove = gChosenMove = gBattleMons[gBankAttacker].moves[gCurrMovePos];
gDisableStructs[gBankAttacker].encoredMove = MOVE_NONE;
gDisableStructs[gBankAttacker].encoredMovePos = 0;
gDisableStructs[gBankAttacker].encoreTimer1 = 0;
*(gBattleStruct->moveTarget + gBankAttacker) = GetMoveTarget(gCurrentMove, 0);
}
else if (gBattleMons[gBankAttacker].moves[gCurrMovePos] != gChosenMovesByBanks[gBankAttacker])
{
gCurrentMove = gChosenMove = gBattleMons[gBankAttacker].moves[gCurrMovePos];
*(gBattleStruct->moveTarget + gBankAttacker) = GetMoveTarget(gCurrentMove, 0);
}
else
{
gCurrentMove = gChosenMove = gBattleMons[gBankAttacker].moves[gCurrMovePos];
}
if (gBattleMons[gBankAttacker].hp != 0)
{
if (GetBankSide(gBankAttacker) == SIDE_PLAYER)
gBattleResults.lastUsedMovePlayer = gCurrentMove;
else
gBattleResults.lastUsedMoveOpponent = gCurrentMove;
}
// choose target
side = GetBankSide(gBankAttacker) ^ BIT_SIDE;
if (gSideTimers[side].followmeTimer != 0
&& gBattleMoves[gCurrentMove].target == MOVE_TARGET_SELECTED
&& GetBankSide(gBankAttacker) != GetBankSide(gSideTimers[side].followmeTarget)
&& gBattleMons[gSideTimers[side].followmeTarget].hp != 0)
{
gBankTarget = gSideTimers[side].followmeTarget;
}
else if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
&& gSideTimers[side].followmeTimer == 0
&& (gBattleMoves[gCurrentMove].power != 0
|| gBattleMoves[gCurrentMove].target != MOVE_TARGET_x10)
&& gBattleMons[*(gBattleStruct->moveTarget + gBankAttacker)].ability != ABILITY_LIGHTNING_ROD
&& gBattleMoves[gCurrentMove].type == TYPE_ELECTRIC)
{
side = GetBankSide(gBankAttacker);
for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++)
{
if (side != GetBankSide(gActiveBank)
&& *(gBattleStruct->moveTarget + gBankAttacker) != gActiveBank
&& gBattleMons[gActiveBank].ability == ABILITY_LIGHTNING_ROD
&& BankGetTurnOrder(gActiveBank) < var)
{
var = BankGetTurnOrder(gActiveBank);
}
}
if (var == 4)
{
if (gBattleMoves[gChosenMove].target & MOVE_TARGET_RANDOM)
{
if (GetBankSide(gBankAttacker) == SIDE_PLAYER)
{
if (Random() & 1)
gBankTarget = GetBankByIdentity(IDENTITY_OPPONENT_MON1);
else
gBankTarget = GetBankByIdentity(IDENTITY_OPPONENT_MON2);
}
else
{
if (Random() & 1)
gBankTarget = GetBankByIdentity(IDENTITY_PLAYER_MON1);
else
gBankTarget = GetBankByIdentity(IDENTITY_PLAYER_MON2);
}
}
else
{
gBankTarget = *(gBattleStruct->moveTarget + gBankAttacker);
}
if (gAbsentBankFlags & gBitTable[gBankTarget])
{
if (GetBankSide(gBankAttacker) != GetBankSide(gBankTarget))
{
gBankTarget = GetBankByIdentity(GetBankIdentity(gBankTarget) ^ BIT_MON);
}
else
{
gBankTarget = GetBankByIdentity(GetBankIdentity(gBankAttacker) ^ BIT_SIDE);
if (gAbsentBankFlags & gBitTable[gBankTarget])
gBankTarget = GetBankByIdentity(GetBankIdentity(gBankTarget) ^ BIT_MON);
}
}
}
else
{
gActiveBank = gBanksByTurnOrder[var];
RecordAbilityBattle(gActiveBank, gBattleMons[gActiveBank].ability);
gSpecialStatuses[gActiveBank].lightningRodRedirected = 1;
gBankTarget = gActiveBank;
}
}
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE
&& gBattleMoves[gChosenMove].target & MOVE_TARGET_RANDOM)
{
if (GetBankSide(gBankAttacker) == SIDE_PLAYER)
{
if (Random() & 1)
gBankTarget = GetBankByIdentity(IDENTITY_OPPONENT_MON1);
else
gBankTarget = GetBankByIdentity(IDENTITY_OPPONENT_MON2);
}
else
{
if (Random() & 1)
gBankTarget = GetBankByIdentity(IDENTITY_PLAYER_MON1);
else
gBankTarget = GetBankByIdentity(IDENTITY_PLAYER_MON2);
}
if (gAbsentBankFlags & gBitTable[gBankTarget]
&& GetBankSide(gBankAttacker) != GetBankSide(gBankTarget))
{
gBankTarget = GetBankByIdentity(GetBankIdentity(gBankTarget) ^ BIT_MON);
}
}
else
{
gBankTarget = *(gBattleStruct->moveTarget + gBankAttacker);
if (gAbsentBankFlags & gBitTable[gBankTarget])
{
if (GetBankSide(gBankAttacker) != GetBankSide(gBankTarget))
{
gBankTarget = GetBankByIdentity(GetBankIdentity(gBankTarget) ^ BIT_MON);
}
else
{
gBankTarget = GetBankByIdentity(GetBankIdentity(gBankAttacker) ^ BIT_SIDE);
if (gAbsentBankFlags & gBitTable[gBankTarget])
gBankTarget = GetBankByIdentity(GetBankIdentity(gBankTarget) ^ BIT_MON);
}
}
}
// choose battlescript
if (gBattleTypeFlags & BATTLE_TYPE_PALACE
&& gProtectStructs[gBankAttacker].flag_x10)
{
if (gBattleMons[gBankAttacker].hp == 0)
{
gCurrentActionFuncId = 12;
return;
}
else if (gPalaceSelectionBattleScripts[gBankAttacker] != NULL)
{
gBattleCommunication[MULTISTRING_CHOOSER] = 4;
gBattlescriptCurrInstr = gPalaceSelectionBattleScripts[gBankAttacker];
gPalaceSelectionBattleScripts[gBankAttacker] = NULL;
}
else
{
gBattleCommunication[MULTISTRING_CHOOSER] = 4;
gBattlescriptCurrInstr = BattleScript_MoveUsedLoafingAround;
}
}
else
{
gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect];
}
if (gBattleTypeFlags & BATTLE_TYPE_ARENA)
sub_81A56E8(gBankAttacker);
gCurrentActionFuncId = ACTION_RUN_BATTLESCRIPT;
}
static void HandleAction_Switch(void)
{
gBankAttacker = gBanksByTurnOrder[gCurrentTurnActionNumber];
gBattle_BG0_X = 0;
gBattle_BG0_Y = 0;
gActionSelectionCursor[gBankAttacker] = 0;
gMoveSelectionCursor[gBankAttacker] = 0;
PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, gBankAttacker, *(gBattleStruct->field_58 + gBankAttacker))
gBattleScripting.bank = gBankAttacker;
gBattlescriptCurrInstr = BattleScript_ActionSwitch;
gCurrentActionFuncId = ACTION_RUN_BATTLESCRIPT;
if (gBattleResults.playerSwitchesCounter < 255)
gBattleResults.playerSwitchesCounter++;
}
static void HandleAction_UseItem(void)
{
gBankAttacker = gBankTarget = gBanksByTurnOrder[gCurrentTurnActionNumber];
gBattle_BG0_X = 0;
gBattle_BG0_Y = 0;
ClearFuryCutterDestinyBondGrudge(gBankAttacker);
gLastUsedItem = gBattleBufferB[gBankAttacker][1] | (gBattleBufferB[gBankAttacker][2] << 8);
if (gLastUsedItem <= ITEM_PREMIER_BALL) // is ball
{
gBattlescriptCurrInstr = gBattlescriptsForBallThrow[gLastUsedItem];
}
else if (gLastUsedItem == ITEM_POKE_DOLL || gLastUsedItem == ITEM_FLUFFY_TAIL)
{
gBattlescriptCurrInstr = gBattlescriptsForRunningByItem[0];
}
else if (GetBankSide(gBankAttacker) == SIDE_PLAYER)
{
gBattlescriptCurrInstr = gUnknown_082DBD3C[0];
}
else
{
gBattleScripting.bank = gBankAttacker;
switch (*(gBattleStruct->AI_itemType + (gBankAttacker >> 1)))
{
case AI_ITEM_FULL_RESTORE:
case AI_ITEM_HEAL_HP:
break;
case AI_ITEM_CURE_CONDITION:
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
if (*(gBattleStruct->AI_itemFlags + gBankAttacker / 2) & 1)
{
if (*(gBattleStruct->AI_itemFlags + gBankAttacker / 2) & 0x3E)
gBattleCommunication[MULTISTRING_CHOOSER] = 5;
}
else
{
while (!(*(gBattleStruct->AI_itemFlags + gBankAttacker / 2) & 1))
{
*(gBattleStruct->AI_itemFlags + gBankAttacker / 2) >>= 1;
gBattleCommunication[MULTISTRING_CHOOSER]++;
}
}
break;
case AI_ITEM_X_STAT:
gBattleCommunication[MULTISTRING_CHOOSER] = 4;
if (*(gBattleStruct->AI_itemFlags + (gBankAttacker >> 1)) & 0x80)
{
gBattleCommunication[MULTISTRING_CHOOSER] = 5;
}
else
{
PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_ATK)
PREPARE_STRING_BUFFER(gBattleTextBuff2, 0xD2)
while (!((*(gBattleStruct->AI_itemFlags + (gBankAttacker >> 1))) & 1))
{
*(gBattleStruct->AI_itemFlags + gBankAttacker / 2) >>= 1;
gBattleTextBuff1[2]++;
}
gBattleScripting.animArg1 = gBattleTextBuff1[2] + 14;
gBattleScripting.animArg2 = 0;
}
break;
case AI_ITEM_GUARD_SPECS:
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
else
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
break;
}
gBattlescriptCurrInstr = gUnknown_082DBD3C[*(gBattleStruct->AI_itemType + gBankAttacker / 2)];
}
gCurrentActionFuncId = ACTION_RUN_BATTLESCRIPT;
}
bool8 TryRunFromBattle(u8 bank)
{
bool8 effect = FALSE;
u8 holdEffect;
u8 pyramidMultiplier;
u8 speedVar;
if (gBattleMons[bank].item == ITEM_ENIGMA_BERRY)
holdEffect = gEnigmaBerries[bank].holdEffect;
else
holdEffect = ItemId_GetHoldEffect(gBattleMons[bank].item);
gStringBank = bank;
if (holdEffect == HOLD_EFFECT_CAN_ALWAYS_RUN)
{
gLastUsedItem = gBattleMons[bank].item ;
gProtectStructs[bank].fleeFlag = 1;
effect++;
}
else if (gBattleMons[bank].ability == ABILITY_RUN_AWAY)
{
if (InBattlePyramid())
{
gBattleStruct->runTries++;
pyramidMultiplier = sub_81A9E28();
speedVar = (gBattleMons[bank].speed * pyramidMultiplier) / (gBattleMons[bank ^ BIT_SIDE].speed) + (gBattleStruct->runTries * 30);
if (speedVar > (Random() & 0xFF))
{
gLastUsedAbility = ABILITY_RUN_AWAY;
gProtectStructs[bank].fleeFlag = 2;
effect++;
}
}
else
{
gLastUsedAbility = ABILITY_RUN_AWAY;
gProtectStructs[bank].fleeFlag = 2;
effect++;
}
}
else if (gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_x4000000) && gBattleTypeFlags & BATTLE_TYPE_TRAINER)
{
effect++;
}
else
{
if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE))
{
if (InBattlePyramid())
{
pyramidMultiplier = sub_81A9E28();
speedVar = (gBattleMons[bank].speed * pyramidMultiplier) / (gBattleMons[bank ^ BIT_SIDE].speed) + (gBattleStruct->runTries * 30);
if (speedVar > (Random() & 0xFF))
effect++;
}
else if (gBattleMons[bank].speed < gBattleMons[bank ^ BIT_SIDE].speed)
{
speedVar = (gBattleMons[bank].speed * 128) / (gBattleMons[bank ^ BIT_SIDE].speed) + (gBattleStruct->runTries * 30);
if (speedVar > (Random() & 0xFF))
effect++;
}
else // same speed or faster
{
effect++;
}
}
gBattleStruct->runTries++;
}
if (effect)
{
gCurrentTurnActionNumber = gNoOfAllBanks;
gBattleOutcome = BATTLE_RAN;
}
return effect;
}
static void HandleAction_Run(void)
{
gBankAttacker = gBanksByTurnOrder[gCurrentTurnActionNumber];
if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000))
{
gCurrentTurnActionNumber = gNoOfAllBanks;
for (gActiveBank = 0; gActiveBank < gNoOfAllBanks; gActiveBank++)
{
if (GetBankSide(gActiveBank) == SIDE_PLAYER)
{
if (gActionForBanks[gActiveBank] == ACTION_RUN)
gBattleOutcome |= BATTLE_LOST;
}
else
{
if (gActionForBanks[gActiveBank] == ACTION_RUN)
gBattleOutcome |= BATTLE_WON;
}
}
gBattleOutcome |= BATTLE_OUTCOME_BIT_x80;
gSaveBlock2Ptr->field_CA9_b = 1;
}
else
{
if (GetBankSide(gBankAttacker) == SIDE_PLAYER)
{
if (!TryRunFromBattle(gBankAttacker)) // failed to run away
{
ClearFuryCutterDestinyBondGrudge(gBankAttacker);
gBattleCommunication[MULTISTRING_CHOOSER] = 3;
gBattlescriptCurrInstr = BattleScript_PrintFailedToRunString;
gCurrentActionFuncId = ACTION_RUN_BATTLESCRIPT;
}
}
else
{
if (gBattleMons[gBankAttacker].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION))
{
gBattleCommunication[MULTISTRING_CHOOSER] = 4;
gBattlescriptCurrInstr = BattleScript_PrintFailedToRunString;
gCurrentActionFuncId = ACTION_RUN_BATTLESCRIPT;
}
else
{
gCurrentTurnActionNumber = gNoOfAllBanks;
gBattleOutcome = BATTLE_POKE_FLED;
}
}
}
}
static void HandleAction_WatchesCarefully(void)
{
gBankAttacker = gBanksByTurnOrder[gCurrentTurnActionNumber];
gBattle_BG0_X = 0;
gBattle_BG0_Y = 0;
gBattlescriptCurrInstr = gBattlescriptsForSafariActions[0];
gCurrentActionFuncId = ACTION_RUN_BATTLESCRIPT;
}
static void HandleAction_SafariZoneBallThrow(void)
{
gBankAttacker = gBanksByTurnOrder[gCurrentTurnActionNumber];
gBattle_BG0_X = 0;
gBattle_BG0_Y = 0;
gNumSafariBalls--;
gLastUsedItem = ITEM_SAFARI_BALL;
gBattlescriptCurrInstr = gBattlescriptsForBallThrow[ITEM_SAFARI_BALL];
gCurrentActionFuncId = ACTION_RUN_BATTLESCRIPT;
}
static void HandleAction_ThrowPokeblock(void)
{
gBankAttacker = gBanksByTurnOrder[gCurrentTurnActionNumber];
gBattle_BG0_X = 0;
gBattle_BG0_Y = 0;
gBattleCommunication[MULTISTRING_CHOOSER] = gBattleBufferB[gBankAttacker][1] - 1;
gLastUsedItem = gBattleBufferB[gBankAttacker][2];
if (gBattleResults.field_1F < 0xFF)
gBattleResults.field_1F++;
if (gBattleStruct->field_7A < 3)
gBattleStruct->field_7A++;
if (gBattleStruct->field_7B > 1)
{
if (gBattleStruct->field_7B < sUnknown_0831BCE0[gBattleStruct->field_7A][gBattleCommunication[MULTISTRING_CHOOSER]])
gBattleStruct->field_7B = 1;
else
gBattleStruct->field_7B -= sUnknown_0831BCE0[gBattleStruct->field_7A][gBattleCommunication[MULTISTRING_CHOOSER]];
}
gBattlescriptCurrInstr = gBattlescriptsForSafariActions[2];
gCurrentActionFuncId = ACTION_RUN_BATTLESCRIPT;
}
static void HandleAction_GoNear(void)
{
gBankAttacker = gBanksByTurnOrder[gCurrentTurnActionNumber];
gBattle_BG0_X = 0;
gBattle_BG0_Y = 0;
gBattleStruct->field_7C += sUnknown_0831BCEF[gBattleStruct->field_79];
if (gBattleStruct->field_7C > 20)
gBattleStruct->field_7C = 20;
gBattleStruct->field_7B +=sUnknown_0831BCF3[gBattleStruct->field_79];
if (gBattleStruct->field_7B > 20)
gBattleStruct->field_7B = 20;
if (gBattleStruct->field_79 < 3)
{
gBattleStruct->field_79++;
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
}
else
{
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
}
gBattlescriptCurrInstr = gBattlescriptsForSafariActions[1];
gCurrentActionFuncId = ACTION_RUN_BATTLESCRIPT;
}
static void HandleAction_SafriZoneRun(void)
{
gBankAttacker = gBanksByTurnOrder[gCurrentTurnActionNumber];
PlaySE(SE_NIGERU);
gCurrentTurnActionNumber = gNoOfAllBanks;
gBattleOutcome = BATTLE_RAN;
}
static void HandleAction_Action9(void)
{
gBankAttacker = gBanksByTurnOrder[gCurrentTurnActionNumber];
gBattle_BG0_X = 0;
gBattle_BG0_Y = 0;
PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, gBankAttacker, gBattlePartyID[gBankAttacker])
gBattlescriptCurrInstr = gBattlescriptsForSafariActions[3];
gCurrentActionFuncId = ACTION_RUN_BATTLESCRIPT;
gActionsByTurnOrder[1] = ACTION_FINISHED;
}
static void HandleAction_Action11(void)
{
if (!sub_8041728())
{
gBattleStruct->field_4D = 0;
gCurrentActionFuncId = ACTION_FINISHED;
}
}
static void HandleAction_NothingIsFainted(void)
{
gCurrentTurnActionNumber++;
gCurrentActionFuncId = gActionsByTurnOrder[gCurrentTurnActionNumber];
gHitMarker &= ~(HITMARKER_DESTINYBOND | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_ATTACKSTRING_PRINTED
| HITMARKER_NO_PPDEDUCT | HITMARKER_IGNORE_SAFEGUARD | HITMARKER_IGNORE_ON_AIR
| HITMARKER_IGNORE_UNDERGROUND | HITMARKER_IGNORE_UNDERWATER | HITMARKER_x100000
| HITMARKER_OBEYS | HITMARKER_x10 | HITMARKER_SYNCHRONISE_EFFECT
| HITMARKER_x8000000 | HITMARKER_x4000000);
}
static void HandleAction_ActionFinished(void)
{
*(gBattleStruct->monToSwitchIntoId + gBanksByTurnOrder[gCurrentTurnActionNumber]) = 6;
gCurrentTurnActionNumber++;
gCurrentActionFuncId = gActionsByTurnOrder[gCurrentTurnActionNumber];
SpecialStatusesClear();
gHitMarker &= ~(HITMARKER_DESTINYBOND | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_ATTACKSTRING_PRINTED
| HITMARKER_NO_PPDEDUCT | HITMARKER_IGNORE_SAFEGUARD | HITMARKER_IGNORE_ON_AIR
| HITMARKER_IGNORE_UNDERGROUND | HITMARKER_IGNORE_UNDERWATER | HITMARKER_x100000
| HITMARKER_OBEYS | HITMARKER_x10 | HITMARKER_SYNCHRONISE_EFFECT
| HITMARKER_x8000000 | HITMARKER_x4000000);
gCurrentMove = 0;
gBattleMoveDamage = 0;
gBattleMoveFlags = 0;
gBattleScripting.animTurn = 0;
gBattleScripting.animTargetsHit = 0;
gLastLandedMoves[gBankAttacker] = 0;
gLastHitByType[gBankAttacker] = 0;
gBattleStruct->dynamicMoveType = 0;
gDynamicBasePower = 0;
gBattleScripting.atk49_state = 0;
gBattleCommunication[3] = 0;
gBattleCommunication[4] = 0;
gBattleScripting.field_16 = 0;
gBattleResources->battleScriptsStack->size = 0;
}