Files
Pokemon-Firered/src/cable_club.c
T
2022-11-26 18:08:49 -05:00

1027 lines
26 KiB
C

#include "global.h"
#include "gflib.h"
#include "battle.h"
#include "battle_records.h"
#include "cable_club.h"
#include "event_data.h"
#include "event_scripts.h"
#include "field_message_box.h"
#include "field_weather.h"
#include "link.h"
#include "load_save.h"
#include "m4a.h"
#include "mystery_gift.h"
#include "new_menu_helpers.h"
#include "overworld.h"
#include "quest_log.h"
#include "script.h"
#include "script_pokemon_util.h"
#include "start_menu.h"
#include "strings.h"
#include "task.h"
#include "trade.h"
#include "trainer_card.h"
#include "union_room.h"
#include "constants/songs.h"
#include "constants/cable_club.h"
#include "constants/field_weather.h"
#include "constants/maps.h"
u32 UnusedVarNeededToMatch[8];
static void Task_LinkupStart(u8 taskId);
static void Task_LinkupAwaitConnection(u8 taskId);
static void Task_LinkupConfirmWhenReady(u8 taskId);
static void Task_LinkupAwaitConfirmation(u8 taskId);
static void Task_LinkupTryConfirmation(u8 taskId);
static void Task_LinkupConfirm(u8 taskId);
static void Task_LinkupExchangeDataWithLeader(u8 taskId);
static void Task_LinkupCheckStatusAfterConfirm(u8 taskId);
static void Task_LinkupAwaitTrainerCardData(u8 taskId);
static void Task_StopLinkup(u8 taskId);
static void Task_LinkupFailed(u8 taskId);
static void Task_LinkupConnectionError(u8 taskId);
static bool8 TryLinkTimeout(u8 taskId);
static void Task_ReestablishLink(u8 taskId);
static void Task_ReestablishLinkAwaitConnection(u8 taskId);
static void Task_ReestablishLinkLeader(u8 taskId);
static void Task_ReestablishLinkAwaitConfirmation(u8 taskId);
#define tState data[0]
#define tMinPlayers data[1]
#define tMaxPlayers data[2]
#define tNumPlayers data[3]
#define tTimer data[4]
#define tWindowId data[5]
static const struct WindowTemplate sWindowTemplate_LinkPlayerCount = {
.bg = 0,
.tilemapLeft = 16,
.tilemapTop = 11,
.width = 11,
.height = 2,
.paletteNum = 15,
.baseBlock = 0x125
};
static const u8 *const sTrainerCardColorNames[] = {
gText_BronzeCard,
gText_CopperCard,
gText_SilverCard,
gText_GoldCard
};
static void CreateLinkupTask(u8 minPlayers, u8 maxPlayers)
{
u8 taskId;
if (FindTaskIdByFunc(Task_LinkupStart) == TASK_NONE)
{
taskId = CreateTask(Task_LinkupStart, 80);
gTasks[taskId].tMinPlayers = minPlayers;
gTasks[taskId].tMaxPlayers = maxPlayers;
}
}
static void PrintNumPlayersInLink(u16 windowId, s32 numPlayers)
{
ConvertIntToDecimalStringN(gStringVar1, numPlayers, STR_CONV_MODE_LEFT_ALIGN, 1);
SetStdWindowBorderStyle(windowId, FALSE);
StringExpandPlaceholders(gStringVar4, gText_NumPlayerLink);
AddTextPrinterParameterized(windowId, FONT_NORMAL, gStringVar4, 0, 0, TEXT_SKIP_DRAW, NULL);
CopyWindowToVram(windowId, COPYWIN_FULL);
}
static void ClearLinkPlayerCountWindow(u16 windowId)
{
ClearStdWindowAndFrame(windowId, FALSE);
CopyWindowToVram(windowId, COPYWIN_FULL);
}
static void UpdateLinkPlayerCountDisplay(u8 taskId, u8 numPlayers)
{
s16 *data = gTasks[taskId].data;
if (numPlayers != tNumPlayers)
{
if (numPlayers < 2)
ClearLinkPlayerCountWindow(tWindowId);
else
PrintNumPlayersInLink(tWindowId, numPlayers);
tNumPlayers = numPlayers;
}
}
static u16 ExchangeDataAndGetLinkupStatus(u8 minPlayers, u8 maxPlayers)
{
switch (GetLinkPlayerDataExchangeStatusTimed(minPlayers, maxPlayers))
{
case EXCHANGE_COMPLETE:
return LINKUP_SUCCESS;
case EXCHANGE_DIFF_SELECTIONS:
return LINKUP_DIFF_SELECTIONS;
case EXCHANGE_PLAYER_NOT_READY:
return LINKUP_PLAYER_NOT_READY;
case EXCHANGE_PARTNER_NOT_READY:
return LINKUP_PARTNER_NOT_READY;
case EXCHANGE_WRONG_NUM_PLAYERS:
ConvertIntToDecimalStringN(gStringVar1, GetLinkPlayerCount_2(), STR_CONV_MODE_LEFT_ALIGN, 1);
return LINKUP_WRONG_NUM_PLAYERS;
default:
return LINKUP_ONGOING;
}
}
static bool32 CheckLinkErrored(u8 taskId)
{
if (HasLinkErrorOccurred() == TRUE)
{
gTasks[taskId].func = Task_LinkupConnectionError;
return TRUE;
}
return FALSE;
}
static bool32 CheckLinkCanceledBeforeConnection(u8 taskId)
{
if (JOY_NEW(B_BUTTON) && !IsLinkConnectionEstablished())
{
gLinkType = 0;
gTasks[taskId].func = Task_LinkupFailed;
return TRUE;
}
return FALSE;
}
static bool32 CheckLinkCanceled(u8 taskId)
{
if (IsLinkConnectionEstablished())
SetSuppressLinkErrorMessage(TRUE);
if (JOY_NEW(B_BUTTON))
{
gLinkType = 0;
gTasks[taskId].func = Task_LinkupFailed;
return TRUE;
}
return FALSE;
}
static bool32 CheckSioErrored(u8 taskId)
{
if (GetSioMultiSI() == TRUE)
{
gTasks[taskId].func = Task_LinkupConnectionError;
return TRUE;
}
return FALSE;
}
// Unused
static void Task_DelayedBlockRequest(u8 taskId)
{
gTasks[taskId].data[0]++;
if (gTasks[taskId].data[0] == 10)
{
SendBlockRequest(BLOCK_REQ_SIZE_100);
DestroyTask(taskId);
}
}
static void Task_LinkupStart(u8 taskId)
{
s16 *data = gTasks[taskId].data;
if (data[0] == 0)
{
OpenLinkTimed();
ResetLinkPlayerCount();
ResetLinkPlayers();
tWindowId = AddWindow(&sWindowTemplate_LinkPlayerCount);
}
else if (data[0] > 9)
{
gTasks[taskId].func = Task_LinkupAwaitConnection;
}
data[0]++;
}
static void Task_LinkupAwaitConnection(u8 taskId)
{
u8 playerCount = GetLinkPlayerCount_2();
if (CheckLinkCanceledBeforeConnection(taskId) == TRUE
|| CheckLinkCanceled(taskId) == TRUE
|| playerCount < 2)
return;
SetSuppressLinkErrorMessage(TRUE);
gTasks[taskId].data[3] = 0;
if (IsLinkMaster() == TRUE)
{
PlaySE(SE_PIN);
ShowFieldAutoScrollMessage(CableClub_Text_WhenAllPlayersReadyAConfirmBCancel);
gTasks[taskId].func = Task_LinkupConfirmWhenReady;
}
else
{
PlaySE(SE_BOO);
ShowFieldAutoScrollMessage(CableClub_Text_AwaitingLinkupBCancel);
gTasks[taskId].func = Task_LinkupExchangeDataWithLeader;
}
}
static void Task_LinkupConfirmWhenReady(u8 taskId)
{
if (CheckLinkCanceledBeforeConnection(taskId) == TRUE
|| CheckSioErrored(taskId) == TRUE
|| CheckLinkErrored(taskId) == TRUE)
return;
if (GetFieldMessageBoxType() == FIELD_MESSAGE_BOX_HIDDEN)
{
gTasks[taskId].tNumPlayers = 0;
gTasks[taskId].func = Task_LinkupAwaitConfirmation;
}
}
static void Task_LinkupAwaitConfirmation(u8 taskId)
{
s16 *data = gTasks[taskId].data;
s32 linkPlayerCount = GetLinkPlayerCount_2();
if (CheckLinkCanceledBeforeConnection(taskId) == TRUE
|| CheckSioErrored(taskId) == TRUE
|| CheckLinkErrored(taskId) == TRUE)
return;
UpdateLinkPlayerCountDisplay(taskId, linkPlayerCount);
if (JOY_NEW(A_BUTTON) && linkPlayerCount >= tMinPlayers)
{
SaveLinkPlayers(linkPlayerCount);
ClearLinkPlayerCountWindow(tWindowId);
ConvertIntToDecimalStringN(gStringVar1, linkPlayerCount, STR_CONV_MODE_LEFT_ALIGN, 1);
ShowFieldAutoScrollMessage(CableClub_Text_StartLinkWithXPlayersAConfirmBCancel);
gTasks[taskId].func = Task_LinkupTryConfirmation;
}
}
static void Task_LinkupTryConfirmation(u8 taskId)
{
if (CheckLinkCanceledBeforeConnection(taskId) == TRUE
|| CheckSioErrored(taskId) == TRUE
|| CheckLinkErrored(taskId) == TRUE)
return;
if (GetFieldMessageBoxType() == FIELD_MESSAGE_BOX_HIDDEN)
{
if (GetSavedPlayerCount() != GetLinkPlayerCount_2())
{
ShowFieldAutoScrollMessage(CableClub_Text_WhenAllPlayersReadyAConfirmBCancel);
gTasks[taskId].func = Task_LinkupConfirmWhenReady;
}
else if (JOY_HELD(B_BUTTON))
{
ShowFieldAutoScrollMessage(CableClub_Text_WhenAllPlayersReadyAConfirmBCancel);
gTasks[taskId].func = Task_LinkupConfirmWhenReady;
}
else if (JOY_HELD(A_BUTTON))
{
PlaySE(SE_SELECT);
CheckShouldAdvanceLinkState();
gTasks[taskId].func = Task_LinkupConfirm;
}
}
}
static void Task_LinkupConfirm(u8 taskId)
{
u8 minPlayers = gTasks[taskId].tMinPlayers;
u8 maxPlayers = gTasks[taskId].tMaxPlayers;
if (CheckLinkErrored(taskId) == TRUE
|| TryLinkTimeout(taskId) == TRUE)
return;
if (GetLinkPlayerCount_2() != GetSavedPlayerCount())
{
gTasks[taskId].func = Task_LinkupConnectionError;
}
else
{
u16 *result = &gSpecialVar_Result;
*result = ExchangeDataAndGetLinkupStatus(minPlayers, maxPlayers);
if (*result)
gTasks[taskId].func = Task_LinkupCheckStatusAfterConfirm;
}
}
static void Task_LinkupExchangeDataWithLeader(u8 taskId)
{
u8 minPlayers = gTasks[taskId].tMinPlayers;
u8 maxPlayers = gTasks[taskId].tMaxPlayers;
u16 *result;
if (CheckLinkCanceledBeforeConnection(taskId) == TRUE
|| CheckLinkErrored(taskId) == TRUE)
return;
result = &gSpecialVar_Result;
*result = ExchangeDataAndGetLinkupStatus(minPlayers, maxPlayers);
if (*result == LINKUP_ONGOING)
return;
if (*result == LINKUP_DIFF_SELECTIONS
|| *result == LINKUP_WRONG_NUM_PLAYERS)
{
SetCloseLinkCallback();
HideFieldMessageBox();
gTasks[taskId].func = Task_StopLinkup;
}
else if (*result == LINKUP_PLAYER_NOT_READY
|| *result == LINKUP_PARTNER_NOT_READY)
{
CloseLink();
HideFieldMessageBox();
gTasks[taskId].func = Task_StopLinkup;
}
else
{
gFieldLinkPlayerCount = GetLinkPlayerCount_2();
gLocalLinkPlayerId = GetMultiplayerId();
SaveLinkPlayers(gFieldLinkPlayerCount);
TrainerCard_GenerateCardForLinkPlayer((void *)gBlockSendBuffer);
gTasks[taskId].func = Task_LinkupAwaitTrainerCardData;
}
}
static bool32 AnyConnectedPartnersPlayingRS(void)
{
int i;
u16 version;
for (i = 0; i < GetLinkPlayerCount(); i++)
{
version = gLinkPlayers[i].version & 0xFF;
if (version == VERSION_RUBY || version == VERSION_SAPPHIRE)
return TRUE;
}
return FALSE;
}
static void Task_LinkupCheckStatusAfterConfirm(u8 taskId)
{
if (CheckLinkErrored(taskId) == TRUE)
return;
if (gSpecialVar_Result == LINKUP_WRONG_NUM_PLAYERS)
{
if (AnyConnectedPartnersPlayingRS() == TRUE)
CloseLink();
else
SetCloseLinkCallback();
HideFieldMessageBox();
gTasks[taskId].func = Task_StopLinkup;
}
else if (gSpecialVar_Result == LINKUP_DIFF_SELECTIONS)
{
SetCloseLinkCallback();
HideFieldMessageBox();
gTasks[taskId].func = Task_StopLinkup;
}
else if (gSpecialVar_Result == LINKUP_PLAYER_NOT_READY
|| gSpecialVar_Result == LINKUP_PARTNER_NOT_READY)
{
CloseLink();
HideFieldMessageBox();
gTasks[taskId].func = Task_StopLinkup;
}
else
{
gFieldLinkPlayerCount = GetLinkPlayerCount_2();
gLocalLinkPlayerId = GetMultiplayerId();
SaveLinkPlayers(gFieldLinkPlayerCount);
TrainerCard_GenerateCardForLinkPlayer((void *)gBlockSendBuffer);
gTasks[taskId].func = Task_LinkupAwaitTrainerCardData;
SendBlockRequest(BLOCK_REQ_SIZE_100);
}
}
static void Task_LinkupAwaitTrainerCardData(u8 taskId)
{
u8 i;
u16 version;
u8 * dest;
if (CheckLinkErrored(taskId) == TRUE)
return;
if (GetBlockReceivedStatus() != GetSavedLinkPlayerCountAsBitFlags())
return;
for (i = 0; i < GetLinkPlayerCount(); i++)
{
version = gLinkPlayers[i].version & 0xFF;
if (version != VERSION_FIRE_RED && version != VERSION_LEAF_GREEN)
{
const struct TrainerCardRSE * src = (const struct TrainerCardRSE *)gBlockRecvBuffer[i];
gTrainerCards[i].rse = *src;
gTrainerCards[i].version = gLinkPlayers[i].version;
}
else
{
const struct TrainerCard * src = (const struct TrainerCard *)gBlockRecvBuffer[i];
gTrainerCards[i] = *src;
}
}
SetSuppressLinkErrorMessage(FALSE);
ResetBlockReceivedFlags();
HideFieldMessageBox();
if (gSpecialVar_Result == LINKUP_SUCCESS)
{
// Dumb trick required to match
if (gLinkType == LINKTYPE_BERRY_BLENDER_SETUP)
*UnusedVarNeededToMatch += 0;
ClearLinkPlayerCountWindow(gTasks[taskId].tWindowId);
ScriptContext_Enable();
DestroyTask(taskId);
}
else
{
SetCloseLinkCallback();
gTasks[taskId].func = Task_StopLinkup;
}
}
static void Task_StopLinkup(u8 taskId)
{
if (!gReceivedRemoteLinkPlayers)
{
ClearLinkPlayerCountWindow(gTasks[taskId].tWindowId);
ScriptContext_Enable();
RemoveWindow(gTasks[taskId].tWindowId);
DestroyTask(taskId);
}
}
static void Task_LinkupFailed(u8 taskId)
{
gSpecialVar_Result = LINKUP_FAILED;
ClearLinkPlayerCountWindow(gTasks[taskId].tWindowId);
HideFieldMessageBox();
ScriptContext_Enable();
DestroyTask(taskId);
}
static void Task_LinkupConnectionError(u8 taskId)
{
gSpecialVar_Result = LINKUP_CONNECTION_ERROR;
ClearLinkPlayerCountWindow(gTasks[taskId].tWindowId);
HideFieldMessageBox();
ScriptContext_Enable();
DestroyTask(taskId);
}
static bool8 TryLinkTimeout(u8 taskId)
{
if (++gTasks[taskId].tTimer > 600)
{
gTasks[taskId].func = Task_LinkupConnectionError;
return TRUE;
}
return FALSE;
}
void TryBattleLinkup(void)
{
u8 minPlayers = 2;
u8 maxPlayers = 2;
switch (gSpecialVar_0x8004)
{
case USING_SINGLE_BATTLE:
minPlayers = 2;
maxPlayers = 2;
gLinkType = LINKTYPE_SINGLE_BATTLE;
break;
case USING_DOUBLE_BATTLE:
minPlayers = 2;
maxPlayers = 2;
gLinkType = LINKTYPE_DOUBLE_BATTLE;
break;
case USING_MULTI_BATTLE:
minPlayers = 4;
maxPlayers = 4;
gLinkType = LINKTYPE_MULTI_BATTLE;
break;
}
CreateLinkupTask(minPlayers, maxPlayers);
}
#undef tMinPlayers
#undef tMaxPlayers
#undef tNumPlayers
#undef tTimer
#undef tWindowId
void TryTradeLinkup(void)
{
gLinkType = LINKTYPE_TRADE_SETUP;
gBattleTypeFlags = 0;
CreateLinkupTask(2, 2);
}
void TryRecordMixLinkup(void)
{
gSpecialVar_Result = LINKUP_ONGOING;
gLinkType = LINKTYPE_RECORD_MIX_BEFORE;
gBattleTypeFlags = 0;
CreateLinkupTask(2, 4);
}
void TryContestLinkup(void)
{
gLinkType = LINKTYPE_CONTEST_GMODE;
gBattleTypeFlags = 0;
CreateLinkupTask(4, 4);
}
u8 CreateTask_ReestablishCableClubLink(void)
{
if (FuncIsActiveTask(Task_ReestablishLink))
return TASK_NONE;
switch (gSpecialVar_0x8004)
{
case USING_SINGLE_BATTLE:
gLinkType = LINKTYPE_SINGLE_BATTLE;
break;
case USING_DOUBLE_BATTLE:
gLinkType = LINKTYPE_DOUBLE_BATTLE;
break;
case USING_MULTI_BATTLE:
gLinkType = LINKTYPE_MULTI_BATTLE;
break;
case USING_TRADE_CENTER:
gLinkType = LINKTYPE_TRADE;
break;
case USING_RECORD_CORNER:
gLinkType = LINKTYPE_RECORD_MIX_AFTER;
break;
}
return CreateTask(Task_ReestablishLink, 80);
}
static void Task_ReestablishLink(u8 taskId)
{
s16 *data = gTasks[taskId].data;
if (data[0] == 0)
{
OpenLink();
ResetLinkPlayers();
CreateTask(Task_WaitForLinkPlayerConnection, 80);
}
else if (data[0] > 9)
{
gTasks[taskId].func = Task_ReestablishLinkAwaitConnection;
}
data[0]++;
}
static void Task_ReestablishLinkAwaitConnection(u8 taskId)
{
if (GetLinkPlayerCount_2() >= 2)
{
if (IsLinkMaster() == TRUE)
gTasks[taskId].func = Task_ReestablishLinkLeader;
else
gTasks[taskId].func = Task_ReestablishLinkAwaitConfirmation;
}
}
static void Task_ReestablishLinkLeader(u8 taskId)
{
if (GetSavedPlayerCount() == GetLinkPlayerCount_2())
{
CheckShouldAdvanceLinkState();
gTasks[taskId].func = Task_ReestablishLinkAwaitConfirmation;
}
}
static void Task_ReestablishLinkAwaitConfirmation(u8 taskId)
{
if (gReceivedRemoteLinkPlayers == TRUE && IsLinkPlayerDataExchangeComplete() == TRUE)
{
CheckLinkPlayersMatchSaved();
StartSendingKeysToLink();
DestroyTask(taskId);
}
}
// Unused
void CableClub_AskSaveTheGame(void)
{
Field_AskSaveTheGame();
}
#define tTimer data[1]
static void Task_StartWiredCableClubBattle(u8 taskId)
{
struct Task *task = &gTasks[taskId];
switch (task->tState)
{
case 0:
FadeScreen(FADE_TO_BLACK, 0);
gLinkType = LINKTYPE_BATTLE;
ClearLinkCallback_2();
task->tState++;
break;
case 1:
if (!gPaletteFade.active)
task->tState++;
break;
case 2:
if (++task->tTimer > 20)
task->tState++;
break;
case 3:
SetCloseLinkCallback();
task->tState++;
break;
case 4:
if (!gReceivedRemoteLinkPlayers)
task->tState++;
break;
case 5:
if (gLinkPlayers[0].trainerId & 1)
PlayMapChosenOrBattleBGM(MUS_RS_VS_GYM_LEADER);
else
PlayMapChosenOrBattleBGM(MUS_RS_VS_TRAINER);
switch (gSpecialVar_0x8004)
{
case USING_SINGLE_BATTLE:
gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_LINK;
break;
case USING_DOUBLE_BATTLE:
gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_LINK | BATTLE_TYPE_DOUBLE;
break;
case USING_MULTI_BATTLE:
ReducePlayerPartyToThree();
gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_LINK | BATTLE_TYPE_DOUBLE | BATTLE_TYPE_MULTI;
break;
}
CleanupOverworldWindowsAndTilemaps();
gTrainerBattleOpponent_A = TRAINER_LINK_OPPONENT;
SetMainCallback2(CB2_InitBattle);
gMain.savedCallback = CB2_ReturnFromCableClubBattle;
DestroyTask(taskId);
break;
}
}
static void Task_StartWirelessCableClubBattle(u8 taskId)
{
s16 *data = gTasks[taskId].data;
int i;
switch (tState)
{
case 0:
FadeScreen(FADE_TO_BLACK, 0);
gLinkType = LINKTYPE_BATTLE;
ClearLinkCallback_2();
tState = 1;
break;
case 1:
if (!gPaletteFade.active)
tState = 2;
break;
case 2:
SendBlock(0, &gLocalLinkPlayer, sizeof(gLocalLinkPlayer));
tState = 3;
break;
case 3:
if (GetBlockReceivedStatus() == GetLinkPlayerCountAsBitFlags())
{
for (i = 0; i < GetLinkPlayerCount(); i++)
{
gLinkPlayers[i] = *(struct LinkPlayer *)gBlockRecvBuffer[i];
ConvertLinkPlayerName(&gLinkPlayers[i]);
ResetBlockReceivedFlag(i);
}
tState = 4;
}
break;
case 4:
if (++tTimer > 20)
tState = 5;
break;
case 5:
SetLinkStandbyCallback();
tState = 6;
break;
case 6:
if (IsLinkTaskFinished())
tState = 7;
break;
case 7:
if (gLinkPlayers[0].trainerId & 1)
PlayMapChosenOrBattleBGM(MUS_RS_VS_GYM_LEADER);
else
PlayMapChosenOrBattleBGM(MUS_RS_VS_TRAINER);
gLinkPlayers[0].linkType = LINKTYPE_BATTLE;
switch (gSpecialVar_0x8004)
{
case USING_SINGLE_BATTLE:
gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_LINK;
break;
case USING_DOUBLE_BATTLE:
gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_LINK | BATTLE_TYPE_DOUBLE;
break;
case USING_MULTI_BATTLE:
ReducePlayerPartyToThree();
gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_LINK | BATTLE_TYPE_DOUBLE | BATTLE_TYPE_MULTI;
break;
}
CleanupOverworldWindowsAndTilemaps();
gTrainerBattleOpponent_A = TRAINER_LINK_OPPONENT;
SetMainCallback2(CB2_InitBattle);
gMain.savedCallback = CB2_ReturnFromCableClubBattle;
DestroyTask(taskId);
break;
}
}
#undef tTimer
static void CB2_ReturnFromUnionRoomBattle(void)
{
switch (gMain.state)
{
case 0:
SetCloseLinkCallback();
gMain.state++;
break;
case 1:
if (IsLinkTaskFinished())
SetMainCallback2(CB2_ReturnToField);
break;
}
}
void CB2_ReturnFromCableClubBattle(void)
{
gBattleTypeFlags &= (u16)~BATTLE_TYPE_LINK_IN_BATTLE;
Overworld_ResetMapMusic();
LoadPlayerParty();
SavePlayerBag();
Special_UpdateTrainerFansAfterLinkBattle();
if (gSpecialVar_0x8004 != USING_MULTI_BATTLE)
{
UpdatePlayerLinkBattleRecords(gLocalLinkPlayerId ^ 1);
if (gWirelessCommType != 0)
{
switch (gBattleOutcome)
{
case B_OUTCOME_WON:
MysteryGift_TryIncrementStat(CARD_STAT_BATTLES_WON, gLinkPlayers[GetMultiplayerId() ^ 1].trainerId);
break;
case B_OUTCOME_LOST:
MysteryGift_TryIncrementStat(CARD_STAT_BATTLES_LOST, gLinkPlayers[GetMultiplayerId() ^ 1].trainerId);
break;
}
}
}
if (InUnionRoom() == TRUE)
gMain.savedCallback = CB2_ReturnFromUnionRoomBattle;
else
gMain.savedCallback = CB2_ReturnToFieldFromMultiplayer;
SetMainCallback2(CB2_SetUpSaveAfterLinkBattle);
}
void CleanupLinkRoomState(void)
{
if (gSpecialVar_0x8004 == USING_SINGLE_BATTLE
|| gSpecialVar_0x8004 == USING_DOUBLE_BATTLE
|| gSpecialVar_0x8004 == USING_MULTI_BATTLE)
{
LoadPlayerParty();
SavePlayerBag();
}
SetWarpDestinationToDynamicWarp(WARP_ID_DYNAMIC);
}
void ExitLinkRoom(void)
{
QueueExitLinkRoomKey();
}
// Note: gSpecialVar_0x8005 contains the id of the seat the player entered
static void Task_EnterCableClubSeat(u8 taskId)
{
struct Task *task = &gTasks[taskId];
switch (task->tState)
{
case 0:
ShowFieldMessage(CableClub_Text_PleaseWaitBCancel);
task->tState = 1;
break;
case 1:
if (IsFieldMessageBoxHidden())
{
SetInCableClubSeat();
SetLocalLinkPlayerId(gSpecialVar_0x8005);
task->tState = 2;
}
break;
case 2:
switch (GetCableClubPartnersReady())
{
case CABLE_SEAT_WAITING:
break;
case CABLE_SEAT_SUCCESS:
// Partners linked and ready, switch to relevant link function
HideFieldMessageBox();
task->tState = 0;
SetStartedCableClubActivity();
SwitchTaskToFollowupFunc(taskId);
break;
case CABLE_SEAT_FAILED:
task->tState = 3;
break;
}
break;
case 3:
// Exit, failure
SetLinkWaitingForScript();
EraseFieldMessageBox(TRUE);
DestroyTask(taskId);
ScriptContext_Enable();
break;
}
}
static void CreateTask_EnterCableClubSeat(TaskFunc followUpFunc)
{
u8 taskId = CreateTask(Task_EnterCableClubSeat, 80);
SetTaskFuncWithFollowupFunc(taskId, Task_EnterCableClubSeat, followUpFunc);
ScriptContext_Stop();
}
static void Task_StartWiredTrade(u8 taskId)
{
struct Task *task = &gTasks[taskId];
switch (task->tState)
{
case 0:
LockPlayerFieldControls();
FadeScreen(FADE_TO_BLACK, 0);
ClearLinkCallback_2();
task->tState++;
break;
case 1:
if (!gPaletteFade.active)
task->tState++;
break;
case 2:
gSelectedTradeMonPositions[TRADE_PLAYER] = 0;
gSelectedTradeMonPositions[TRADE_PARTNER] = 0;
m4aMPlayAllStop();
SetCloseLinkCallback();
task->tState++;
break;
case 3:
if (!gReceivedRemoteLinkPlayers)
{
SetMainCallback2(CB2_StartCreateTradeMenu);
DestroyTask(taskId);
}
break;
}
}
static void Task_StartWirelessTrade(u8 taskId)
{
s16 *data = gTasks[taskId].data;
switch (tState)
{
case 0:
LockPlayerFieldControls();
FadeScreen(FADE_TO_BLACK, 0);
ClearLinkRfuCallback();
tState++;
break;
case 1:
if (!gPaletteFade.active)
tState++;
break;
case 2:
gSelectedTradeMonPositions[TRADE_PLAYER] = 0;
gSelectedTradeMonPositions[TRADE_PARTNER] = 0;
m4aMPlayAllStop();
SetLinkStandbyCallback();
tState++;
break;
case 3:
if (IsLinkTaskFinished())
{
CreateTask_CreateTradeMenu();
DestroyTask(taskId);
}
break;
}
}
void EnterTradeSeat(void)
{
if (gWirelessCommType)
CreateTask_EnterCableClubSeat(Task_StartWirelessTrade);
else
CreateTask_EnterCableClubSeat(Task_StartWiredTrade);
}
static void CreateTask_StartWiredTrade(void)
{
CreateTask(Task_StartWiredTrade, 80);
}
void StartWiredCableClubTrade(void)
{
CreateTask_StartWiredTrade();
ScriptContext_Stop();
}
void EnterColosseumPlayerSpot(void)
{
gLinkType = LINKTYPE_BATTLE;
if (gWirelessCommType)
CreateTask_EnterCableClubSeat(Task_StartWirelessCableClubBattle);
else
CreateTask_EnterCableClubSeat(Task_StartWiredCableClubBattle);
}
// Unused
static void CreateTask_EnterCableClubSeatNoFollowup(void)
{
CreateTask(Task_EnterCableClubSeat, 80);
ScriptContext_Stop();
}
void Script_ShowLinkTrainerCard(void)
{
ShowTrainerCardInLink(gSpecialVar_0x8006, CB2_ReturnToFieldContinueScriptPlayMapMusic);
}
bool32 GetSeeingLinkPlayerCardMsg(u8 linkPlayerIndex)
{
u8 numStars;
gSpecialVar_0x8006 = linkPlayerIndex;
StringCopy(gStringVar1, gLinkPlayers[linkPlayerIndex].name);
numStars = GetTrainerCardStars(linkPlayerIndex);
if (numStars == 0)
return FALSE;
StringCopy(gStringVar2, sTrainerCardColorNames[numStars - 1]);
return TRUE;
}
#define tTimer data[0]
void Task_WaitForLinkPlayerConnection(u8 taskId)
{
struct Task *task = &gTasks[taskId];
if (++task->tTimer > 300)
{
CloseLink();
SetMainCallback2(CB2_LinkError);
DestroyTask(taskId);
}
if (gReceivedRemoteLinkPlayers)
DestroyTask(taskId);
}
#undef tTimer
static void Task_WaitExitToScript(u8 taskId)
{
if (!gReceivedRemoteLinkPlayers)
{
ScriptContext_Enable();
DestroyTask(taskId);
}
}
// Unused
static void ExitLinkToScript(u8 taskId)
{
SetCloseLinkCallback();
gTasks[taskId].func = Task_WaitExitToScript;
}