summaryrefslogtreecommitdiff
path: root/src/battle_2.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/battle_2.c')
-rw-r--r--src/battle_2.c2374
1 files changed, 2374 insertions, 0 deletions
diff --git a/src/battle_2.c b/src/battle_2.c
new file mode 100644
index 000000000..8d1f6a7a1
--- /dev/null
+++ b/src/battle_2.c
@@ -0,0 +1,2374 @@
+#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 "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"
+
+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 u32 gBattleTypeFlags;
+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 struct UnknownPokemonStruct2 gUnknown_02022FF8[3]; // what is it used for?
+extern struct UnknownPokemonStruct2* gUnknown_02023058; // what is it used for?
+extern u8 gBattleOutcome;
+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 const u8 gSpeciesNames[][POKEMON_NAME_LENGTH + 1];
+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[];
+
+// 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 void HandleLinkBattleSetup(void); // rom_3
+extern void SetUpBattleVarsAndBirchZigzagoon(void); // rom_3
+extern void sub_8032768(void); // rom_3
+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 sub_80729D0(u8 healthoxSpriteId);
+
+// 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);
+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 oac_poke_opponent(struct Sprite *sprite);
+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);
+void sub_8039AF4(struct Sprite *sprite);
+
+void CB2_InitBattle(void)
+{
+ MoveSaveBlocks_ResetHeap();
+ AllocateBattleResrouces();
+ 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) == 3; 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);
+ }
+}
+
+static 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) == 3; 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();
+ sub_814F9EC(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)
+ {
+ sub_814F9EC(gText_RecordBattleToPass, 0);
+ gBattleCommunication[MULTIUSE_STATE]++;
+ }
+ break;
+ case 4:
+ if (!IsTextPrinterActive(0))
+ {
+ sub_8056A3C(0x18, 8, 0x1D, 0xD, 0);
+ sub_814F9EC(gText_BattleYesNoChoice, 0xC);
+ gBattleCommunication[CURSOR_POSITION] = 1;
+ BattleCreateCursorAt(1);
+ gBattleCommunication[MULTIUSE_STATE]++;
+ }
+ break;
+ case 5:
+ if (gMain.newKeys & DPAD_UP)
+ {
+ if (gBattleCommunication[CURSOR_POSITION] != 0)
+ {
+ PlaySE(SE_SELECT);
+ BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]);
+ gBattleCommunication[CURSOR_POSITION] = 0;
+ BattleCreateCursorAt(0);
+ }
+ }
+ else if (gMain.newKeys & DPAD_DOWN)
+ {
+ if (gBattleCommunication[CURSOR_POSITION] == 0)
+ {
+ PlaySE(SE_SELECT);
+ BattleDestroyCursorAt(gBattleCommunication[CURSOR_POSITION]);
+ gBattleCommunication[CURSOR_POSITION] = 1;
+ BattleCreateCursorAt(1);
+ }
+ }
+ else if (gMain.newKeys & A_BUTTON)
+ {
+ PlaySE(SE_SELECT);
+ if (gBattleCommunication[CURSOR_POSITION] == 0)
+ {
+ sub_8056A3C(0x18, 8, 0x1D, 0xD, 1);
+ 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)
+ {
+ sub_8056A3C(0x18, 8, 0x1D, 0xD, 1);
+ if (gMain.field_439_x4)
+ {
+ sub_800ADF8();
+ sub_814F9EC(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);
+ sub_814F9EC(gDisplayedStringBattle, 0);
+ gBattleCommunication[1] = 0x80;
+ gBattleCommunication[MULTIUSE_STATE]++;
+ }
+ else
+ {
+ BattleStringExpandPlaceholdersToDisplayedString(gText_BattleRecordCouldntBeSaved);
+ sub_814F9EC(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();
+ sub_814F9EC(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
+
+static 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);
+ sub_80729D0(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;
+}
+
+extern u32 gUnknown_02022F88;
+extern u16 gBattlePartyID[BATTLE_BANKS_COUNT];
+extern u8 gBattleMonForms[BATTLE_BANKS_COUNT];
+
+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;
+}
+
+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;
+}
+