#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 "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" 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* gUnknown_02024230[BATTLE_BANKS_COUNT]; extern u16 gUnknownMovesUsedByBanks[BATTLE_BANKS_COUNT]; extern u16 gLastUsedMovesByBanks[BATTLE_BANKS_COUNT]; extern u16 gUnknown_02024250[BATTLE_BANKS_COUNT]; extern u16 gUnknown_02024258[BATTLE_BANKS_COUNT]; extern u16 gUnknown_02024260[BATTLE_BANKS_COUNT]; extern u16 gLockedMoves[BATTLE_BANKS_COUNT]; extern u8 gUnknown_02024270[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* gBattlescriptPtrsForSelection[BATTLE_BANKS_COUNT]; extern const u8* gBattlescriptCurrInstr; extern u32 gBattlePalaceMoveSelectionRngValue; extern u8 gActionsByTurnOrder[BATTLE_BANKS_COUNT]; extern u8 gCurrentTurnActionNumber; extern u16 gDynamicBasePower; extern u8 gCritMultiplier; extern u8 gCurrMovePos; extern u8 gUnknown_020241E9; extern u16 gLastUsedMove; 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[]; // battlescripts extern const u8 gUnknown_082DB8BE[]; extern const u8 gUnknown_082DB881[]; extern const u8 BattleScript_ActionSelectionItemsCantBeUsed[]; extern const u8 gUnknown_082DAB11[]; extern const u8 gUnknown_082DB9BA[]; extern const u8 gUnknown_082DAAFE[]; extern const u8 gUnknown_082DAB0B[]; extern const u8 BattleScript_FocusPunchSetUp[]; extern const u8 BattleScript_LinkBattleWonOrLost[]; extern const u8 BattleScript_FrontierTrainerBattleWon[]; extern const u8 BattleScript_LocalTrainerBattleWon[]; extern const u8 BattleScript_PayDayMoneyAndPickUpItems[]; extern const u8 BattleScript_LocalBattleLost[]; extern const u8 gUnknown_082DB9C8[]; extern const u8 gUnknown_082DAA0B[]; extern const u8 gUnknown_082DB9C1[]; extern const u8 BattleScript_RanAwayUsingMonAbility[]; extern const u8 BattleScript_SmokeBallEscape[]; extern const u8 BattleScript_GotAwaySafely[]; extern const u8 BattleScript_WildMonFled[]; extern const u8 BattleScript_MoveUsedLoafingAround[]; extern const u8 BattleScript_ActionSwitch[]; extern const u8 BattleScript_PrintFailedToRunString[]; // 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 sub_81DB4DC(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 < 6; 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(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) sub_81DB4DC(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()) { gScriptResult = 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 < 6; 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 < 6; 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(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; } } } // to get rid of once the struct is declared in a header struct MonCoords { // This would use a bitfield, but sub_8079F44 // uses it as a u8 and casting won't match. u8 coords; // u8 x:4, y:4; u8 y_offset; }; 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; gLastUsedMovesByBanks[i] = 0; gUnknown_02024250[i] = 0; gUnknown_02024258[i] = 0; gUnknown_02024260[i] = 0; gUnknown_02024270[i] = 0xFF; gLockedMoves[i] = 0; gUnknownMovesUsedByBanks[i] = 0; gBattleResources->flags->flags[i] = 0; gUnknown_02024230[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)) && sub_8185FB8()) 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].perishSong1 = disableStructCopy.perishSong1; gDisableStructs[gActiveBank].perishSong2 = disableStructCopy.perishSong2; gDisableStructs[gActiveBank].bankPreventingEscape = disableStructCopy.bankPreventingEscape; } gBattleMoveFlags = 0; gDisableStructs[gActiveBank].isFirstTurn= 2; gDisableStructs[gActiveBank].truantUnknownBit = disableStructCopy.truantUnknownBit; gLastUsedMovesByBanks[gActiveBank] = 0; gUnknown_02024250[gActiveBank] = 0; gUnknown_02024258[gActiveBank] = 0; gUnknown_02024260[gActiveBank] = 0; gUnknownMovesUsedByBanks[gActiveBank] = 0; gUnknown_02024270[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; gLastUsedMovesByBanks[gActiveBank] = 0; gUnknown_02024250[gActiveBank] = 0; gUnknown_02024258[gActiveBank] = 0; gUnknown_02024260[gActiveBank] = 0; gUnknownMovesUsedByBanks[gActiveBank] = 0; gUnknown_02024270[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 < 6; 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 < 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); } } 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(gUnknown_082DB8BE); } } 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(gUnknown_082DB881); else if (gBattleTypeFlags & BATTLE_TYPE_ARENA && gBattleStruct->field_DA == 0) BattleScriptExecute(gUnknown_082DB8BE); } 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 sub_8185FD0(); 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); gBattlescriptPtrsForSelection[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()) { gBattlescriptPtrsForSelection[gActiveBank] = gUnknown_082DAB11; 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) { gBattlescriptPtrsForSelection[gActiveBank] = gUnknown_082DB9BA; 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(gUnknown_082DAAFE); gBattleCommunication[gActiveBank] = 1; } else if (IsRunningFromBattleImpossible() != 0 && gBattleBufferB[gActiveBank][1] == ACTION_RUN) { gBattlescriptPtrsForSelection[gActiveBank] = gUnknown_082DAB0B; 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 = gBattlescriptPtrsForSelection[gActiveBank]; if (!(gBattleExecBuffer & ((gBitTable[gActiveBank]) | (0xF0000000) | (gBitTable[gActiveBank] << 4) | (gBitTable[gActiveBank] << 8) | (gBitTable[gActiveBank] << 0xC)))) { gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]](); } gBattlescriptPtrsForSelection[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 = gBattlescriptPtrsForSelection[gActiveBank]; if (!(gBattleExecBuffer & ((gBitTable[gActiveBank]) | (0xF0000000) | (gBitTable[gActiveBank] << 4) | (gBitTable[gActiveBank] << 8) | (gBitTable[gActiveBank] << 0xC)))) { gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]](); } gBattlescriptPtrsForSelection[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(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(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)) { gScriptResult = 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 = gUnknown_082DB9C8; gBattleOutcome &= ~(BATTLE_OUTCOME_BIT_x80); gSaveBlock2Ptr->field_CA9_b = 1; } else { gBattlescriptCurrInstr = gUnknown_082DAA0B; 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 = gUnknown_082DB9C1; gBattleOutcome = BATTLE_FORFEITED; gSaveBlock2Ptr->field_CA9_b = 1; } else if (gBattleTypeFlags & BATTLE_TYPE_x4000000) { gBattlescriptCurrInstr = gUnknown_082DB9C1; 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; gScriptResult = 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 = gLastUsedMove = 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 = gLastUsedMove = 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 = gLastUsedMove = 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 = gLastUsedMove = 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 = gLastUsedMove = gBattleMons[gBankAttacker].moves[gCurrMovePos]; *(gBattleStruct->moveTarget + gBankAttacker) = GetMoveTarget(gCurrentMove, 0); } else { gCurrentMove = gLastUsedMove = 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[gLastUsedMove].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[gLastUsedMove].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 (gUnknown_02024230[gBankAttacker] != NULL) { gBattleCommunication[MULTISTRING_CHOOSER] = 4; gBattlescriptCurrInstr = gUnknown_02024230[gBankAttacker]; gUnknown_02024230[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; gUnknown_02024250[gBankAttacker] = 0; gUnknown_02024258[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; }