#include "global.h" #include "cable_club.h" #include "battle.h" #include "battle_records.h" #include "constants/songs.h" #include "contest_util.h" #include "event_data.h" #include "field_message_box.h" #include "field_specials.h" #include "field_weather.h" #include "link.h" #include "load_save.h" #include "m4a.h" #include "main.h" #include "menu.h" #include "overworld.h" #include "palette.h" #include "record_mixing.h" #include "script.h" #include "sound.h" #include "start_menu.h" #include "string_util.h" #include "strings2.h" #include "task.h" #include "text.h" #include "trade.h" #include "trainer_card.h" extern u16 gBattleTypeFlags; extern const u8 gUnknown_081A4932[]; extern const u8 gUnknown_081A4975[]; extern const u8 gUnknown_081A49B6[]; extern const u8 gUnknown_081A490C[]; extern struct { u8 field0; u8 field1; } gUnknown_020297D8; static void sub_8082F20(u8 taskId); static void sub_8082F68(u8 taskId); static void sub_8082FEC(u8 taskId); static void sub_808303C(u8 taskId); static void sub_80830E4(u8 taskId); static void sub_8083188(u8 taskId); static void sub_80831F8(u8 taskId); static void sub_8083288(u8 taskId); static void sub_8083314(u8 taskId); static void sub_80833C4(u8 taskId); static void sub_80833EC(u8 taskId); static void sub_8083418(u8 taskId); static bool8 sub_8083444(u8 taskId); static void sub_808353C(u8 taskId); static void sub_8083710(u8 taskId); static void sub_8083760(u8 taskId); static void sub_80837B4(u8 taskId); static void sub_80837EC(u8 taskId); static void sub_808382C(u8 taskId); static void sub_8083958(void); static void sub_80839DC(u8 taskId); static void sub_8083AAC(u8 taskId); static void sub_8083B44(u8 taskId); static void sub_8083B6C(void); static void sub_8083CA4(u8 taskId); #if DEBUG static u8 debug_sub_808B850(void); #endif #ifdef GERMAN const u8 TrainerCardColorName_Bronze[] = _("BRONZE"); const u8 TrainerCardColorName_Copper[] = _("KUPFER"); const u8 TrainerCardColorName_Silver[] = _("SILBER"); const u8 TrainerCardColorName_Gold[] = _("GOLD"); #else const u8 TrainerCardColorName_Bronze[] = _("BRONZE"); const u8 TrainerCardColorName_Copper[] = _("COPPER"); const u8 TrainerCardColorName_Silver[] = _("SILVER"); const u8 TrainerCardColorName_Gold[] = _("GOLD"); #endif const u8 *const gTrainerCardColorNames[] = { TrainerCardColorName_Bronze, TrainerCardColorName_Copper, TrainerCardColorName_Silver, TrainerCardColorName_Gold, }; #if DEBUG u8 debug_sub_808A4D0(TaskFunc func) { if (func == sub_8082F68) return 1; if (func == sub_8082FEC) return 17; if (func == sub_808303C) return 18; if (func == sub_8083188) return 19; if (func == sub_80830E4) return 20; if (func == sub_80831F8) return 33; if (func == sub_8083314) return 2; if (func == sub_80833C4) return 3; return 0; } void debug_sub_808A55C(u8 taskId) { s32 i; if (!gTasks[gTasks[taskId].data[0]].isActive) { if (gTasks[taskId].data[1] == 5) DestroyTask(taskId); gTasks[taskId].data[1]++; } PrintHex(gShouldAdvanceLinkState, 2, 0, 2); PrintHex((u8)gBlockSendBuffer[0], 22, 5, 4); for (i = 0; i < 4; i++) { PrintHex(gLinkPlayerPending[i], 5 + i * 2, 0, 1); PrintHex(gBlockRecvBuffer[i][0], 22, 6 + i, 4); } PrintHex(gLinkStatus, 15, 0, 8); PrintHex(gLink.state, 2, 10, 2); PrintHex(GetMultiplayerId(), 7, 12, 2); PrintHex(GetBlockReceivedStatus(), 7, 10, 2); PrintHex(gReceivedRemoteLinkPlayers, 2, 12, 1); PrintHex(gSpecialVar_Result, 11, 8, 2); PrintHex((gLinkStatus & 0x1C) >> 2, 11, 10, 2); PrintHex(IsLinkConnectionEstablished(), 11, 12, 1); PrintHex(IsLinkTaskFinished(), 15, 10, 1); PrintHex(debug_sub_808A4D0(gTasks[gTasks[taskId].data[0]].func), 15, 12, 2); PrintHex((uintptr_t)gLinkCallback, 2, 13, 8); PrintHex(HasLinkErrorOccurred(), 2, 2, 1); for (i = 0; i < 4; i++) PrintHex(gLinkPlayers[i].linkType, 2 + i * 6, 3, 4); PrintHex(REG_SIOCNT, 2, 6, 4); PrintHex(debug_sub_808B850(), 25, 3, 1); } #endif static void sub_8082CD4(u8 arg0, u8 arg1) { #if DEBUG InitLinkTestBG_Unused(12, 0, 31, 2); #endif if (FindTaskIdByFunc(sub_8082F20) == 0xFF) { u8 taskId1; #if DEBUG u8 taskId2; #endif taskId1 = CreateTask(sub_8082F20, 80); gTasks[taskId1].data[1] = arg0; gTasks[taskId1].data[2] = arg1; #if DEBUG taskId2 = CreateTask(debug_sub_808A55C, 80); gTasks[taskId2].data[0] = taskId1; #endif } } static void sub_8082D18(u32 value) { ConvertIntToDecimalStringN(gStringVar1, value, STR_CONV_MODE_LEFT_ALIGN, 1); Menu_DrawStdWindowFrame(18, 10, 28, 13); MenuPrint_Centered(gOtherText_PLink, 19, 11, 72); } static void sub_8082D4C() { Menu_EraseWindowRect(18, 10, 28, 13); } static void sub_8082D60(u8 taskId, u8 arg1) { s16 *data = &gTasks[taskId].data[3]; if (arg1 != *data) { if (arg1 <= 1) sub_8082D4C(); else sub_8082D18(arg1); *data = arg1; } } static u32 sub_8082D9C(u8 minPlayers, u8 maxPlayers) { int playerCount; switch (GetLinkPlayerDataExchangeStatusTimed()) { case EXCHANGE_COMPLETE: playerCount = GetLinkPlayerCount_2(); if (minPlayers <= playerCount && playerCount <= maxPlayers) return 1; ConvertIntToDecimalStringN(gStringVar1, playerCount, STR_CONV_MODE_LEFT_ALIGN, 1); return 4; case EXCHANGE_TIMED_OUT: return 0; case EXCHANGE_IN_PROGRESS: return 3; default: return 0; } } static bool32 sub_8082DF4(u8 taskId) { if (HasLinkErrorOccurred() == TRUE) { gTasks[taskId].func = sub_8083418; return TRUE; } return FALSE; } static bool32 sub_8082E28(u8 taskId) { if ((gMain.newKeys & B_BUTTON) && IsLinkConnectionEstablished() == FALSE) { gTasks[taskId].func = sub_80833EC; return TRUE; } return FALSE; } static bool32 sub_8082E6C(u8 taskId) { if (IsLinkConnectionEstablished()) SetSuppressLinkErrorMessage(TRUE); if (gMain.newKeys & B_BUTTON) { gTasks[taskId].func = sub_80833EC; return TRUE; } return FALSE; } static bool32 sub_8082EB8(u8 taskId) { if (GetSioMultiSI() == 1) { gTasks[taskId].func = sub_8083418; return TRUE; } return FALSE; } void unref_sub_8082EEC(u8 taskId) { gTasks[taskId].data[0]++; if (gTasks[taskId].data[0] == 10) { sub_8007E9C(2); DestroyTask(taskId); } } static void sub_8082F20(u8 taskId) { s16 *data = gTasks[taskId].data; if (data[0] == 0) { OpenLinkTimed(); sub_80082EC(); ResetLinkPlayers(); } else if (data[0] > 9) { gTasks[taskId].func = sub_8082F68; } data[0]++; } static void sub_8082F68(u8 taskId) { u32 playerCount = GetLinkPlayerCount_2(); if (sub_8082E28(taskId) == TRUE || sub_8082E6C(taskId) == TRUE || playerCount < 2) return; SetSuppressLinkErrorMessage(TRUE); gTasks[taskId].data[3] = 0; if (IsLinkMaster() == TRUE) { PlaySE(SE_PIN); ShowFieldAutoScrollMessage(gUnknown_081A4932); gTasks[taskId].func = sub_8082FEC; } else { PlaySE(SE_BOO); ShowFieldAutoScrollMessage(gUnknown_081A49B6); gTasks[taskId].func = sub_80831F8; } } static void sub_8082FEC(u8 taskId) { if (sub_8082E28(taskId) == TRUE || sub_8082EB8(taskId) == TRUE || sub_8082DF4(taskId) == TRUE) return; if (GetFieldMessageBoxMode() == FIELD_MESSAGE_BOX_HIDDEN) { gTasks[taskId].data[3] = 0; gTasks[taskId].func = sub_808303C; } } static void sub_808303C(u8 taskId) { s16 *taskData = gTasks[taskId].data; s32 linkPlayerCount = GetLinkPlayerCount_2(); if (sub_8082E28(taskId) == TRUE || sub_8082EB8(taskId) == TRUE || sub_8082DF4(taskId) == TRUE) return; sub_8082D60(taskId, linkPlayerCount); if (!(gMain.newKeys & A_BUTTON)) return; #if ENGLISH if (linkPlayerCount < taskData[1]) return; sub_80081C8(linkPlayerCount); sub_8082D4C(); ConvertIntToDecimalStringN(gStringVar1, linkPlayerCount, STR_CONV_MODE_LEFT_ALIGN, 1); ShowFieldAutoScrollMessage((u8 *)gUnknown_081A4975); gTasks[taskId].func = sub_80830E4; #elif GERMAN if ((gLinkType == 0x2255 && (u32)linkPlayerCount > 1) || (gLinkType != 0x2255 && taskData[1] <= linkPlayerCount)) { sub_80081C8(linkPlayerCount); sub_8082D4C(); ConvertIntToDecimalStringN(gStringVar1, linkPlayerCount, STR_CONV_MODE_LEFT_ALIGN, 1); ShowFieldAutoScrollMessage((u8 *)gUnknown_081A4975); gTasks[taskId].func = sub_80830E4; } #endif } static void sub_80830E4(u8 taskId) { if (sub_8082E28(taskId) == TRUE || sub_8082EB8(taskId) == TRUE || sub_8082DF4(taskId) == TRUE) return; if (GetFieldMessageBoxMode() == FIELD_MESSAGE_BOX_HIDDEN) { if (sub_800820C() != GetLinkPlayerCount_2()) { ShowFieldAutoScrollMessage(gUnknown_081A4932); gTasks[taskId].func = sub_8082FEC; } else if (gMain.heldKeys & B_BUTTON) { ShowFieldAutoScrollMessage(gUnknown_081A4932); gTasks[taskId].func = sub_8082FEC; } else if (gMain.heldKeys & A_BUTTON) { PlaySE(SE_SELECT); sub_8007F4C(); gTasks[taskId].func = sub_8083188; } } } static void sub_8083188(u8 taskId) { u8 local1 = gTasks[taskId].data[1]; u8 local2 = gTasks[taskId].data[2]; if (sub_8082DF4(taskId) == TRUE || sub_8083444(taskId) == TRUE) return; if (GetLinkPlayerCount_2() != sub_800820C()) { gTasks[taskId].func = sub_8083418; } else { gSpecialVar_Result = sub_8082D9C(local1, local2); if (gSpecialVar_Result != 0) gTasks[taskId].func = sub_8083288; } } static void sub_80831F8(u8 taskId) { u8 local1, local2; local1 = gTasks[taskId].data[1]; local2 = gTasks[taskId].data[2]; if (sub_8082E28(taskId) == TRUE || sub_8082DF4(taskId) == TRUE) return; #if DEBUG sub_8082D60(taskId, GetLinkPlayerCount_2()); #endif gSpecialVar_Result = sub_8082D9C(local1, local2); if (gSpecialVar_Result == 0) return; if (gSpecialVar_Result == 3) { SetCloseLinkCallback(); HideFieldMessageBox(); gTasks[taskId].func = sub_80833C4; } else { gFieldLinkPlayerCount = GetLinkPlayerCount_2(); gUnknown_03004860 = GetMultiplayerId(); sub_80081C8(gFieldLinkPlayerCount); TrainerCard_GenerateCardForPlayer((struct TrainerCard *)gBlockSendBuffer); gTasks[taskId].func = sub_8083314; } } static void sub_8083288(u8 taskId) { if (sub_8082DF4(taskId) == TRUE) return; if (gSpecialVar_Result == 3) { SetCloseLinkCallback(); HideFieldMessageBox(); gTasks[taskId].func = sub_80833C4; } else { gFieldLinkPlayerCount = GetLinkPlayerCount_2(); gUnknown_03004860 = GetMultiplayerId(); sub_80081C8(gFieldLinkPlayerCount); TrainerCard_GenerateCardForPlayer((struct TrainerCard *)gBlockSendBuffer); gTasks[taskId].func = sub_8083314; sub_8007E9C(2); } } static void sub_8083314(u8 taskId) { u8 index; struct TrainerCard *trainerCards; if (sub_8082DF4(taskId) == TRUE) return; if (GetBlockReceivedStatus() != sub_8008198()) return; index = 0; trainerCards = gTrainerCards; for (index = 0; index < GetLinkPlayerCount(); index++) { void *src; src = gBlockRecvBuffer[index]; memcpy(&trainerCards[index], src, sizeof(struct TrainerCard)); } SetSuppressLinkErrorMessage(FALSE); ResetBlockReceivedFlags(); HideFieldMessageBox(); if (gSpecialVar_Result == 1) { #if ENGLISH u16 linkType; linkType = gLinkType; // FIXME: sub_8082D4C doesn't take any arguments sub_8082D4C(0x4411, linkType); #elif GERMAN if (gLinkType != 0x4411) { if (gLinkType == 0x6601) deUnkValue2 = 1; } sub_8082D4C(); #endif EnableBothScriptContexts(); DestroyTask(taskId); return; } SetCloseLinkCallback(); gTasks[taskId].func = sub_80833C4; } static void sub_80833C4(u8 taskId) { if (gReceivedRemoteLinkPlayers == FALSE) { sub_8082D4C(); EnableBothScriptContexts(); DestroyTask(taskId); } } static void sub_80833EC(u8 taskId) { gSpecialVar_Result = 5; sub_8082D4C(); HideFieldMessageBox(); EnableBothScriptContexts(); DestroyTask(taskId); } static void sub_8083418(u8 taskId) { gSpecialVar_Result = 6; sub_8082D4C(); HideFieldMessageBox(); EnableBothScriptContexts(); DestroyTask(taskId); } static bool8 sub_8083444(u8 taskId) { gTasks[taskId].data[4]++; if (gTasks[taskId].data[4] > 600) { gTasks[taskId].func = sub_8083418; return TRUE; } return FALSE; } void sub_808347C(u8 arg0) { u32 r3 = 2; u32 r2 = 2; switch (gSpecialVar_0x8004) { case 1: r3 = 2; gLinkType = 0x2233; break; case 2: r3 = 2; gLinkType = 0x2244; break; case 5: r3 = 4; r2 = 4; gLinkType = 0x2255; break; } sub_8082CD4(r3, r2); } void sub_80834E4(void) { gLinkType = 0x1133; gBattleTypeFlags = 0; sub_8082CD4(2, 2); } void sub_808350C(void) { gSpecialVar_Result = 0; gLinkType = 0x3311; gBattleTypeFlags = 0; sub_8082CD4(2, 4); } static void sub_808353C(u8 taskId) { int playerCount; int i; switch (gTasks[taskId].data[0]) { case 0: if (gSpecialVar_Result == 1) { playerCount = GetLinkPlayerCount(); for (i = 0; i < playerCount; i++) { if (gLinkPlayers[i].language == LANGUAGE_JAPANESE) { gSpecialVar_Result = 7; sub_8008480(); gTasks[taskId].data[0] = 1; return; } } } EnableBothScriptContexts(); DestroyTask(taskId); break; case 1: if (gReceivedRemoteLinkPlayers == FALSE) { EnableBothScriptContexts(); DestroyTask(taskId); } break; } } void sub_80835D8(void) { int taskId = FindTaskIdByFunc(sub_808353C); if (taskId == 0xFF) { taskId = CreateTask(sub_808353C, 80); gTasks[taskId].data[0] = 0; } } void sub_8083614(void) { gLinkType = 0x4411; gBattleTypeFlags = 0; sub_8082CD4(2, 4); } void sub_808363C(void) { gLinkType = 0x6601; gBattleTypeFlags = 0; sub_8082CD4(4, 4); } u8 sub_8083664(void) { if (FuncIsActiveTask(sub_8083710) != FALSE) return 0xFF; switch (gSpecialVar_0x8004) { case 1: gLinkType = 0x2233; break; case 2: gLinkType = 0x2244; break; case 5: gLinkType = 0x2255; break; case 3: gLinkType = 0x1111; break; case 4: gLinkType = 0x3322; break; } return CreateTask(sub_8083710, 80); } static void sub_8083710(u8 taskId) { s16 *data = gTasks[taskId].data; if (data[0] == 0) { OpenLink(); ResetLinkPlayers(); CreateTask(sub_8083C50, 80); } else if (data[0] >= 10) { gTasks[taskId].func = sub_8083760; } data[0]++; } static void sub_8083760(u8 taskId) { if (GetLinkPlayerCount_2() >= 2) { if (IsLinkMaster() == TRUE) gTasks[taskId].func = sub_80837B4; else gTasks[taskId].func = sub_80837EC; } } static void sub_80837B4(u8 taskId) { if (sub_800820C() == GetLinkPlayerCount_2()) { sub_8007F4C(); gTasks[taskId].func = sub_80837EC; } } static void sub_80837EC(u8 taskId) { if (gReceivedRemoteLinkPlayers == TRUE && IsLinkPlayerDataExchangeComplete() == TRUE) { sub_800826C(); sub_8007B14(); DestroyTask(taskId); } } void sub_8083820(void) { SaveGame(); } static void sub_808382C(u8 taskId) { struct Task* task = &gTasks[taskId]; switch (task->data[0]) { case 0: FadeScreen(1, 0); gLinkType = 0x2211; ClearLinkCallback_2(); task->data[0]++; break; case 1: if (!gPaletteFade.active) task->data[0]++; break; case 2: task->data[1]++; if (task->data[1] > 20) task->data[0]++; break; case 3: SetCloseLinkCallback(); task->data[0]++; break; case 4: if (!gReceivedRemoteLinkPlayers) task->data[0]++; break; case 5: if (gLinkPlayers[0].trainerId & 1) current_map_music_set__default_for_battle(MUS_VS_GYM_LEADER); else current_map_music_set__default_for_battle(MUS_VS_TRAINER); switch (gSpecialVar_0x8004) { case 1: gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_LINK; break; case 2: gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_LINK | BATTLE_TYPE_DOUBLE; break; case 5: ReducePlayerPartyToThree(); gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_LINK | BATTLE_TYPE_DOUBLE | BATTLE_TYPE_MULTI; break; } SetMainCallback2(CB2_InitBattle); gMain.savedCallback = sub_8083958; DestroyTask(taskId); break; } } static void sub_8083958(void) { Overworld_ResetMapMusic(); LoadPlayerParty(); SavePlayerBag(); sub_810FEFC(); if (gSpecialVar_0x8004 != 5) UpdateLinkBattleRecords(gUnknown_03004860 ^ 1); gMain.savedCallback = sub_805465C; SetMainCallback2(sub_8071B28); } void sub_80839A4(void) { if (gSpecialVar_0x8004 == 1 || gSpecialVar_0x8004 == 2 || gSpecialVar_0x8004 == 5) { LoadPlayerParty(); SavePlayerBag(); } copy_saved_warp2_bank_and_enter_x_to_warp1(0x7F); } void sub_80839D0(void) { sub_805559C(); } static void sub_80839DC(u8 taskId) { struct Task* task = &gTasks[taskId]; switch (task->data[0]) { case 0: ShowFieldMessage(gUnknown_081A490C); task->data[0] = 1; break; case 1: if (IsFieldMessageBoxHidden()) { sub_8055574(); sub_8007270(gSpecialVar_0x8005); task->data[0] = 2; } break; case 2: switch (sub_80554F8()) { case 0: break; case 1: HideFieldMessageBox(); task->data[0] = 0; SwitchTaskToFollowupFunc(taskId); break; case 2: task->data[0] = 3; break; } break; case 3: sub_8055588(); HideFieldMessageBox(); Menu_EraseScreen(); DestroyTask(taskId); EnableBothScriptContexts(); break; } } void sub_8083A84(TaskFunc followupFunc) { u8 taskId = CreateTask(sub_80839DC, 80); SetTaskFuncWithFollowupFunc(taskId, sub_80839DC, followupFunc); ScriptContext1_Stop(); } static void sub_8083AAC(u8 taskId) { struct Task *task = &gTasks[taskId]; switch (task->data[0]) { case 0: ScriptContext2_Enable(); FadeScreen(1, 0); ClearLinkCallback_2(); task->data[0]++; break; case 1: if (!gPaletteFade.active) task->data[0]++; break; case 2: gUnknown_020297D8.field0 = 0; gUnknown_020297D8.field1 = 0; m4aMPlayAllStop(); SetCloseLinkCallback(); task->data[0]++; break; case 3: if (!gReceivedRemoteLinkPlayers) { SetMainCallback2(sub_8047CD8); DestroyTask(taskId); } break; } } static void sub_8083B44(u8 taskId) { sub_8083B6C(); DestroyTask(taskId); } void sub_8083B5C(void) { sub_8083A84(sub_8083B44); } static void sub_8083B6C(void) { CreateTask(sub_8083AAC, 80); } void sub_8083B80(void) { sub_8083B6C(); ScriptContext1_Stop(); } void sub_8083B90(void) { gLinkType = 0x2211; sub_8083A84(sub_808382C); } void unref_sub_8083BB0(void) { u8 taskId = CreateTask(sub_80839DC, 80); SetTaskFuncWithFollowupFunc(taskId, sub_80839DC, Task_RecordMixing_Main); ScriptContext1_Stop(); } void sub_8083BDC(void) { TrainerCard_ShowLinkCard(gSpecialVar_0x8006, CB2_ReturnToFieldContinueScriptPlayMapMusic); } bool32 sub_8083BF4(u8 linkPlayerIndex) { u32 trainerCardColorIndex; gSpecialVar_0x8006 = linkPlayerIndex; StringCopy(gStringVar1, gLinkPlayers[linkPlayerIndex].name); trainerCardColorIndex = sub_80934C4(linkPlayerIndex); if (trainerCardColorIndex == 0) return FALSE; StringCopy(gStringVar2, gTrainerCardColorNames[trainerCardColorIndex - 1]); return TRUE; } void sub_8083C50(u8 taskId) { struct Task *task = &gTasks[taskId]; task->data[0]++; if (task->data[0] > 300) { CloseLink(); SetMainCallback2(CB2_LinkError); DestroyTask(taskId); } if (gReceivedRemoteLinkPlayers) DestroyTask(taskId); } #if DEBUG u16 unk_3004E94; u32 unk_3004E98; static void debug_sub_808B7A8(u8); void debug_sub_808B778(void) { if (!FuncIsActiveTask(debug_sub_808B7A8)) CreateTask(debug_sub_808B7A8, 80); unk_3004E98++; } static void debug_sub_808B7A8(u8 taskId) { gTasks[taskId].data[0]++; if (gTasks[taskId].data[0] == 30) { gTasks[taskId].data[0] = 0; unk_3004E94 |= 1; } } #endif static void sub_8083CA4(u8 taskId) { if (!gReceivedRemoteLinkPlayers) { EnableBothScriptContexts(); DestroyTask(taskId); } } void unref_sub_8083CC8(u8 taskId) { SetCloseLinkCallback(); gTasks[taskId].func = sub_8083CA4; } #if DEBUG EWRAM_DATA static u8 unk_2030220 = 0; void debug_sub_808B82C(void) { unk_2030220 = 0; } void debug_sub_808B838(u8 a) { unk_2030220 |= 1 << a; } static u8 debug_sub_808B850(void) { return unk_2030220; } #endif