#ifndef GUARD_LINK_H #define GUARD_LINK_H #define MAX_LINK_PLAYERS 4 #define MAX_RFU_PLAYERS 5 #define CMD_LENGTH 8 #define QUEUE_CAPACITY 50 #define OVERWORLD_RECV_QUEUE_MAX 3 #define BLOCK_BUFFER_SIZE 0x100 #define LINK_SLAVE 0 #define LINK_MASTER 8 #define LINK_STAT_LOCAL_ID 0x00000003 #define LINK_STAT_PLAYER_COUNT 0x0000001C #define LINK_STAT_PLAYER_COUNT_SHIFT 2 #define LINK_STAT_MASTER 0x00000020 #define LINK_STAT_MASTER_SHIFT 5 #define LINK_STAT_CONN_ESTABLISHED 0x00000040 #define LINK_STAT_CONN_ESTABLISHED_SHIFT 6 #define LINK_STAT_RECEIVED_NOTHING 0x00000100 #define LINK_STAT_RECEIVED_NOTHING_SHIFT 8 #define LINK_STAT_UNK_FLAG_9 0x00000200 #define LINK_STAT_UNK_FLAG_9_SHIFT 9 #define LINK_STAT_ERRORS 0x0007F000 #define LINK_STAT_ERRORS_SHIFT 12 #define LINK_STAT_ERROR_HARDWARE 0x00001000 #define LINK_STAT_ERROR_HARDWARE_SHIFT 12 #define LINK_STAT_ERROR_CHECKSUM 0x00002000 #define LINK_STAT_ERROR_CHECKSUM_SHIFT 13 #define LINK_STAT_ERROR_QUEUE_FULL 0x00004000 #define LINK_STAT_ERROR_QUEUE_FULL_SHIFT 14 #define LINK_STAT_ERROR_LAG_MASTER 0x00010000 #define LINK_STAT_ERROR_LAG_MASTER_SHIFT 16 #define LINK_STAT_ERROR_INVALID_ID 0x00020000 #define LINK_STAT_ERROR_INVALID_ID_SHIFT 17 #define LINK_STAT_ERROR_LAG_SLAVE 0x00040000 #define LINK_STAT_ERROR_LAG_SLAVE_SHIFT 18 #define EXTRACT_PLAYER_COUNT(status) \ (((status) & LINK_STAT_PLAYER_COUNT) >> LINK_STAT_PLAYER_COUNT_SHIFT) #define EXTRACT_MASTER(status) \ (((status) >> LINK_STAT_MASTER_SHIFT) & 1) #define EXTRACT_CONN_ESTABLISHED(status) \ (((status) >> LINK_STAT_CONN_ESTABLISHED_SHIFT) & 1) #define EXTRACT_RECEIVED_NOTHING(status) \ (((status) >> LINK_STAT_RECEIVED_NOTHING_SHIFT) & 1) #define EXTRACT_LINK_ERRORS(status) \ (((status) & LINK_STAT_ERRORS) >> LINK_STAT_ERRORS_SHIFT) #define LINKCMD_BLENDER_STOP 0x1111 #define LINKCMD_SEND_LINK_TYPE 0x2222 #define LINKCMD_BLENDER_SCORE_MISS 0x2345 #define LINKCMD_READY_EXIT_STANDBY 0x2FFE #define LINKCMD_SEND_PACKET 0x2FFF #define LINKCMD_BLENDER_SEND_KEYS 0x4444 #define LINKCMD_BLENDER_SCORE_BEST 0x4523 #define LINKCMD_BLENDER_SCORE_GOOD 0x5432 #define LINKCMD_DUMMY_1 0x5555 #define LINKCMD_DUMMY_2 0x5566 #define LINKCMD_READY_CLOSE_LINK 0x5FFF #define LINKCMD_SEND_EMPTY 0x6666 #define LINKCMD_SEND_0xEE 0x7777 #define LINKCMD_BLENDER_PLAY_AGAIN 0x7779 #define LINKCMD_COUNTDOWN 0x7FFF #define LINKCMD_CONT_BLOCK 0x8888 #define LINKCMD_BLENDER_NO_BERRIES 0x9999 #define LINKCMD_BLENDER_NO_PBLOCK_SPACE 0xAAAA #define LINKCMD_SEND_ITEM 0xAAAB #define LINKCMD_READY_TO_TRADE 0xAABB #define LINKCMD_READY_FINISH_TRADE 0xABCD #define LINKCMD_INIT_BLOCK 0xBBBB #define LINKCMD_READY_CANCEL_TRADE 0xBBCC #define LINKCMD_SEND_HELD_KEYS 0xCAFE #define LINKCMD_SEND_BLOCK_REQ 0xCCCC #define LINKCMD_START_TRADE 0xCCDD #define LINKCMD_CONFIRM_FINISH_TRADE 0xDCBA #define LINKCMD_SET_MONS_TO_TRADE 0xDDDD #define LINKCMD_PLAYER_CANCEL_TRADE 0xDDEE #define LINKCMD_REQUEST_CANCEL 0xEEAA #define LINKCMD_BOTH_CANCEL_TRADE 0xEEBB #define LINKCMD_PARTNER_CANCEL_TRADE 0xEECC #define LINKCMD_NONE 0xEFFF #define LINKTYPE_TRADE 0x1111 #define LINKTYPE_TRADE_CONNECTING 0x1122 #define LINKTYPE_TRADE_SETUP 0x1133 #define LINKTYPE_TRADE_DISCONNECTED 0x1144 #define LINKTYPE_BATTLE 0x2211 #define LINKTYPE_UNUSED_BATTLE 0x2222 // Unused, inferred from gap #define LINKTYPE_SINGLE_BATTLE 0x2233 #define LINKTYPE_DOUBLE_BATTLE 0x2244 #define LINKTYPE_MULTI_BATTLE 0x2255 #define LINKTYPE_BATTLE_TOWER_50 0x2266 #define LINKTYPE_BATTLE_TOWER_OPEN 0x2277 #define LINKTYPE_BATTLE_TOWER 0x2288 #define LINKTYPE_RECORD_MIX_BEFORE 0x3311 #define LINKTYPE_RECORD_MIX_AFTER 0x3322 #define LINKTYPE_BERRY_BLENDER_SETUP 0x4411 #define LINKTYPE_BERRY_BLENDER 0x4422 #define LINKTYPE_MYSTERY_EVENT 0x5501 #define LINKTYPE_UNUSED_EREADER 0x5502 // Unused, inferred from gap #define LINKTYPE_EREADER 0x5503 #define LINKTYPE_CONTEST_GMODE 0x6601 #define LINKTYPE_CONTEST_EMODE 0x6602 enum { BLOCK_REQ_SIZE_NONE, // Identical to 200 BLOCK_REQ_SIZE_200, BLOCK_REQ_SIZE_100, BLOCK_REQ_SIZE_220, BLOCK_REQ_SIZE_40, }; struct LinkStatus { u32 localId:2; u32 playerCount:3; u32 master:1; u32 connEstablished:1; u32 unused_7:1; u32 receivedNothing:1; u32 unused_9:7; u32 errors:7; }; #define MASTER_HANDSHAKE 0x8FFF #define SLAVE_HANDSHAKE 0xB9A0 #define EREADER_HANDSHAKE 0xCCD0 #define SIO_MULTI_CNT ((struct SioMultiCnt *)REG_ADDR_SIOCNT) enum { LINK_STATE_START0, LINK_STATE_START1, LINK_STATE_HANDSHAKE, LINK_STATE_INIT_TIMER, LINK_STATE_CONN_ESTABLISHED, }; enum { EXCHANGE_NOT_STARTED, EXCHANGE_COMPLETE, EXCHANGE_TIMED_OUT, EXCHANGE_DIFF_SELECTIONS, EXCHANGE_PLAYER_NOT_READY, EXCHANGE_PARTNER_NOT_READY, EXCHANGE_WRONG_NUM_PLAYERS, EXCHANGE_STAT_7 }; enum { QUEUE_FULL_NONE, QUEUE_FULL_SEND, QUEUE_FULL_RECV, }; enum { LAG_NONE, LAG_MASTER, LAG_SLAVE, }; struct LinkPlayer { /* 0x00 */ u16 version; /* 0x02 */ u16 lp_field_2; /* 0x04 */ u32 trainerId; /* 0x08 */ u8 name[PLAYER_NAME_LENGTH + 1]; /* 0x10 */ u8 progressFlags; // (& 0x0F) is hasNationalDex, (& 0xF0) is hasClearedGame /* 0x11 */ u8 neverRead; /* 0x12 */ u8 progressFlagsCopy; /* 0x13 */ u8 gender; /* 0x14 */ u32 linkType; /* 0x18 */ u16 id; // battler id in battles /* 0x1A */ u16 language; }; struct LinkPlayerBlock { char magic1[16]; struct LinkPlayer linkPlayer; char magic2[16]; }; // circular queues struct SendQueue { /* 0x000 */ u16 data[CMD_LENGTH][QUEUE_CAPACITY]; /* 0x320 */ u8 pos; /* 0x321 */ u8 count; }; struct RecvQueue { u16 data[MAX_LINK_PLAYERS][CMD_LENGTH][QUEUE_CAPACITY]; u8 pos; u8 count; }; struct Link { /* 0x000 */ u8 isMaster; // 0: slave, 8: master /* 0x001 */ u8 state; /* 0x002 */ u8 localId; // local multi-player ID /* 0x003 */ u8 playerCount; /* 0x004 */ u16 handshakeBuffer[MAX_LINK_PLAYERS]; /* 0x00c */ bool8 receivedNothing; /* 0x00d */ s8 serialIntrCounter; /* 0x00e */ bool8 handshakeAsMaster; /* 0x00f */ u8 link_field_F; // error conditions /* 0x010 */ bool8 hardwareError; // hardware reported an error /* 0x011 */ bool8 badChecksum; // checksum didn't match between devices /* 0x012 */ u8 queueFull; // send or recv queue out of space /* 0x013 */ u8 lag; // connection is lagging /* 0x014 */ u16 checksum; /* 0x016 */ u8 sendCmdIndex; /* 0x017 */ u8 recvCmdIndex; /* 0x018 */ struct SendQueue sendQueue; /* 0x33c */ struct RecvQueue recvQueue; }; struct BlockRequest { void * address; u32 size; }; extern struct Link gLink; extern u16 gRecvCmds[MAX_RFU_PLAYERS][CMD_LENGTH]; extern u8 gBlockSendBuffer[BLOCK_BUFFER_SIZE]; extern u16 gLinkType; extern u32 gLinkStatus; extern u16 gBlockRecvBuffer[MAX_RFU_PLAYERS][BLOCK_BUFFER_SIZE / 2]; extern u16 gSendCmd[CMD_LENGTH]; extern struct LinkPlayer gLinkPlayers[MAX_RFU_PLAYERS]; extern bool8 gReceivedRemoteLinkPlayers; extern u32 gBerryBlenderKeySendAttempts; extern bool8 gLinkVSyncDisabled; extern u32 gLinkStatus; bool8 IsWirelessAdapterConnected(void); void Task_DestroySelf(u8 taskId); void OpenLink(void); void CloseLink(void); u16 LinkMain2(const u16 *); void ClearLinkCallback(void); void ClearLinkCallback_2(void); u8 GetLinkPlayerCount(void); void OpenLinkTimed(void); u8 GetLinkPlayerDataExchangeStatusTimed(int lower, int upper); bool8 IsLinkPlayerDataExchangeComplete(void); u32 GetLinkPlayerTrainerId(u8); void ResetLinkPlayers(void); u8 GetMultiplayerId(void); u8 BitmaskAllOtherLinkPlayers(void); bool8 SendBlock(u8, const void *, u16); u8 GetBlockReceivedStatus(void); void ResetBlockReceivedFlags(void); void ResetBlockReceivedFlag(u8); u8 GetLinkPlayerCount_2(void); bool8 IsLinkMaster(void); void CB2_LinkError(void); bool8 GetSioMultiSI(void); bool8 IsLinkConnectionEstablished(void); bool8 HasLinkErrorOccurred(void); void ResetSerial(void); u32 LinkMain1(u8 *shouldAdvanceLinkState, u16 *sendCmd, u16 (*recvCmds)[CMD_LENGTH]); void LinkVSync(void); void Timer3Intr(void); void SerialCB(void); bool32 InUnionRoom(void); void LoadWirelessStatusIndicatorSpriteGfx(void); bool8 IsLinkTaskFinished(void); void CreateWirelessStatusIndicatorSprite(u8, u8); void SetLinkStandbyCallback(void); void SetWirelessCommType1(void); void CheckShouldAdvanceLinkState(void); void SetCloseLinkCallback(void); bool8 HandleLinkConnection(void); void SetLinkDebugValues(u32 seed, u32 flags); void SetBerryBlenderLinkCallback(void); void SetSuppressLinkErrorMessage(bool8 flag); void ConvertLinkPlayerName(struct LinkPlayer *linkPlayer); void ClearSavedLinkPlayers(void); void SetLinkErrorBuffer(u32 status, u8 lastSendQueueCount, u8 lastRecvQueueCount, bool8 disconnected); void LocalLinkPlayerToBlock(void); void LinkPlayerFromBlock(u32 who); bool32 Link_AnyPartnersPlayingFRLG_JP(void); void ResetLinkPlayerCount(void); void SaveLinkPlayers(u8 a0); void SetWirelessCommType0(void); bool32 IsLinkRecvQueueAtOverworldMax(void); extern u16 gLinkPartnersHeldKeys[6]; extern u32 gLinkDebugSeed; extern struct LinkPlayerBlock gLocalLinkPlayerBlock; extern bool8 gLinkErrorOccurred; extern u32 gLinkDebugFlags; extern bool8 gRemoteLinkPlayersNotReceived[MAX_LINK_PLAYERS]; extern u8 gBlockReceivedStatus[MAX_LINK_PLAYERS]; extern u16 gLinkHeldKeys; extern u32 gLinkStatus; extern bool8 gReadyToExitStandby[MAX_LINK_PLAYERS]; extern bool8 gReadyToCloseLink[MAX_LINK_PLAYERS]; extern u16 gReadyCloseLinkType; extern u8 gSuppressLinkErrorMessage; extern u8 gWirelessCommType; extern bool8 gSavedLinkPlayerCount; extern u8 gSavedMultiplayerId; extern struct LinkTestBGInfo gLinkTestBGInfo; extern void (*gLinkCallback)(void); extern u8 gShouldAdvanceLinkState; extern u16 gLinkTestBlockChecksums[MAX_LINK_PLAYERS]; extern u8 gBlockRequestType; extern u8 gLastSendQueueCount; extern u8 gLastRecvQueueCount; extern u16 gLinkSavedIme; extern struct LinkPlayer gLocalLinkPlayer; bool32 Link_AnyPartnersPlayingRubyOrSapphire(void); bool32 LinkDummy_Return2(void); void SetLocalLinkPlayerId(u8); u8 GetSavedPlayerCount(void); bool8 SendBlockRequest(u8 type); u8 GetLinkPlayerCountAsBitFlags(void); u8 GetSavedLinkPlayerCountAsBitFlags(void); void SetCloseLinkCallbackHandleJP(void); void CheckLinkPlayersMatchSaved(void); void StartSendingKeysToLink(void); bool8 DoesLinkPlayerCountMatchSaved(void); void SetCloseLinkCallbackAndType(u16 type); bool32 IsSendingKeysToLink(void); u32 GetLinkRecvQueueLength(void); #endif // GUARD_LINK_H