Merge branch 'master' into doc-miscbattle

This commit is contained in:
GriffinR 2021-10-15 22:46:43 -04:00 committed by GitHub
commit e1900efe1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 2863 additions and 2829 deletions

View File

@ -1,9 +1,15 @@
#!/usr/bin/perl
use IPC::Cmd qw[ run ];
use Getopt::Long;
my $usage = "Usage: calcrom.pl file.map [--data]\n";
my $showData;
GetOptions("data" => \$showData) or die $usage;
(@ARGV == 1)
or die "ERROR: no map file specified.\n";
or die $usage;
open(my $file, $ARGV[0])
or die "ERROR: could not open file '$ARGV[0]'.\n";
@ -149,17 +155,13 @@ else
print "$undocumented symbols undocumented ($undocPct%)\n";
}
print "\n";
my $dataTotal = $srcdata + $data;
my $srcDataPct = sprintf("%.4f", 100 * $srcdata / $dataTotal);
my $dataPct = sprintf("%.4f", 100 * $data / $dataTotal);
if ($showData)
{
print "\n";
my $dataTotal = $srcdata + $data;
my $srcDataPct = sprintf("%.4f", 100 * $srcdata / $dataTotal);
my $dataPct = sprintf("%.4f", 100 * $data / $dataTotal);
if ($data == 0)
{
print "Data porting to C is 100% complete\n"
}
else
{
print "$dataTotal total bytes of data\n";
print "$srcdata bytes of data in src ($srcDataPct%)\n";
print "$data bytes of data in data ($dataPct%)\n";

View File

@ -1,2 +1,2 @@
gf_rfu_REQ_api
Rfu
gRfuAPIBuffer
gRfu

View File

@ -43,7 +43,7 @@ gSpecials::
def_special CloseLink
def_special ColosseumPlayerSpotTriggered
def_special PlayerEnteredTradeSeat
def_special nullsub_37
def_special Script_StartWiredTrade
def_special CableClubSaveGame
def_special TryBerryBlenderLinkup
def_special GetLinkPartnerNames

View File

@ -120,10 +120,10 @@ typedef struct InitializeParametersTag {
// rfu_REQ_configSystem argument
u8 maxMFrame; // Maximum number of times to re-transmit of RFU level
u8 MC_TimerCount; // MC_Timer count (x16.7ms)
u16 availSlot_flag; // Use RFU-API constant "AVAIL_SLOT1-4" to specify the maximum number of child devices (1 - 4) that can be connected to a parent device.
u16 availSlot_flag; // Use RFU-API constant "AVAIL_SLOT1-4" to specify the maximum number of child devices (1 - 4) that can be connected to a parent device.
// rfu_REQB_configGameData argument
u8 mboot_flag; // Multiplayer boot flag
u8 mboot_flag; // Multiplayer boot flag
u16 serialNo; // Game serial number
u8 *gameName; // Game name
u8 *userName; // User name
@ -132,8 +132,8 @@ typedef struct InitializeParametersTag {
u8 fastSearchParent_flag; // Flag indicating whether parent fast search operation to be performed by child.
// Link recovery settings
u8 linkRecovery_enable; // Determines whether or not to execute the link recovery process when a link cut occurs
u16 linkRecovery_period; // Time to spend on the link recovery process (x 16.7 ms) Note: Runs for unlimited time when specifying 0.
u8 linkRecovery_enable; // Determines whether or not to execute the link recovery process when a link cut occurs
u16 linkRecovery_period; // Time to spend on the link recovery process (x 16.7 ms) Note: Runs for unlimited time when specifying 0.
// Setting for NI-type data transmit/receive period
u16 NI_failCounter_limit; // Limit for failCounter during NI type data transmit/receive (x 16.7 ms) Note: Runs for unlimited time when specifying 0.
@ -142,44 +142,49 @@ typedef struct InitializeParametersTag {
// Timer that counts with the V-Blank cycle
typedef struct VblankTimerTag {
u8 active; // Timer ON/OFF (bits 0 - 3 indicate ON/OFF for each connected slot)
u16 count_max; // Maximum count value (x16.7ms)
u8 active; // Timer ON/OFF (bits 0 - 3 indicate ON/OFF for each connected slot)
u16 count_max; // Maximum count value (x16.7ms)
u16 count[RFU_CHILD_MAX]; // Current count value (x 16.7 ms) for each connected slot
}VBL_TIMER;
typedef struct linkManagerTag
{
/* 0x000 */ u8 acceptSlot_flag;
/* 0x001 */ u8 acceptCount;
/* 0x002 */ vu8 childClockSlave_flag;
/* 0x003 */ vu8 parentAck_flag;
/* 0x004 */ u8 state;
/* 0x005 */ u8 next_state;
/* 0x006 */ u8 parent_child;
/* 0x007 */ u8 pcswitch_flag;
/* 0x008 */ u8 RFU_powerOn_flag;
/* 0x009 */ u8 linkRecovery_enable;
/* 0x00a */ u8 linkRecovery_start_flag;
/* 0x00b */ u8 fastSearchParent_flag;
/* 0x00c */ u8 connectSlot_flag_old;
/* 0x00d */ u8 reserveDisconnectSlot_flag;
/* 0x00e */ u8 active;
/* 0x00f */ u8 msc_exe_flag;
/* 0x010 */ u8 child_slot;
/* 0x011 */ u8 state_bak[2];
/* 0x014 */ u16 param[2];
/* 0x018 */ u16 NI_failCounter_limit;
/* 0x01a */ u16 connect_period;
/* 0x01c */ u16 pcswitch_period_bak;
/* 0x01e */ u16 work;
/* 0x020 */ u16 *acceptable_serialNo_list;
/* 0x024 */ VBL_TIMER nameAcceptTimer;
/* 0x030 */ VBL_TIMER linkRecoveryTimer;
/* 0x03c */ INIT_PARAM *init_param;
/* 0x040 */ void (*LMAN_callback)(u8, u8);
/* 0x044 */ void (*MSC_callback)(u16);
u8 acceptSlot_flag; // Connection slot of child for which Link Manager accepted connection, expressed in bits. (This bit is not dropped for a broken link but is dropped with complete disconnection.)
u8 acceptCount; // Number of child devices for which connections accepted by Link Manager.
vu8 childClockSlave_flag; // Flag indicating whether AGB clock slave state is currently being maintained by child.
vu8 parentAck_flag; // Flag indicating the child devices for which the parent received ACK by UNI commmunication.
u8 state; // Current link manager state
u8 next_state; // State that the link manager transitions to when it is next called.
u8 parent_child; // Shows whether operating on a parent or child.
u8 pcswitch_flag; // Flag for parent-child switching search.
u8 RFU_powerOn_flag; // Flag indicating whether RFU has been powered down.
u8 linkRecovery_enable; // ON/OFF flag for the link recovery process.
u8 linkRecovery_start_flag; // Link recovery start flag
u8 fastSearchParent_flag; // ON/OFF flag for parent fast search by child.
u8 connectSlot_flag_old; // Value of rfuLinkStatus->connectSlot_flag (internally used by the API) when the link manager was called previously.
u8 reserveDisconnectSlot_flag; // Bit indication of the child slot that was reject by child connection authentication and is waiting for disconnect.
u8 active; // Link manager operating flag (internally used by the API)
u8 msc_exe_flag; // MSC callback executing flag (internally used by the API)
u8 child_slot; // Slot number where child device connected (internally used by the API)
u8 state_bak[2]; // Backup of link manager state (internally used by the API)
u16 param[2]; // Region where parameters returned when LMAN callback occurs are stored.
u16 NI_failCounter_limit; // Period of failCounter during NI type data transmit/receive (x 16.7 ms) Note: Runs for unlimited time when specifying 0
u16 connect_period; // Count for the period to execute a connection process (x 16.7 ms). Note: Runs for unlimited time when specifying 0.
u16 pcswitch_period_bak; // Backup for No. 3 SC period during parent-child switching search.
u16 work; // Work region used by the link manager.
u16 *acceptable_serialNo_list; // List of game serial numbers that can accept connections. (See Note below)
VBL_TIMER nameAcceptTimer; // Timer for period to receive game names from child device.
VBL_TIMER linkRecoveryTimer; // Timer for the link recovery process period for both parent and child. Note: Runs for unlimited time when specifying 0.
INIT_PARAM *init_param; // Pointer to parameter when executing initial setting process.
void (*LMAN_callback)(u8 msg,u8 param_count); // Pointer to user-defined LMAN callback routine generated by link manager operation.
void (*MSC_callback)(u16 REQ_commandID); // User-defined MSC callback function. (When defining the link manager, defines the MSC callback using rfu_LMAN_initializeManager or rfu_LMAN_setMSCCallback without using rfu_setMSCCallback.)
} LINK_MANAGER;
/* Note: The acceptable_serialNo_list uses the following format to specify a list of game serial numbers that the parent device can accept connections from and terminates with 0xffff. (maximum 16 devices)
u16 acceptable_serialNo_list[]={0x0001, 0x0002, 0x0003, 0xffff};
*/
extern struct linkManagerTag lman;
u32 rfu_LMAN_REQBN_softReset_and_checkID(void);

View File

@ -13,14 +13,14 @@
Almost exclusively used to set metatiles on the map before it's first drawn
6. ON_FRAME_TABLE: Run every frame after the map has faded in, before player input is processed.
This is a table of scripts that each run if their condition is satisfied.
This is a table of scripts; only the first script whose condition is satisfied is run.
Used to trigger an event, such as the player exiting the cable car or the SS Tidal sailor announcing progress
2. ON_TRANSITION: Run during the transition to the map
Used to set map-specific flags/vars, update object positions/movement types, set weather, etc
5. ON_WARP_INTO_MAP_TABLE: Run after the map's objects are loaded.
This is a table of scripts that each run if their condition is satisfied.
This is a table of scripts; only the first script whose condition is satisfied is run.
Used to add objects to the scene or update something about the player as they warp in (e.g. their facing dir or visibility)
Note that ON_TRANSITION may also handle object visibility, but would do so by modifying a flag or var

View File

@ -1,7 +1,11 @@
#ifndef GUARD_CONSTANTS_UNION_ROOM_H
#define GUARD_CONSTANTS_UNION_ROOM_H
#define MAX_UNION_ROOM_PLAYERS 8
// The number of possible group leaders visible in the Union Room.
// Note that this is different than the number of people actively
// connected as children via the Wireless Adapter, which cannot
// exceed RFU_CHILD_MAX (4), for a total of 5 including the player.
#define MAX_UNION_ROOM_LEADERS 8
#define UNION_ROOM_SPAWN_NONE 0
#define UNION_ROOM_SPAWN_IN 1
@ -13,8 +17,8 @@
#define ACTIVITY_BATTLE_MULTI 3
#define ACTIVITY_TRADE 4
#define ACTIVITY_CHAT 5
#define ACTIVITY_WONDER_CARD 6
#define ACTIVITY_WONDER_NEWS 7
#define ACTIVITY_WONDER_CARD_DUP 6 // Duplicates of later WONDER constants
#define ACTIVITY_WONDER_NEWS_DUP 7 //
#define ACTIVITY_CARD 8
#define ACTIVITY_POKEMON_JUMP 9
#define ACTIVITY_BERRY_CRUSH 10
@ -32,9 +36,8 @@
#define ACTIVITY_NPCTALK 19
#define ACTIVITY_PLYRTALK 20
// Duplicate IDs?
#define ACTIVITY_WONDER_CARD2 21
#define ACTIVITY_WONDER_NEWS2 22
#define ACTIVITY_WONDER_CARD 21
#define ACTIVITY_WONDER_NEWS 22
#define ACTIVITY_CONTEST_COOL 23
#define ACTIVITY_CONTEST_BEAUTY 24
@ -46,15 +49,6 @@
#define IN_UNION_ROOM (1 << 6)
// Used in UR_AddTextPrinterParameterized
#define UR_COLOR_DKE_WHT_LTE 0
#define UR_COLOR_RED_WHT_LTR 1
#define UR_COLOR_GRN_WHT_LTG 2
#define UR_COLOR_WHT_WHT_LTE 3
#define UR_COLOR_WHT_DKE_LTE 4
#define UR_COLOR_GRN_DN6_LTB 5
#define UR_COLOR_DN5_DN6_LTB 6
#define LINK_GROUP_SINGLE_BATTLE 0
#define LINK_GROUP_DOUBLE_BATTLE 1
#define LINK_GROUP_MULTI_BATTLE 2

View File

@ -104,6 +104,14 @@
#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;
@ -227,8 +235,6 @@ struct BlockRequest
u32 size;
};
extern const struct BlockRequest sBlockRequestLookupTable[5];
extern struct Link gLink;
extern u16 gRecvCmds[MAX_RFU_PLAYERS][CMD_LENGTH];
extern u8 gBlockSendBuffer[BLOCK_BUFFER_SIZE];
@ -236,8 +242,7 @@ 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[5];
extern u16 word_3002910[];
extern struct LinkPlayer gLinkPlayers[MAX_RFU_PLAYERS];
extern bool8 gReceivedRemoteLinkPlayers;
extern u32 gBerryBlenderKeySendAttempts;
extern bool8 gLinkVSyncDisabled;
@ -249,8 +254,6 @@ void Task_DestroySelf(u8 taskId);
void OpenLink(void);
void CloseLink(void);
u16 LinkMain2(const u16 *);
void sub_8007B14(void);
bool32 sub_8007B24(void);
void ClearLinkCallback(void);
void ClearLinkCallback_2(void);
u8 GetLinkPlayerCount(void);
@ -259,10 +262,8 @@ u8 GetLinkPlayerDataExchangeStatusTimed(int lower, int upper);
bool8 IsLinkPlayerDataExchangeComplete(void);
u32 GetLinkPlayerTrainerId(u8);
void ResetLinkPlayers(void);
void sub_8007E24(void);
void sub_8007E4C(void);
u8 GetMultiplayerId(void);
u8 bitmask_all_link_players_but_self(void);
u8 BitmaskAllOtherLinkPlayers(void);
bool8 SendBlock(u8, const void *, u16);
u8 GetBlockReceivedStatus(void);
void ResetBlockReceivedFlags(void);
@ -270,7 +271,7 @@ void ResetBlockReceivedFlag(u8);
u8 GetLinkPlayerCount_2(void);
bool8 IsLinkMaster(void);
void CB2_LinkError(void);
u8 GetSioMultiSI(void);
bool8 GetSioMultiSI(void);
bool8 IsLinkConnectionEstablished(void);
bool8 HasLinkErrorOccurred(void);
void ResetSerial(void);
@ -285,16 +286,14 @@ void CreateWirelessStatusIndicatorSprite(u8, u8);
void SetLinkStandbyCallback(void);
void SetWirelessCommType1(void);
void CheckShouldAdvanceLinkState(void);
u8 IsLinkMaster(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);
u8 GetSioMultiSI(void);
void ClearSavedLinkPlayers(void);
void BufferLinkErrorInfo(u32 status, u8 lastSendQueueCount, u8 lastRecvQueueCount, bool8 disconnected);
void SetLinkErrorBuffer(u32 status, u8 lastSendQueueCount, u8 lastRecvQueueCount, bool8 disconnected);
void LocalLinkPlayerToBlock(void);
void LinkPlayerFromBlock(u32 who);
bool32 Link_AnyPartnersPlayingFRLG_JP(void);
@ -312,8 +311,6 @@ extern bool8 gRemoteLinkPlayersNotReceived[MAX_LINK_PLAYERS];
extern u8 gBlockReceivedStatus[MAX_LINK_PLAYERS];
extern u16 gLinkHeldKeys;
extern u32 gLinkStatus;
extern u8 gUnknown_030030E4;
extern u8 gUnknown_030030E8;
extern bool8 gReadyToExitStandby[MAX_LINK_PLAYERS];
extern bool8 gReadyToCloseLink[MAX_LINK_PLAYERS];
extern u16 gReadyCloseLinkType;
@ -329,23 +326,14 @@ extern u8 gBlockRequestType;
extern u8 gLastSendQueueCount;
extern u8 gLastRecvQueueCount;
extern u16 gLinkSavedIme;
extern u32 gFiller_03003074;
extern u32 gFiller_03003154;
extern u32 gFiller_03003158;
extern u32 gFiller_0300315c;
extern u32 gFiller_03004138;
extern u32 gFiller_0300413C;
extern u32 gFiller_03003080;
extern struct LinkPlayer gLocalLinkPlayer;
bool32 Link_AnyPartnersPlayingRubyOrSapphire(void);
bool32 LinkDummy_Return2(void);
void SetLocalLinkPlayerId(u8);
u8 GetSavedPlayerCount(void);
void sub_8009FAC(void);
bool8 SendBlockRequest(u8 type);
u8 GetLinkPlayerCountAsBitFlags(void);
u8 sub_800A0C8(s32, s32);
u8 GetSavedLinkPlayerCountAsBitFlags(void);
void SetCloseLinkCallbackHandleJP(void);
void CheckLinkPlayersMatchSaved(void);

View File

@ -5,29 +5,30 @@
#include "link.h"
#include "AgbRfu_LinkManager.h"
#define RFUCMD_MASK 0xFF00
#define RFUCMD_SEND_PACKET 0x2F00
#define RFUCMD_BLENDER_SEND_KEYS 0x4400
#define RFUCMD_READY_CLOSE_LINK 0x5F00
#define RFUCMD_READY_EXIT_STANDBY 0x6600
#define RFUCMD_0x7700 0x7700
#define RFUCMD_0x7800 0x7800
#define RFUCMD_0x8800 0x8800
#define RFUCMD_0x8900 0x8900
#define RFUCMD_SEND_PLAYER_IDS 0x7700
#define RFUCMD_SEND_PLAYER_IDS_NEW 0x7800
#define RFUCMD_SEND_BLOCK_INIT 0x8800
#define RFUCMD_SEND_BLOCK 0x8900
#define RFUCMD_SEND_BLOCK_REQ 0xA100
#define RFUCMD_SEND_HELD_KEYS 0xBE00
#define RFUCMD_0xED00 0xED00
#define RFUCMD_0xEE00 0xEE00
#define RFUCMD_DISCONNECT 0xED00
#define RFUCMD_DISCONNECT_PARENT 0xEE00
#define RFU_SERIAL_7F7D 0x7F7D
#define RFU_SERIAL_GAME 0x0002 // Serial number for Pokémon game (FRLG or Emerald)
#define RFU_SERIAL_WONDER_DISTRIBUTOR 0x7F7D // Serial number for distributing Wonder Cards / News
#define RFU_SERIAL_UNKNOWN 0x0000 // Unreferenced acceptable serial number. Gamecube?
#define RFU_SERIAL_END 0xFFFF
#define COMM_SLOT_LENGTH 14
#define RECV_QUEUE_NUM_SLOTS 32
#define RECV_QUEUE_SLOT_LENGTH (14 * MAX_RFU_PLAYERS)
#define SEND_QUEUE_NUM_SLOTS 40
#define SEND_QUEUE_SLOT_LENGTH 14
#define BACKUP_QUEUE_NUM_SLOTS 2
#define BACKUP_QUEUE_SLOT_LENGTH 14
#define RFU_PACKET_SIZE 6
@ -41,12 +42,42 @@
#define RFU_STATUS_WAIT_ACK_JOIN_GROUP 7
#define RFU_STATUS_LEAVE_GROUP_NOTICE 8
#define RFU_STATUS_LEAVE_GROUP 9
#define RFU_STATUS_10 10
#define RFU_STATUS_11 11
#define RFU_STATUS_CHILD_LEAVE_READY 10
#define RFU_STATUS_CHILD_LEAVE 11
#define RFU_STATUS_ACK_JOIN_GROUP 12
// RfuTgtData.gname is read as these structs.
struct GFtgtGnameSub
// Values for disconnectMode
enum {
RFU_DISCONNECT_NONE,
RFU_DISCONNECT_ERROR,
RFU_DISCONNECT_NORMAL,
};
// Values for errorState
enum {
RFU_ERROR_STATE_NONE,
RFU_ERROR_STATE_OCCURRED,
RFU_ERROR_STATE_PROCESSED,
RFU_ERROR_STATE_DISCONNECTING,
RFU_ERROR_STATE_IGNORE,
};
// These error flags are set in errorInfo, and given as
// the uppermost 16 bits of 'status' for sLinkErrorBuffer.
// The first 8 bits are reserved for the link manager msg
// when the error occurred, and the last 8 bits are this
// sequence of presumably meaningful error flags, but
// ultimately sLinkErrorBuffer's status is never read.
#define F_RFU_ERROR_1 (1 << 8)
#define F_RFU_ERROR_2 (1 << 9) // Never set
#define F_RFU_ERROR_3 (1 << 10) // Never set
#define F_RFU_ERROR_4 (1 << 11) // Never set
#define F_RFU_ERROR_5 (1 << 12)
#define F_RFU_ERROR_6 (1 << 13)
#define F_RFU_ERROR_7 (1 << 14)
#define F_RFU_ERROR_8 (1 << 15)
struct RfuGameCompatibilityData
{
u16 language:4;
u16 hasNews:1;
@ -56,24 +87,41 @@ struct GFtgtGnameSub
u16 hasNationalDex:1;
u16 gameClear:1;
u16 version:4;
u16 unused:2;
u8 playerTrainerId[2];
};
struct __attribute__((packed, aligned(2))) GFtgtGname
// This struct is sent via the Wireless Adapter as the game name or "gname" data.
// Gname is only applicable during Wireless Single Game Pak Multiplay, when the
// adapter needs this data for connection. Per the RFU manual, during "normal"
// wireless play (the kind the Pokémon games use) the gname data can be used for
// anything the developers want. This struct is what GF decided to use it for.
// It can be up to 13 bytes in size (RFU_GAME_NAME_LENGTH).
// The player's name is sent separately as the username ("uname"), and does not
// use a struct (gHostRfuUsername).
struct __attribute__((packed, aligned(2))) RfuGameData
{
struct GFtgtGnameSub unk_00;
u8 child_sprite_gender[RFU_CHILD_MAX]; // u8 sprite_idx:3;
// u8 gender:1;
// u8 unk_4:3
// u8 active:1
u16 species:10;
u16 type:6;
struct RfuGameCompatibilityData compatibility;
u8 partnerInfo[RFU_CHILD_MAX];
u16 tradeSpecies:10;
u16 tradeType:6;
u8 activity:7;
u8 started:1;
u8 startedActivity:1;
u8 playerGender:1;
u8 level:7;
u8 tradeLevel:7;
u8 padding;
}; // size: RFU_GNAME_SIZE
};
// Constants for getting/setting information in 'partnerInfo' of RfuGameData.
// This data is used to determine what the link partners look like from
// the host's perspective.
// Bits 0-2 are a shortened trainerId
// Bit 3 is the player's gender
// Bits 4-6 are unknown/unused
// Bit 7 is an 'active' flag
#define PINFO_TID_MASK 0x7
#define PINFO_GENDER_SHIFT 3
#define PINFO_ACTIVE_FLAG (1 << 7)
struct RfuBlockSend
{
@ -89,7 +137,7 @@ struct RfuBlockSend
struct RfuRecvQueue
{
/* 0x000 */ u8 slots[RECV_QUEUE_NUM_SLOTS][RECV_QUEUE_SLOT_LENGTH];
/* 0x000 */ u8 slots[RECV_QUEUE_NUM_SLOTS][COMM_SLOT_LENGTH * MAX_RFU_PLAYERS];
/* 0x8c0 */ vu8 recvSlot;
/* 0x8c1 */ vu8 sendSlot;
/* 0x8c2 */ vu8 count;
@ -98,7 +146,7 @@ struct RfuRecvQueue
struct RfuSendQueue
{
/* 0x000 */ u8 slots[SEND_QUEUE_NUM_SLOTS][SEND_QUEUE_SLOT_LENGTH];
/* 0x000 */ u8 slots[SEND_QUEUE_NUM_SLOTS][COMM_SLOT_LENGTH];
/* 0x230 */ vu8 recvSlot;
/* 0x231 */ vu8 sendSlot;
/* 0x232 */ vu8 count;
@ -107,33 +155,34 @@ struct RfuSendQueue
struct RfuBackupQueue
{
/* 0x00 */ u8 slots[BACKUP_QUEUE_NUM_SLOTS][BACKUP_QUEUE_SLOT_LENGTH];
/* 0x00 */ u8 slots[BACKUP_QUEUE_NUM_SLOTS][COMM_SLOT_LENGTH];
/* 0x1c */ vu8 recvSlot;
/* 0x1d */ vu8 sendSlot;
/* 0x1e */ vu8 count;
};
struct GFRfuManager
// Stores data needed for the RFU on GF's end
struct RfuManager
{
/* 0x000 */ void (*callback)(void);
/* 0x004 */ u16 state;
/* 0x006 */ u8 filler_06[4];
/* 0x00a */ u16 linkmanMsg;
/* 0x006 */ u8 unused1[4];
/* 0x00a */ u16 errorInfo;
/* 0x00c */ u8 parentChild;
/* 0x00d */ u8 playerCount;
/* 0x00e */ bool8 unk_0e;
/* 0x00f */ u8 unk_0f;
/* 0x010 */ u16 unk_10;
/* 0x012 */ u16 unk_12;
/* 0x014 */ u8 unk_14[RFU_CHILD_MAX][14];
/* 0x04c */ u8 unk_4c[14];
/* 0x00e */ bool8 runParentMain2;
/* 0x00f */ u8 unused2;
/* 0x010 */ u16 errorParam0;
/* 0x012 */ u16 errorParam1;
/* 0x014 */ u8 childRecvBuffer[RFU_CHILD_MAX][COMM_SLOT_LENGTH];
/* 0x04c */ u8 childSendBuffer[COMM_SLOT_LENGTH];
/* 0x05a */ u8 blockRequestType;
/* 0x05b */ u8 unk_5b;
/* 0x05b */ u8 blockSendAttempts;
/* 0x05c */ bool8 blockReceived[MAX_RFU_PLAYERS];
/* 0x061 */ bool8 numBlocksReceived[MAX_RFU_PLAYERS];
/* 0x066 */ u8 idleTaskId;
/* 0x067 */ u8 searchTaskId;
/* 0x068 */ u8 filler_68[4];
/* 0x068 */ u8 unused3[4];
/* 0x06c */ struct RfuBlockSend sendBlock;
/* 0x080 */ struct RfuBlockSend recvBlock[MAX_RFU_PLAYERS];
/* 0x0e4 */ bool8 readyCloseLink[MAX_RFU_PLAYERS];
@ -144,59 +193,56 @@ struct GFRfuManager
/* 0x0f1 */ u8 status;
/* 0x0f2 */ u16 packet[RFU_PACKET_SIZE];
/* 0x0fe */ u16 resendExitStandbyTimer;
/* 0x100 */ u16 unk_100;
/* 0x102 */ u8 unk_102;
/* 0x103 */ u8 filler_103[0x10A - 0x103];
/* 0x10A */ struct GFtgtGname unk_10A;
/* 0x100 */ u16 allReadyNum;
/* 0x102 */ u8 childSendCmdId;
/* 0x103 */ u8 unused4[7];
/* 0x10A */ struct RfuGameData parent;
u8 filler_;
u8 playerName[PLAYER_NAME_LENGTH + 1];
u8 parentName[RFU_USER_NAME_LENGTH];
/* 0x124 */ struct RfuRecvQueue recvQueue;
/* 0x9e8 */ struct RfuSendQueue sendQueue;
/* 0xc1c */ struct RfuBackupQueue backupQueue;
/* 0xc3c */ vu8 linkRecovered;
/* 0xc3d */ u8 unk_c3d;
/* 0xc3d */ u8 reconnectParentId;
/* 0xc3e */ vu8 childSlot;
/* 0xc3f */ u8 unk_c3f[70];
/* 0xc85 */ u8 unk_c85;
/* 0xc86 */ u8 recvStatus;
/* 0xc87 */ u8 recvCmds[5][7][2];
/* 0xc3f */ u8 childRecvQueue[COMM_SLOT_LENGTH * MAX_RFU_PLAYERS];
/* 0xc85 */ u8 leaveGroupStatus;
/* 0xc86 */ u8 childRecvStatus;
/* 0xc87 */ u8 recvCmds[MAX_RFU_PLAYERS][CMD_LENGTH - 1][2];
/* 0xccd */ u8 parentId;
/* 0xcce */ u8 multiplayerId;
/* 0xccf */ u8 unk_ccf;
/* 0xcd0 */ vu8 unk_cd0;
/* 0xccf */ u8 connectParentFailures;
/* 0xcd0 */ vu8 childSendCount;
/* 0xcd1 */ u8 partnerSendStatuses[RFU_CHILD_MAX];
/* 0xcd5 */ u8 partnerRecvStatuses[RFU_CHILD_MAX];
/* 0xcd9 */ u8 unk_cd9;
/* 0xcda */ u8 unk_cda;
/* 0xcdb */ vbool8 unk_cdb;
/* 0xcdc */ vbool8 unk_cdc;
/* 0xcdd */ u8 unk_cdd;
/* 0xcd9 */ bool8 stopNewConnections;
/* 0xcda */ u8 parentSendSlot;
/* 0xcdb */ vbool8 parentFinished;
/* 0xcdc */ vbool8 parentMain2Failed;
/* 0xcdd */ u8 unused5;
/* 0xcde */ u8 linkPlayerIdx[RFU_CHILD_MAX];
/* 0xce2 */ u8 unk_ce2;
/* 0xce2 */ u8 unk_ce3;
/* 0xce4 */ u8 unk_ce4;
/* 0xce5 */ u8 unk_ce5;
/* 0xce5 */ u8 unk_ce6;
/* 0xce2 */ u8 parentSlots;
/* 0xce2 */ u8 disconnectSlots;
/* 0xce4 */ u8 disconnectMode;
/* 0xce5 */ u8 nextChildBits;
/* 0xce5 */ u8 newChildQueue;
/* 0xce7 */ u8 acceptSlot_flag;
/* 0xce8 */ u8 unk_ce8;
/* 0xce9 */ u8 unk_ce9;
/* 0xcea */ u8 unk_cea[4];
/* 0xcee */ u8 unk_cee[4];
/* 0xce8 */ bool8 playerExchangeActive;
/* 0xce9 */ u8 incomingChild;
/* 0xcea */ u8 numChildRecvErrors[RFU_CHILD_MAX];
/* 0xcee */ u8 childRecvIds[RFU_CHILD_MAX];
}; // size = 0xcf4
// Exported RAM declarations
extern struct GFtgtGname gHostRFUtgtGnameBuffer;
extern u8 gHostRFUtgtUnameBuffer[];
extern struct GFRfuManager Rfu;
extern struct RfuGameData gHostRfuGameData;
extern u8 gHostRfuUsername[];
extern struct RfuManager gRfu;
extern u8 gWirelessStatusIndicatorSpriteId;
// Exported ROM declarations
void WipeTrainerNameRecords(void);
void InitRFUAPI(void);
void LinkRfu_Shutdown(void);
void Rfu_SetBlockReceivedFlag(u8 who);
void Rfu_ResetBlockReceivedFlag(u8 who);
void Rfu_SetBlockReceivedFlag(u8 linkPlayerId);
void Rfu_ResetBlockReceivedFlag(u8 linkPlayerId);
bool32 IsSendingKeysToRfu(void);
void StartSendingKeysToRfu(void);
void Rfu_SetBerryBlenderLinkCallback(void);
@ -213,61 +259,61 @@ void Rfu_SetLinkStandbyCallback(void);
void ResetLinkRfuGFLayer(void);
void UpdateWirelessStatusIndicatorSprite(void);
void InitRFU(void);
bool32 sub_8010EC0(void);
bool32 sub_8010F1C(void);
bool32 RfuMain1(void);
bool32 RfuMain2(void);
bool32 RfuHasErrored(void);
bool32 IsRfuRecvQueueEmpty(void);
u32 GetRfuRecvQueueLength(void);
void RfuVSync(void);
void sub_80111B0(bool32 a0);
void RfuSetIgnoreError(bool32 enable);
u8 RfuGetStatus(void);
struct GFtgtGname *GetHostRFUtgtGname(void);
void UpdateGameData_GroupLockedIn(u8 a0);
void GetLinkmanErrorParams(u32 a0);
void RfuSetStatus(u8 a0, u16 a1);
u8 sub_801048C(bool32 a0);
void LinkRfu3_SetGnameUnameFromStaticBuffers(struct GFtgtGname *buff1, u8 *buff2);
void SetHostRFUtgtGname(u8 activity, u32 child_sprite_genders, bool32 started);
void InitializeRfuLinkManager_LinkLeader(u32 a0);
bool32 sub_8012240(void);
struct RfuGameData *GetHostRfuGameData(void);
void UpdateGameData_GroupLockedIn(u8 startedActivity);
void RfuSetErrorParams(u32 errorInfo);
void RfuSetStatus(u8 status, u16 errorInfo);
u8 Rfu_SetLinkRecovery(bool32 enable);
void CopyHostRfuGameDataAndUsername(struct RfuGameData *gameData, u8 *username);
void SetHostRfuGameData(u8 activity, u32 partnerInfo, bool32 startedActivity);
void InitializeRfuLinkManager_LinkLeader(u32 groupMax);
bool32 IsRfuCommunicatingWithAllChildren(void);
void LinkRfu_StopManagerAndFinalizeSlots(void);
bool32 sub_80105EC(void);
bool32 RfuTryDisconnectLeavingChildren(void);
bool32 HasTrainerLeftPartnersList(u16 trainerId, const u8 *name);
void SendRfuStatusToPartner(u8 status, u16 trainerId, const u8 *name);
u32 WaitSendRfuStatusToPartner(u16 trainerId, const u8 *name);
void RequestDisconnectSlotByTrainerNameAndId(const u8 *a0, u16 a1);
void RequestDisconnectSlotByTrainerNameAndId(const u8 *name, u16 id);
bool8 LmanAcceptSlotFlagIsNotZero(void);
bool32 WaitRfuState(bool32 a0);
void sub_801103C(void);
bool32 WaitRfuState(bool32 force);
void GetOtherPlayersInfoFlags(void);
void InitializeRfuLinkManager_JoinGroup(void);
void SendLeaveGroupNotice(void);
void RecordMixTrainerNames(void);
void SaveLinkTrainerNames(void);
void LinkRfu_CreateConnectionAsParent(void);
void LinkRfu_StopManagerBeforeEnteringChat(void);
void UpdateGameData_SetActivity(u8 activity, u32 flags, bool32 started);
void CreateTask_RfuReconnectWithParent(const u8 *src, u16 trainerId);
void SetGnameBufferWonderFlags(bool32 a0, bool32 a1);
void ClearAndInitHostRFUtgtGname(void);
void UpdateGameData_SetActivity(u8 activity, u32 partnerInfo, bool32 startedActivity);
void CreateTask_RfuReconnectWithParent(const u8 *name, u16 trainerId);
void SetHostRfuWonderFlags(bool32 hasNews, bool32 hasCard);
void ResetHostRfuGameData(void);
void SetTradeBoardRegisteredMonInfo(u32 type, u32 species, u32 level);
void InitializeRfuLinkManager_EnterUnionRoom(void);
void sub_8012188(const u8 *name, struct GFtgtGname *structPtr, u8 a2);
void TryConnectToUnionRoomParent(const u8 *name, struct RfuGameData *parent, u8 activity);
bool32 IsUnionRoomListenTaskActive(void);
void Rfu_SendPacket(void *data);
bool32 PlayerHasMetTrainerBefore(u16 id, u8 *name);
void sub_8011DE0(u32 arg0);
u8 sub_801100C(s32 a0);
void sub_800EF7C(void);
bool8 LinkRfu_GetNameIfCompatible(struct GFtgtGname *buff1, u8 *buff2, u8 idx);
bool8 LinkRfu_GetNameIfSerial7F7D(struct GFtgtGname *buff1, u8 *buff2, u8 idx);
s32 sub_800E87C(u8 idx);
void Rfu_DisconnectPlayerById(u32 playerIdx);
u8 GetLinkPlayerInfoFlags(s32 playerId);
void StopUnionRoomLinkManager(void);
bool8 Rfu_GetCompatiblePlayerData(struct RfuGameData *gameData, u8 *username, u8 idx);
bool8 Rfu_GetWonderDistributorPlayerData(struct RfuGameData *gameData, u8 *username, u8 idx);
s32 Rfu_GetIndexOfNewestChild(u8 bits);
void CreateTask_RfuIdle(void);
void DestroyTask_RfuIdle(void);
void ClearRecvCommands(void);
void LinkRfu_FatalError(void);
bool32 sub_8011A9C(void);
void sub_80104B0(void);
void sub_8011A50(void);
void sub_80110B8(u32 a0);
bool32 Rfu_IsPlayerExchangeActive(void);
void Rfu_StopPartnerSearch(void);
void RfuSetNormalDisconnectMode(void);
void SetUnionRoomChatPlayerData(u32 numPlayers);
bool32 IsRfuSerialNumberValid(u32 serialNo);
bool8 IsRfuRecoveringFromLinkLoss(void);
void RfuRecvQueue_Reset(struct RfuRecvQueue *queue);
@ -276,9 +322,9 @@ void RfuRecvQueue_Enqueue(struct RfuRecvQueue *queue, u8 *data);
void RfuSendQueue_Enqueue(struct RfuSendQueue *queue, u8 *data);
bool8 RfuRecvQueue_Dequeue(struct RfuRecvQueue *queue, u8 *dest);
bool8 RfuSendQueue_Dequeue(struct RfuSendQueue *queue, u8 *dest);
void RfuBackupQueue_Enqueue(struct RfuBackupQueue *queue, const u8 *q2);
bool8 RfuBackupQueue_Dequeue(struct RfuBackupQueue *queue, u8 *q2);
void InitHostRFUtgtGname(struct GFtgtGname *data, u8 activity, bool32 started, s32 child_sprite_genders);
void RfuBackupQueue_Enqueue(struct RfuBackupQueue *queue, const u8 *data);
bool8 RfuBackupQueue_Dequeue(struct RfuBackupQueue *queue, u8 *src);
void InitHostRfuGameData(struct RfuGameData *data, u8 activity, bool32 startedActivity, s32 partnerInfo);
void CreateWirelessStatusIndicatorSprite(u8 x, u8 y);
void DestroyWirelessStatusIndicatorSprite(void);
void LoadWirelessStatusIndicatorSpriteGfx(void);

6
include/reload_save.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef GUARD_RELOAD_SAVE_H
#define GUARD_RELOAD_SAVE_H
void ReloadSave(void);
#endif // GUARD_RELOAD_SAVE_H

View File

@ -1,12 +0,0 @@
#ifndef GUARD_RESET_SAVE_HEAP_H
#define GUARD_RESET_SAVE_HEAP_H
// Exported type declarations
// Exported RAM declarations
// Exported ROM declarations
void sub_81700F8(void);
#endif //GUARD_RESET_SAVE_HEAP_H

View File

@ -36,6 +36,7 @@ struct SaveSectionOffsets
// Emerald changes this definition to be the sectors per slot.
#define NUM_SECTORS_PER_SLOT 16
#define NUM_SAVE_SLOTS 2
#define UNKNOWN_CHECK_VALUE 0x8012025
#define SPECIAL_SECTION_SENTINEL 0xB39D
@ -104,7 +105,7 @@ bool8 sub_8153408(void);
bool8 FullSaveGame(void);
bool8 CheckSaveFile(void);
u8 Save_LoadGameData(u8 saveType);
u16 sub_815355C(void);
u16 GetSaveBlocksPointersBaseOffset(void);
u32 TryReadSpecialSaveSection(u8 sector, u8* dst);
u32 TryWriteSpecialSaveSection(u8 sector, u8* src);
void Task_LinkSave(u8 taskId);

View File

@ -16,8 +16,8 @@ extern const struct WindowTemplate gTradeEvolutionSceneYesNoWindowTemplate;
s32 GetGameProgressForLinkTrade(void);
void CB2_StartCreateTradeMenu(void);
void CB2_LinkTrade(void);
int CanRegisterMonForTradingBoard(struct GFtgtGnameSub a0, u16, u16, u8);
int GetUnionRoomTradeMessageId(struct GFtgtGnameSub a0, struct GFtgtGnameSub a1, u16 a2, u16 a3, u8 a4, u16 a5, u8 a6);
int CanRegisterMonForTradingBoard(struct RfuGameCompatibilityData a0, u16, u16, u8);
int GetUnionRoomTradeMessageId(struct RfuGameCompatibilityData a0, struct RfuGameCompatibilityData a1, u16 a2, u16 a3, u8 a4, u16 a5, u8 a6);
int CanSpinTradeMon(struct Pokemon*, u16);
void InitTradeSequenceBgGpuRegs(void);
void LinkTradeDrawWindow(void);

View File

@ -5,50 +5,58 @@
#include "link.h"
#include "constants/union_room.h"
// Exported type declarations
// In the Union Room the player is only ever connected to ≤ 4 other players.
// However, there can be up to MAX_UNION_ROOM_LEADERS (8) object events to
// represent leaders of recently discovered link groups, and each of those groups
// may have up to MAX_RFU_PLAYERS (5) players in it including the leader.
// These players are represented on-screen by NPC sprites drawn around the leader.
// Thus there can be 40 sprites of other players on-screen, in 8 groups of 5.
#define NUM_UNION_ROOM_SPRITES (MAX_UNION_ROOM_LEADERS * MAX_RFU_PLAYERS)
struct WirelessGnameUnamePair
// The maximum number of recently connected players that can be tracked.
// Note that this is significantly less than NUM_UNION_ROOM_SPRITES, i.e. not
// every player that can be shown in the Union Room can be tracked at once.
// Information such as a group member's gender can instead be read from partnerInfo
// of the leader's RfuGameData by tracking at least all of the group leaders.
#define MAX_RFU_PLAYER_LIST_SIZE 16
struct RfuPlayerData
{
struct GFtgtGname gname;
u8 ALIGNED(4) playerName[PLAYER_NAME_LENGTH + 1];
struct RfuGameData data;
u8 ALIGNED(4) name[RFU_USER_NAME_LENGTH];
};
struct UnkStruct_x1C
struct RfuPlayer
{
struct WirelessGnameUnamePair gname_uname;
u8 active:1;
};
struct UnkStruct_x20
{
struct WirelessGnameUnamePair gname_uname;
struct RfuPlayerData rfu;
u16 timeoutCounter;
u8 groupScheduledAnim:2;
bool8 useRedText:1; // Never set
u8 field_1B;
u8 filler[3];
u8 newPlayerCountdown;
u8 unused;
};
struct UnkStruct_Main0
struct RfuPlayerList
{
struct UnkStruct_x20 arr[MAX_UNION_ROOM_PLAYERS];
struct RfuPlayer players[MAX_RFU_PLAYER_LIST_SIZE];
};
struct UnkStruct_Main4
struct RfuIncomingPlayer
{
struct UnkStruct_x1C arr[MAX_RFU_PLAYERS];
struct RfuPlayerData rfu;
bool8 active:1;
};
struct UnkStruct_Main8
struct RfuIncomingPlayerList
{
struct UnkStruct_x20 arr[MAX_RFU_PLAYERS];
struct RfuIncomingPlayer players[MAX_RFU_PLAYERS];
};
struct WirelessLink_Leader
{
struct UnkStruct_Main0 *field_0;
struct UnkStruct_Main4 *field_4;
struct UnkStruct_Main8 *field_8;
struct RfuPlayerList *playerList;
struct RfuIncomingPlayerList *incomingPlayerList;
struct RfuPlayerList *playerListBackup;
u8 state;
u8 textState;
u8 delayTimerAfterOk;
@ -57,8 +65,8 @@ struct WirelessLink_Leader
u8 nPlayerModeWindowId;
u8 listTaskId;
u8 playerCount;
u16 field_14;
u8 field_16;
u16 yesNoWindowId;
u8 unused;
u8 listenTaskId;
u8 activity;
u8 joinRequestAnswer;
@ -67,20 +75,20 @@ struct WirelessLink_Leader
struct WirelessLink_Group
{
struct UnkStruct_Main0 *field_0;
struct UnkStruct_Main4 *field_4;
struct RfuPlayerList *playerList;
struct RfuIncomingPlayerList *incomingPlayerList;
u8 state;
u8 textState;
u8 field_A;
u8 delayTimerAfterOk; // Unused
u8 listWindowId;
u8 bButtonCancelWindowId;
u8 playerNameAndIdWindowId;
u8 listTaskId;
u8 leaderId;
u8 field_10;
u8 unused;
u8 listenTaskId;
u8 isWonderNews;
u8 field_13;
bool8 isWonderNews;
bool8 showListMenu; // Never set
u8 refreshTimer;
u8 delayBeforePrint;
};
@ -95,73 +103,59 @@ struct UnionRoomObject
struct WirelessLink_URoom
{
struct UnkStruct_Main0 *field_0;
struct UnkStruct_Main4 *field_4;
struct UnkStruct_Main0 *field_8;
struct UnkStruct_Main4 *field_C;
struct RfuPlayerList *playerList;
struct RfuIncomingPlayerList *incomingChildList;
struct RfuPlayerList *spawnPlayer;
struct RfuIncomingPlayerList *incomingParentList;
u16 unknown; // Never read
u16 field_12;
u16 unreadPlayerId;
u8 state;
u8 stateAfterPrint;
u8 textState;
u8 filler[4];
u8 topListMenuWindowId;
u8 topListMenuId;
u8 tradeBoardSelectWindowId;
u8 tradeBoardDetailsWindowId;
u8 tradeBoardMainWindowId;
u8 tradeBoardHeaderWindowId;
u8 unused1;
u8 searchTaskId;
u8 spriteIds[40];
u8 spriteIds[NUM_UNION_ROOM_SPRITES];
u8 unused2;
u8 tradeBoardListMenuId;
u16 playerSendBuffer[6];
u8 activityRequestStrbufs[4][16];
u16 partnerYesNoResponse;
u16 recvActivityRequest[3];
struct UnionRoomObject objects[MAX_UNION_ROOM_PLAYERS];
struct UnionRoomObject objects[MAX_UNION_ROOM_LEADERS];
u8 trainerCardStrBuffer[12][15];
u8 trainerCardColorStrBuffer[48];
u8 trainerCardMsgStrBuffer[200];
};
union WirelessLink_Main
{
struct WirelessLink_Leader *leader;
struct WirelessLink_Group *group;
struct WirelessLink_URoom *uRoom;
};
struct UnionRoomTrade
{
u16 state;
u16 type;
u32 playerPersonality;
u8 offerPlayerId;
u8 filler1;
u16 playerSpecies;
u16 playerLevel;
u16 species;
u16 level;
u16 filler2;
u32 personality;
};
// Exported RAM declarations
extern u8 gPlayerCurrActivity;
extern union WirelessLink_Main gUnknown_02022C30;
extern struct GFtgtGnameSub gPartnerTgtGnameSub;
extern struct RfuGameCompatibilityData gRfuPartnerCompatibilityData;
extern u16 gUnionRoomOfferedSpecies;
extern u8 gUnionRoomRequestedMonType;
// Exported ROM declarations
u8 CreateTask_CreateTradeMenu(void);
void SetUsingUnionRoomStartMenu(void);
void MEvent_CreateTask_CardOrNewsWithFriend(u32 arg0);
void MEvent_CreateTask_CardOrNewsOverWireless(u32 arg0);
void MEvent_CreateTask_Leader(u32 arg0);
void MEvent_CreateTask_CardOrNewsWithFriend(u32 activity);
void MEvent_CreateTask_CardOrNewsOverWireless(u32 activity);
void MEvent_CreateTask_Leader(u32 activity);
u8 CreateTask_ListenToWireless(void);
void StartUnionRoomBattle(u16 battleFlags);

View File

@ -3,12 +3,12 @@
u8 InitUnionRoomPlayerObjects(struct UnionRoomObject *players);
void DestroyUnionRoomPlayerObjects(void);
void CreateGroupMemberSpritesInvisible(u8 *spriteIds, s32 playerIdx);
void DestroyGroupMemberSprites(u8 *spriteIds);
void CreateUnionRoomPlayerSprites(u8 *spriteIds, s32 leaderId);
void DestroyUnionRoomPlayerSprites(u8 *spriteIds);
void SetTilesAroundUnionRoomPlayersPassable(void);
void ScheduleUnionRoomPlayerRefresh(struct WirelessLink_URoom *uroom);
void HandleUnionRoomPlayerRefresh(struct WirelessLink_URoom *uroom);
bool32 TryInteractWithUnionRoomMember(struct UnkStruct_Main0 *main0, s16 *directionPtr, s16 *playerIdxPtr, u8 *spriteIds);
void UpdateUnionRoomMemberFacing(u32 currDirection, u32 playerIdx, struct UnkStruct_Main0 *main0);
bool32 TryInteractWithUnionRoomMember(struct RfuPlayerList *list, s16 *memberIdPtr, s16 *leaderIdPtr, u8 *spriteIds);
void UpdateUnionRoomMemberFacing(u32 memberId, u32 leaderId, struct RfuPlayerList *list);
#endif //GUARD_UNION_ROOM_PLAYER_AVATAR_H

View File

@ -256,7 +256,7 @@ SECTIONS {
src/battle_controller_wally.o(.text);
src/player_pc.o(.text);
src/intro.o(.text);
src/reset_save_heap.o(.text);
src/reload_save.o(.text);
src/field_region_map.o(.text);
src/battle_anim_throw.o(.text);
src/hall_of_fame.o(.text);

View File

@ -789,7 +789,7 @@ static void Task_HandleSendLinkBuffersData(u8 taskId)
gTasks[taskId].data[15] = 0;
}
blockSize = (gLinkBattleSendBuffer[gTasks[taskId].data[15] + LINK_BUFF_SIZE_LO] | (gLinkBattleSendBuffer[gTasks[taskId].data[15] + LINK_BUFF_SIZE_HI] << 8)) + LINK_BUFF_DATA;
SendBlock(bitmask_all_link_players_but_self(), &gLinkBattleSendBuffer[gTasks[taskId].data[15]], blockSize);
SendBlock(BitmaskAllOtherLinkPlayers(), &gLinkBattleSendBuffer[gTasks[taskId].data[15]], blockSize);
gTasks[taskId].data[11]++;
}
else

View File

@ -984,7 +984,7 @@ static void CB2_HandleStartBattle(void)
gLinkPlayers[1].id = 1;
}
SendBlock(bitmask_all_link_players_but_self(), &gBattleStruct->multiBuffer.linkBattlerHeader, sizeof(gBattleStruct->multiBuffer.linkBattlerHeader));
SendBlock(BitmaskAllOtherLinkPlayers(), &gBattleStruct->multiBuffer.linkBattlerHeader, sizeof(gBattleStruct->multiBuffer.linkBattlerHeader));
gBattleCommunication[MULTIUSE_STATE] = 2;
}
if (gWirelessCommType)
@ -1024,7 +1024,7 @@ static void CB2_HandleStartBattle(void)
if (IsLinkTaskFinished())
{
// Send Pokémon 1-2
SendBlock(bitmask_all_link_players_but_self(), gPlayerParty, sizeof(struct Pokemon) * 2);
SendBlock(BitmaskAllOtherLinkPlayers(), gPlayerParty, sizeof(struct Pokemon) * 2);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
@ -1041,7 +1041,7 @@ static void CB2_HandleStartBattle(void)
if (IsLinkTaskFinished())
{
// Send Pokémon 3-4
SendBlock(bitmask_all_link_players_but_self(), &gPlayerParty[2], sizeof(struct Pokemon) * 2);
SendBlock(BitmaskAllOtherLinkPlayers(), &gPlayerParty[2], sizeof(struct Pokemon) * 2);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
@ -1058,7 +1058,7 @@ static void CB2_HandleStartBattle(void)
if (IsLinkTaskFinished())
{
// Send Pokémon 5-6
SendBlock(bitmask_all_link_players_but_self(), &gPlayerParty[4], sizeof(struct Pokemon) * 2);
SendBlock(BitmaskAllOtherLinkPlayers(), &gPlayerParty[4], sizeof(struct Pokemon) * 2);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
@ -1105,7 +1105,7 @@ static void CB2_HandleStartBattle(void)
// Both players are using Emerald, send rng seed for recorded battle
if (IsLinkTaskFinished())
{
SendBlock(bitmask_all_link_players_but_self(), &gRecordedBattleRngSeed, sizeof(gRecordedBattleRngSeed));
SendBlock(BitmaskAllOtherLinkPlayers(), &gRecordedBattleRngSeed, sizeof(gRecordedBattleRngSeed));
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
@ -1198,7 +1198,7 @@ static void CB2_HandleStartMultiPartnerBattle(void)
*(&gBattleStruct->multiBuffer.linkBattlerHeader.versionSignatureHi) = 3;
BufferPartyVsScreenHealth_AtStart();
SetPlayerBerryDataInBattleStruct();
SendBlock(bitmask_all_link_players_but_self(), &gBattleStruct->multiBuffer.linkBattlerHeader, sizeof(gBattleStruct->multiBuffer.linkBattlerHeader));
SendBlock(BitmaskAllOtherLinkPlayers(), &gBattleStruct->multiBuffer.linkBattlerHeader, sizeof(gBattleStruct->multiBuffer.linkBattlerHeader));
gBattleCommunication[MULTIUSE_STATE] = 2;
}
@ -1236,7 +1236,7 @@ static void CB2_HandleStartMultiPartnerBattle(void)
if (IsLinkTaskFinished())
{
// Send Pokémon 1-2
SendBlock(bitmask_all_link_players_but_self(), gPlayerParty, sizeof(struct Pokemon) * 2);
SendBlock(BitmaskAllOtherLinkPlayers(), gPlayerParty, sizeof(struct Pokemon) * 2);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
@ -1262,7 +1262,7 @@ static void CB2_HandleStartMultiPartnerBattle(void)
if (IsLinkTaskFinished())
{
// Send Pokémon 3
SendBlock(bitmask_all_link_players_but_self(), &gPlayerParty[2], sizeof(struct Pokemon));
SendBlock(BitmaskAllOtherLinkPlayers(), &gPlayerParty[2], sizeof(struct Pokemon));
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
@ -1288,7 +1288,7 @@ static void CB2_HandleStartMultiPartnerBattle(void)
if (IsLinkTaskFinished())
{
// Send enemy Pokémon 1-2 to partner
SendBlock(bitmask_all_link_players_but_self(), gEnemyParty, sizeof(struct Pokemon) * 2);
SendBlock(BitmaskAllOtherLinkPlayers(), gEnemyParty, sizeof(struct Pokemon) * 2);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
@ -1306,7 +1306,7 @@ static void CB2_HandleStartMultiPartnerBattle(void)
if (IsLinkTaskFinished())
{
// Send enemy Pokémon 3-4 to partner
SendBlock(bitmask_all_link_players_but_self(), &gEnemyParty[2], sizeof(struct Pokemon) * 2);
SendBlock(BitmaskAllOtherLinkPlayers(), &gEnemyParty[2], sizeof(struct Pokemon) * 2);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
@ -1324,7 +1324,7 @@ static void CB2_HandleStartMultiPartnerBattle(void)
if (IsLinkTaskFinished())
{
// Send enemy Pokémon 5-6 to partner
SendBlock(bitmask_all_link_players_but_self(), &gEnemyParty[4], sizeof(struct Pokemon) * 2);
SendBlock(BitmaskAllOtherLinkPlayers(), &gEnemyParty[4], sizeof(struct Pokemon) * 2);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
@ -1365,7 +1365,7 @@ static void CB2_HandleStartMultiPartnerBattle(void)
// Send rng seed for recorded battle
if (IsLinkTaskFinished())
{
SendBlock(bitmask_all_link_players_but_self(), &gRecordedBattleRngSeed, sizeof(gRecordedBattleRngSeed));
SendBlock(BitmaskAllOtherLinkPlayers(), &gRecordedBattleRngSeed, sizeof(gRecordedBattleRngSeed));
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
@ -1447,7 +1447,7 @@ static void CB2_PreInitMultiBattle(void)
{
sMultiPartnerPartyBuffer = Alloc(sizeof(gMultiPartnerParty));
SetMultiPartnerMenuParty(0);
SendBlock(bitmask_all_link_players_but_self(), sMultiPartnerPartyBuffer, sizeof(gMultiPartnerParty));
SendBlock(BitmaskAllOtherLinkPlayers(), sMultiPartnerPartyBuffer, sizeof(gMultiPartnerParty));
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
@ -1592,7 +1592,7 @@ static void CB2_HandleStartMultiBattle(void)
BufferPartyVsScreenHealth_AtStart();
SetPlayerBerryDataInBattleStruct();
SendBlock(bitmask_all_link_players_but_self(), &gBattleStruct->multiBuffer.linkBattlerHeader, sizeof(gBattleStruct->multiBuffer.linkBattlerHeader));
SendBlock(BitmaskAllOtherLinkPlayers(), &gBattleStruct->multiBuffer.linkBattlerHeader, sizeof(gBattleStruct->multiBuffer.linkBattlerHeader));
gBattleCommunication[MULTIUSE_STATE]++;
}
if (gWirelessCommType)
@ -1649,7 +1649,7 @@ static void CB2_HandleStartMultiBattle(void)
case 3:
if (IsLinkTaskFinished())
{
SendBlock(bitmask_all_link_players_but_self(), gPlayerParty, sizeof(struct Pokemon) * 2);
SendBlock(BitmaskAllOtherLinkPlayers(), gPlayerParty, sizeof(struct Pokemon) * 2);
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
@ -1712,7 +1712,7 @@ static void CB2_HandleStartMultiBattle(void)
case 5:
if (IsLinkTaskFinished())
{
SendBlock(bitmask_all_link_players_but_self(), gPlayerParty + 2, sizeof(struct Pokemon));
SendBlock(BitmaskAllOtherLinkPlayers(), gPlayerParty + 2, sizeof(struct Pokemon));
gBattleCommunication[MULTIUSE_STATE]++;
}
break;
@ -1811,7 +1811,7 @@ static void CB2_HandleStartMultiBattle(void)
u32* ptr = gBattleStruct->multiBuffer.battleVideo;
ptr[0] = gBattleTypeFlags;
ptr[1] = gRecordedBattleRngSeed; // UB: overwrites berry data
SendBlock(bitmask_all_link_players_but_self(), ptr, sizeof(gBattleStruct->multiBuffer.battleVideo));
SendBlock(BitmaskAllOtherLinkPlayers(), ptr, sizeof(gBattleStruct->multiBuffer.battleVideo));
gBattleCommunication[MULTIUSE_STATE]++;
}
break;

View File

@ -2575,7 +2575,7 @@ static void LoadLinkMultiOpponentsData(void)
challengeNum = gSaveBlock2Ptr->frontier.towerWinStreaks[battleMode][lvlMode] / 7;
if (IsLinkTaskFinished())
{
SendBlock(bitmask_all_link_players_but_self(), &challengeNum, sizeof(challengeNum));
SendBlock(BitmaskAllOtherLinkPlayers(), &challengeNum, sizeof(challengeNum));
gSpecialVar_Result = 1;
}
}
@ -2612,7 +2612,7 @@ static void LoadLinkMultiOpponentsData(void)
case 2:
if (IsLinkTaskFinished())
{
SendBlock(bitmask_all_link_players_but_self(), &gSaveBlock2Ptr->frontier.trainerIds, sizeof(gSaveBlock2Ptr->frontier.trainerIds));
SendBlock(BitmaskAllOtherLinkPlayers(), &gSaveBlock2Ptr->frontier.trainerIds, sizeof(gSaveBlock2Ptr->frontier.trainerIds));
gSpecialVar_Result = 3;
}
break;

View File

@ -1355,7 +1355,7 @@ static void CB2_StartBlenderLink(void)
{
ResetBlockReceivedFlags();
if (GetMultiplayerId() == 0)
SendBlockRequest(4);
SendBlockRequest(BLOCK_REQ_SIZE_40);
sBerryBlender->mainState++;
}
break;
@ -2069,7 +2069,7 @@ static bool32 CheckRecvCmdMatches(u16 recvCmd, u16 linkCmd, u16 rfuCmd)
{
if (gReceivedRemoteLinkPlayers && gWirelessCommType)
{
if ((recvCmd & 0xFF00) == rfuCmd)
if ((recvCmd & RFUCMD_MASK) == rfuCmd)
return TRUE;
}
else
@ -3135,7 +3135,7 @@ static void UpdateBlenderCenter(void)
}
else
{
if ((gRecvCmds[0][BLENDER_COMM_INPUT_STATE] & 0xFF00) == RFUCMD_BLENDER_SEND_KEYS)
if ((gRecvCmds[0][BLENDER_COMM_INPUT_STATE] & RFUCMD_MASK) == RFUCMD_BLENDER_SEND_KEYS)
{
sBerryBlender->progressBarValue = gRecvCmds[0][BLENDER_COMM_PROGRESS_BAR];
sBerryBlender->arrowPos = gRecvCmds[0][BLENDER_COMM_ARROW_POS];

View File

@ -984,12 +984,12 @@ static u32 QuitBerryCrush(MainCallback exitCallback)
return 0;
}
#define ERROR_EXIT(exitCallback) \
{ \
SetMainCallback2(exitCallback); \
Rfu.unk_10 = 0; \
Rfu.unk_12 = 0; \
Rfu.errorState = 1; \
#define ERROR_EXIT(exitCallback) \
{ \
SetMainCallback2(exitCallback); \
gRfu.errorParam0 = 0; \
gRfu.errorParam1 = 0; \
gRfu.errorState = RFU_ERROR_STATE_OCCURRED; \
}
void StartBerryCrush(MainCallback exitCallback)
@ -2565,7 +2565,7 @@ static void HandlePartnerInput(struct BerryCrushGame *game)
linkState = (struct BerryCrushGame_LinkState *)gRecvCmds[i];
// Skip player if we have not received a packet from them
if ((linkState->rfuCmd & 0xFF00) != RFUCMD_SEND_PACKET)
if ((linkState->rfuCmd & RFUCMD_MASK) != RFUCMD_SEND_PACKET)
continue;
if (linkState->sendFlag != SEND_GAME_STATE)
continue;
@ -2805,7 +2805,7 @@ static void RecvLinkData(struct BerryCrushGame *game)
for (i = 0; i < game->playerCount; i++)
game->players[i].inputState = INPUT_STATE_NONE;
if ((gRecvCmds[0][0] & 0xFF00) != RFUCMD_SEND_PACKET)
if ((gRecvCmds[0][0] & RFUCMD_MASK) != RFUCMD_SEND_PACKET)
{
game->playedSound = FALSE;
return;

View File

@ -185,9 +185,9 @@ static bool32 CheckLinkCanceled(u8 taskId)
return FALSE;
}
static bool32 sub_80B25CC(u8 taskId)
static bool32 CheckSioErrored(u8 taskId)
{
if (GetSioMultiSI() == 1)
if (GetSioMultiSI() == TRUE)
{
gTasks[taskId].func = Task_LinkupConnectionError;
return TRUE;
@ -196,12 +196,12 @@ static bool32 sub_80B25CC(u8 taskId)
}
// Unused
static void sub_80B2600(u8 taskId)
static void Task_DelayedBlockRequest(u8 taskId)
{
gTasks[taskId].data[0]++;
if (gTasks[taskId].data[0] == 10)
{
SendBlockRequest(2);
SendBlockRequest(BLOCK_REQ_SIZE_100);
DestroyTask(taskId);
}
}
@ -252,7 +252,7 @@ static void Task_LinkupAwaitConnection(u8 taskId)
static void Task_LinkupConfirmWhenReady(u8 taskId)
{
if (CheckLinkCanceledBeforeConnection(taskId) == TRUE
|| sub_80B25CC(taskId) == TRUE
|| CheckSioErrored(taskId) == TRUE
|| CheckLinkErrored(taskId) == TRUE)
return;
@ -269,7 +269,7 @@ static void Task_LinkupAwaitConfirmation(u8 taskId)
s32 linkPlayerCount = GetLinkPlayerCount_2();
if (CheckLinkCanceledBeforeConnection(taskId) == TRUE
|| sub_80B25CC(taskId) == TRUE
|| CheckSioErrored(taskId) == TRUE
|| CheckLinkErrored(taskId) == TRUE)
return;
@ -291,7 +291,7 @@ static void Task_LinkupAwaitConfirmation(u8 taskId)
static void Task_LinkupTryConfirmation(u8 taskId)
{
if (CheckLinkCanceledBeforeConnection(taskId) == TRUE
|| sub_80B25CC(taskId) == TRUE
|| CheckSioErrored(taskId) == TRUE
|| CheckLinkErrored(taskId) == TRUE)
return;
@ -424,7 +424,7 @@ static void Task_LinkupCheckStatusAfterConfirm(u8 taskId)
card->monSpecies[0] = GetMonData(&gPlayerParty[gSelectedOrderFromParty[0] - 1], MON_DATA_SPECIES, NULL);
card->monSpecies[1] = GetMonData(&gPlayerParty[gSelectedOrderFromParty[1] - 1], MON_DATA_SPECIES, NULL);
gTasks[taskId].func = Task_LinkupAwaitTrainerCardData;
SendBlockRequest(2);
SendBlockRequest(BLOCK_REQ_SIZE_100);
}
}
@ -1172,9 +1172,11 @@ static void CreateTask_StartWiredTrade(void)
CreateTask(Task_StartWiredTrade, 80);
}
void nullsub_37(void)
// Unused, implemented in Ruby/Sapphire
void Script_StartWiredTrade(void)
{
// CreateTask_StartWiredTrade();
// ScriptContext1_Stop();
}
void ColosseumPlayerSpotTriggered(void)
@ -1251,7 +1253,7 @@ void Task_WaitForLinkPlayerConnection(u8 taskId)
#undef tTimer
static void sub_80B3AAC(u8 taskId)
static void Task_WaitExitToScript(u8 taskId)
{
if (!gReceivedRemoteLinkPlayers)
{
@ -1261,10 +1263,10 @@ static void sub_80B3AAC(u8 taskId)
}
// Unused
static void sub_80B3AD0(u8 taskId)
static void ExitLinkToScript(u8 taskId)
{
SetCloseLinkCallback();
gTasks[taskId].func = sub_80B3AAC;
gTasks[taskId].func = Task_WaitExitToScript;
}
#define tTimer data[1]

View File

@ -22,7 +22,7 @@ static void Task_LinkContest_InitFlags(u8);
bool32 LinkContest_SendBlock(void *src, u16 size)
{
memcpy(gDecompressionBuffer, src, size);
if (SendBlock(bitmask_all_link_players_but_self(), gDecompressionBuffer, size))
if (SendBlock(BitmaskAllOtherLinkPlayers(), gDecompressionBuffer, size))
return TRUE;
else
return FALSE;
@ -162,7 +162,7 @@ void Task_LinkContest_CommunicateMonsRS(u8 taskId)
// Only if leader. Request other players data
if (++gTasks[taskId].tTimer > 300)
{
SendBlockRequest(2);
SendBlockRequest(BLOCK_REQ_SIZE_100);
gTasks[taskId].tState = 1;
}
break;
@ -238,7 +238,7 @@ void Task_LinkContest_CommunicateCategoryRS(u8 taskId)
case 10:
if (++gTasks[taskId].tTimer > 10)
{
SendBlockRequest(2);
SendBlockRequest(BLOCK_REQ_SIZE_100);
gTasks[taskId].tState = 1;
}
break;
@ -491,7 +491,7 @@ void Task_LinkContest_CommunicateLeaderIdsRS(u8 taskId)
case 10:
if (++gTasks[taskId].tTimer > 10)
{
SendBlockRequest(2);
SendBlockRequest(BLOCK_REQ_SIZE_100);
gTasks[taskId].tState = 1;
}
break;

File diff suppressed because it is too large Load Diff

View File

@ -3106,7 +3106,7 @@ static u32 RecvPacket_ReadyToStart(u32 playerId)
{
struct ReadyToStartPacket *packet;
if ((gRecvCmds[0][0] & 0xFF00) != RFUCMD_SEND_PACKET)
if ((gRecvCmds[0][0] & RFUCMD_MASK) != RFUCMD_SEND_PACKET)
return FALSE;
packet = (void *)&gRecvCmds[playerId][1];
@ -3233,7 +3233,7 @@ static bool32 RecvPacket_GameState(u32 playerId,
struct GameStatePacket *packet;
struct DodrioGame_Berries *berries = &player->berries;
if ((gRecvCmds[0][0] & 0xFF00) != RFUCMD_SEND_PACKET)
if ((gRecvCmds[0][0] & RFUCMD_MASK) != RFUCMD_SEND_PACKET)
return FALSE;
packet = (void *)&gRecvCmds[0][1];
@ -3310,7 +3310,7 @@ static bool32 RecvPacket_PickState(u32 playerId, u8 *pickState)
{
struct PickStatePacket *packet;
if ((gRecvCmds[0][0] & 0xFF00) != RFUCMD_SEND_PACKET)
if ((gRecvCmds[0][0] & RFUCMD_MASK) != RFUCMD_SEND_PACKET)
return FALSE;
packet = (void *)&gRecvCmds[playerId][1];
@ -3341,7 +3341,7 @@ static bool32 RecvPacket_ReadyToEnd(u32 playerId)
{
struct ReadyToEndPacket *packet;
if ((gRecvCmds[0][0] & 0xFF00) != RFUCMD_SEND_PACKET)
if ((gRecvCmds[0][0] & RFUCMD_MASK) != RFUCMD_SEND_PACKET)
return FALSE;
packet = (void *)&gRecvCmds[playerId][1];

View File

@ -1138,22 +1138,22 @@ u8 player_get_pos_including_state_based_drift(s16 *x, s16 *y)
switch (object->movementActionId)
{
case MOVEMENT_ACTION_WALK_NORMAL_DOWN:
case MOVEMENT_ACTION_PLAYER_RUN_DOWN:
(*y)++;
return TRUE;
case MOVEMENT_ACTION_WALK_NORMAL_UP:
case MOVEMENT_ACTION_PLAYER_RUN_UP:
(*y)--;
return TRUE;
case MOVEMENT_ACTION_WALK_NORMAL_LEFT:
case MOVEMENT_ACTION_PLAYER_RUN_LEFT:
(*x)--;
return TRUE;
case MOVEMENT_ACTION_WALK_NORMAL_RIGHT:
case MOVEMENT_ACTION_PLAYER_RUN_RIGHT:
(*x)++;
return TRUE;
case MOVEMENT_ACTION_WALK_NORMAL_DOWN:
case MOVEMENT_ACTION_PLAYER_RUN_DOWN:
(*y)++;
return TRUE;
case MOVEMENT_ACTION_WALK_NORMAL_UP:
case MOVEMENT_ACTION_PLAYER_RUN_UP:
(*y)--;
return TRUE;
case MOVEMENT_ACTION_WALK_NORMAL_LEFT:
case MOVEMENT_ACTION_PLAYER_RUN_LEFT:
(*x)--;
return TRUE;
case MOVEMENT_ACTION_WALK_NORMAL_RIGHT:
case MOVEMENT_ACTION_PLAYER_RUN_RIGHT:
(*x)++;
return TRUE;
}
}

View File

@ -204,7 +204,7 @@ static void Task_ReturnToFieldWirelessLink(u8 taskId)
if (!IsLinkTaskFinished())
{
if (++task->data[1] > 1800)
GetLinkmanErrorParams(0x6000);
RfuSetErrorParams(F_RFU_ERROR_6 | F_RFU_ERROR_7);
}
else
{

View File

@ -3779,7 +3779,7 @@ static void Task_LinkRetireStatusWithBattleTowerPartner(u8 taskId)
{
// Send value of gSpecialVar_0x8004 to leader
// Will either be BATTLE_TOWER_LINK_CONTINUE or BATTLE_TOWER_LINK_RETIRE
SendBlock(bitmask_all_link_players_but_self(), &gSpecialVar_0x8004, sizeof(gSpecialVar_0x8004));
SendBlock(BitmaskAllOtherLinkPlayers(), &gSpecialVar_0x8004, sizeof(gSpecialVar_0x8004));
gTasks[taskId].tState++;
}
}
@ -3828,7 +3828,7 @@ static void Task_LinkRetireStatusWithBattleTowerPartner(u8 taskId)
else
{
// Send whether or not play should continue
SendBlock(bitmask_all_link_players_but_self(), &gSpecialVar_Result, sizeof(gSpecialVar_Result));
SendBlock(BitmaskAllOtherLinkPlayers(), &gSpecialVar_Result, sizeof(gSpecialVar_Result));
gTasks[taskId].tState++;
}
}

View File

@ -1142,7 +1142,7 @@ void CB2_InitCopyrightScreenAfterBootup(void)
{
if (!SetUpCopyrightScreen())
{
SetSaveBlocksPointers(sub_815355C());
SetSaveBlocksPointers(GetSaveBlocksPointersBaseOffset());
ResetMenuAndMonGlobals();
Save_ResetSaveCounters();
Save_LoadGameData(SAVE_NORMAL);

View File

@ -1,6 +1,14 @@
#include <limits.h>
#include "librfu.h"
// If expanding the length of the player name and wireless link functionality is
// desired, ensure that the name string is limited in size when it's copied from the
// saveblock to any Rfu-related fields (e.g. in SetHostRfuUsername).
// If wireless link functionality is not desired ignore or delete this warning.
#if RFU_USER_NAME_LENGTH < (PLAYER_NAME_LENGTH + 1)
#warning "The Wireless Adapter hardware expects a username of no more than 8 bytes."
#endif
struct LLSFStruct
{
u8 frameSize;

View File

@ -1,7 +1,7 @@
#include "global.h"
#include "m4a.h"
#include "malloc.h"
#include "reset_save_heap.h"
#include "reload_save.h"
#include "save.h"
#include "bg.h"
#include "window.h"
@ -108,7 +108,7 @@ static EWRAM_DATA u16 sTimeOutCounter = 0;
EWRAM_DATA struct LinkPlayer gLocalLinkPlayer = {};
EWRAM_DATA struct LinkPlayer gLinkPlayers[MAX_RFU_PLAYERS] = {};
static EWRAM_DATA struct LinkPlayer sSavedLinkPlayers[MAX_RFU_PLAYERS] = {};
EWRAM_DATA struct {
static EWRAM_DATA struct {
u32 status;
u8 lastRecvQueueCount;
u8 lastSendQueueCount;
@ -140,7 +140,7 @@ static void LinkCB_WaitCloseLinkWithJP(void);
static void LinkCB_Standby(void);
static void LinkCB_StandbyForAll(void);
static void CheckErrorStatus(void);
static void TrySetLinkErrorBuffer(void);
static void CB2_PrintErrorMessage(void);
static bool8 IsSioMultiMaster(void);
static void SetWirelessCommType0_Internal(void);
@ -166,11 +166,11 @@ static const u16 sLinkTestDigitsGfx[] = INCBIN_U16("graphics/interface/link_test
static const u8 sUnusedTransparentWhite[] = _("{HIGHLIGHT TRANSPARENT}{COLOR WHITE}");
static const u16 sCommErrorBg_Gfx[] = INCBIN_U16("graphics/interface/comm_error_bg.4bpp");
static const struct BlockRequest sBlockRequests[] = {
{gBlockSendBuffer, 200},
{gBlockSendBuffer, 200},
{gBlockSendBuffer, 100},
{gBlockSendBuffer, 220},
{gBlockSendBuffer, 40}
[BLOCK_REQ_SIZE_NONE] = {gBlockSendBuffer, 200},
[BLOCK_REQ_SIZE_200] = {gBlockSendBuffer, 200},
[BLOCK_REQ_SIZE_100] = {gBlockSendBuffer, 100},
[BLOCK_REQ_SIZE_220] = {gBlockSendBuffer, 220},
[BLOCK_REQ_SIZE_40] = {gBlockSendBuffer, 40}
};
static const u8 sBGControlRegs[] = {
REG_OFFSET_BG0CNT,
@ -394,9 +394,7 @@ void CloseLink(void)
{
gReceivedRemoteLinkPlayers = FALSE;
if (gWirelessCommType)
{
LinkRfu_Shutdown();
}
sLinkOpen = FALSE;
DisableSerial();
}
@ -485,22 +483,18 @@ u16 LinkMain2(const u16 *heldKeys)
u8 i;
if (!sLinkOpen)
{
return 0;
}
for (i = 0; i < CMD_LENGTH; i++)
{
gSendCmd[i] = 0;
}
gLinkHeldKeys = *heldKeys;
if (gLinkStatus & LINK_STAT_CONN_ESTABLISHED)
{
ProcessRecvCmds(SIO_MULTI_CNT->id);
if (gLinkCallback != NULL)
{
gLinkCallback();
}
CheckErrorStatus();
TrySetLinkErrorBuffer();
}
return gLinkStatus;
}
@ -1029,7 +1023,7 @@ u8 GetMultiplayerId(void)
return SIO_MULTI_CNT->id;
}
u8 bitmask_all_link_players_but_self(void)
u8 BitmaskAllOtherLinkPlayers(void)
{
u8 mpId;
@ -1563,10 +1557,13 @@ static void LinkCB_StandbyForAll(void)
}
}
static void CheckErrorStatus(void)
static void TrySetLinkErrorBuffer(void)
{
// Check if a link error has occurred
if (sLinkOpen && EXTRACT_LINK_ERRORS(gLinkStatus))
{
// Link error has occurred, handle message details if
// necessary, then stop the link.
if (!gSuppressLinkErrorMessage)
{
sLinkErrorBuffer.status = gLinkStatus;
@ -1579,7 +1576,7 @@ static void CheckErrorStatus(void)
}
}
void BufferLinkErrorInfo(u32 status, u8 lastSendQueueCount, u8 lastRecvQueueCount, bool8 disconnected)
void SetLinkErrorBuffer(u32 status, u8 lastSendQueueCount, u8 lastRecvQueueCount, bool8 disconnected)
{
sLinkErrorBuffer.status = status;
sLinkErrorBuffer.lastSendQueueCount = lastSendQueueCount;
@ -1709,7 +1706,7 @@ static void CB2_PrintErrorMessage(void)
PlaySE(SE_PIN);
gWirelessCommType = 0;
sLinkErrorBuffer.disconnected = FALSE;
sub_81700F8();
ReloadSave();
}
}
else if (gWirelessCommType == 2)
@ -1731,12 +1728,12 @@ static void CB2_PrintErrorMessage(void)
bool8 GetSioMultiSI(void)
{
return (REG_SIOCNT & 0x04) != 0;
return (REG_SIOCNT & SIO_MULTI_SI) != 0;
}
static bool8 IsSioMultiMaster(void)
{
return (REG_SIOCNT & 0x8) && !(REG_SIOCNT & 0x04);
return (REG_SIOCNT & SIO_MULTI_SD) && (REG_SIOCNT & SIO_MULTI_SI) == 0;
}
bool8 IsLinkConnectionEstablished(void)
@ -1782,10 +1779,10 @@ void LinkPlayerFromBlock(u32 who)
SetMainCallback2(CB2_LinkError);
}
// When this function returns TRUE the callbacks are skipped
bool8 HandleLinkConnection(void)
{
bool32 r4;
bool32 r5;
bool32 main1Failed, main2Failed;
if (gWirelessCommType == 0)
{
@ -1796,11 +1793,13 @@ bool8 HandleLinkConnection(void)
}
else
{
r4 = sub_8010EC0();
r5 = sub_8010F1C();
main1Failed = RfuMain1(); // Always returns FALSE
main2Failed = RfuMain2();
if (IsSendingKeysOverCable() == TRUE)
{
if (r4 == TRUE || IsRfuRecvQueueEmpty() || r5)
// This will never be reached.
// IsSendingKeysOverCable is always FALSE for wireless communication
if (main1Failed == TRUE || IsRfuRecvQueueEmpty() || main2Failed)
return TRUE;
}
}
@ -1916,9 +1915,7 @@ u32 LinkMain1(u8 *shouldAdvanceLinkState, u16 *sendCmd, u16 (*recvCmds)[CMD_LENG
break;
case 1:
if (gLink.isMaster == LINK_MASTER && gLink.playerCount > 1)
{
gLink.handshakeAsMaster = TRUE;
}
break;
case 2:
gLink.state = LINK_STATE_START0;
@ -1974,20 +1971,14 @@ u32 LinkMain1(u8 *shouldAdvanceLinkState, u16 *sendCmd, u16 (*recvCmds)[CMD_LENG
}
if (gLink.lag == LAG_MASTER)
{
retVal |= LINK_STAT_ERROR_LAG_MASTER;
}
if (gLink.localId >= MAX_LINK_PLAYERS)
{
retVal |= LINK_STAT_ERROR_INVALID_ID;
}
retVal2 = retVal;
if (gLink.lag == LAG_SLAVE)
{
retVal2 |= LINK_STAT_ERROR_LAG_SLAVE;
}
return retVal2;
}

File diff suppressed because it is too large Load Diff

View File

@ -15,6 +15,9 @@ enum {
WIRELESS_STATUS_ANIM_ERROR,
};
#define TAG_GFX_STATUS_INDICATOR 0xD431
#define TAG_PAL_STATUS_INDICATOR 0xD432
#define UNUSED_QUEUE_NUM_SLOTS 2
#define UNUSED_QUEUE_SLOT_LENGTH 256
@ -29,7 +32,7 @@ struct RfuUnusedQueue
EWRAM_DATA u8 gWirelessStatusIndicatorSpriteId = 0;
static u8 sUnknown_03000D74;
static u8 sSequenceArrayValOffset;
static const u16 sWirelessLinkIconPalette[] = INCBIN_U16("graphics/interface/wireless_link_icon.gbapal");
static const u32 sWirelessLinkIconPic[] = INCBIN_U32("graphics/interface/wireless_link_icon.4bpp.lz");
@ -290,16 +293,16 @@ static const union AnimCmd *const sWirelessStatusIndicatorAnims[] = {
};
static const struct CompressedSpriteSheet sWirelessStatusIndicatorSpriteSheet = {
sWirelessLinkIconPic, 0x0380, 0xD431
sWirelessLinkIconPic, 0x0380, TAG_GFX_STATUS_INDICATOR
};
static const struct SpritePalette sWirelessStatusIndicatorSpritePalette = {
sWirelessLinkIconPalette, 0xD432
sWirelessLinkIconPalette, TAG_PAL_STATUS_INDICATOR
};
static const struct SpriteTemplate sWirelessStatusIndicatorSpriteTemplate = {
.tileTag = 0xD431,
.paletteTag = 0xD432,
.tileTag = TAG_GFX_STATUS_INDICATOR,
.paletteTag = TAG_PAL_STATUS_INDICATOR,
.oam = &sWirelessStatusIndicatorOamData,
.anims = sWirelessStatusIndicatorAnims,
.images = NULL,
@ -314,10 +317,8 @@ void RfuRecvQueue_Reset(struct RfuRecvQueue *queue)
for (i = 0; i < RECV_QUEUE_NUM_SLOTS; i++)
{
for (j = 0; j < RECV_QUEUE_SLOT_LENGTH; j++)
{
for (j = 0; j < COMM_SLOT_LENGTH * MAX_RFU_PLAYERS; j++)
queue->slots[i][j] = 0;
}
}
queue->sendSlot = 0;
queue->recvSlot = 0;
@ -332,10 +333,8 @@ void RfuSendQueue_Reset(struct RfuSendQueue *queue)
for (i = 0; i < SEND_QUEUE_NUM_SLOTS; i++)
{
for (j = 0; j < SEND_QUEUE_SLOT_LENGTH; j++)
{
for (j = 0; j < COMM_SLOT_LENGTH; j++)
queue->slots[i][j] = 0;
}
}
queue->sendSlot = 0;
queue->recvSlot = 0;
@ -351,9 +350,7 @@ static void RfuUnusedQueue_Reset(struct RfuUnusedQueue *queue)
for (i = 0; i < UNUSED_QUEUE_NUM_SLOTS; i++)
{
for (j = 0; j < UNUSED_QUEUE_SLOT_LENGTH; j++)
{
queue->slots[i][j] = 0;
}
}
queue->sendSlot = 0;
queue->recvSlot = 0;
@ -372,21 +369,21 @@ void RfuRecvQueue_Enqueue(struct RfuRecvQueue *queue, u8 *data)
imeBak = REG_IME;
REG_IME = 0;
count = 0;
for (i = 0; i < RECV_QUEUE_SLOT_LENGTH; i += RECV_QUEUE_SLOT_LENGTH / MAX_RFU_PLAYERS)
for (i = 0; i < COMM_SLOT_LENGTH * MAX_RFU_PLAYERS; i += COMM_SLOT_LENGTH)
{
if (data[i] == 0 && data[i + 1] == 0)
count++;
}
if (count != MAX_RFU_PLAYERS)
{
for (i = 0; i < RECV_QUEUE_SLOT_LENGTH; i++)
for (i = 0; i < COMM_SLOT_LENGTH * MAX_RFU_PLAYERS; i++)
queue->slots[queue->recvSlot][i] = data[i];
queue->recvSlot++;
queue->recvSlot %= RECV_QUEUE_NUM_SLOTS;
queue->count++;
for (i = 0; i < RECV_QUEUE_SLOT_LENGTH; i++)
for (i = 0; i < COMM_SLOT_LENGTH * MAX_RFU_PLAYERS; i++)
data[i] = 0;
}
REG_IME = imeBak;
@ -406,22 +403,20 @@ void RfuSendQueue_Enqueue(struct RfuSendQueue *queue, u8 *data)
{
imeBak = REG_IME;
REG_IME = 0;
for (i = 0; i < SEND_QUEUE_SLOT_LENGTH; i++)
for (i = 0; i < COMM_SLOT_LENGTH; i++)
{
if (data[i] != 0)
break;
}
if (i != SEND_QUEUE_SLOT_LENGTH)
if (i != COMM_SLOT_LENGTH)
{
for (i = 0; i < SEND_QUEUE_SLOT_LENGTH; i++)
{
for (i = 0; i < COMM_SLOT_LENGTH; i++)
queue->slots[queue->recvSlot][i] = data[i];
}
queue->recvSlot++;
queue->recvSlot %= SEND_QUEUE_NUM_SLOTS;
queue->count++;
for (i = 0; i < SEND_QUEUE_SLOT_LENGTH; i++)
for (i = 0; i < COMM_SLOT_LENGTH; i++)
data[i] = 0;
}
REG_IME = imeBak;
@ -441,13 +436,13 @@ bool8 RfuRecvQueue_Dequeue(struct RfuRecvQueue *queue, u8 *src)
REG_IME = 0;
if (queue->recvSlot == queue->sendSlot || queue->full)
{
for (i = 0; i < RECV_QUEUE_SLOT_LENGTH; i++)
for (i = 0; i < COMM_SLOT_LENGTH * MAX_RFU_PLAYERS; i++)
src[i] = 0;
REG_IME = imeBak;
return FALSE;
}
for (i = 0; i < RECV_QUEUE_SLOT_LENGTH; i++)
for (i = 0; i < COMM_SLOT_LENGTH * MAX_RFU_PLAYERS; i++)
{
src[i] = queue->slots[queue->sendSlot][i];
}
@ -468,7 +463,7 @@ bool8 RfuSendQueue_Dequeue(struct RfuSendQueue *queue, u8 *src)
imeBak = REG_IME;
REG_IME = 0;
for (i = 0; i < SEND_QUEUE_SLOT_LENGTH; i++)
for (i = 0; i < COMM_SLOT_LENGTH; i++)
src[i] = queue->slots[queue->sendSlot][i];
queue->sendSlot++;
@ -488,7 +483,7 @@ void RfuBackupQueue_Enqueue(struct RfuBackupQueue *queue, const u8 *data)
}
else
{
for (i = 0; i < BACKUP_QUEUE_SLOT_LENGTH; i++)
for (i = 0; i < COMM_SLOT_LENGTH; i++)
queue->slots[queue->recvSlot][i] = data[i];
queue->recvSlot++;
@ -510,7 +505,7 @@ bool8 RfuBackupQueue_Dequeue(struct RfuBackupQueue *queue, u8 *src)
if (src != NULL)
{
for (i = 0; i < BACKUP_QUEUE_SLOT_LENGTH; i++)
for (i = 0; i < COMM_SLOT_LENGTH; i++)
src[i] = queue->slots[queue->sendSlot][i];
}
queue->sendSlot++;
@ -555,46 +550,57 @@ static bool8 RfuUnusedQueue_Dequeue(struct RfuUnusedQueue *queue, u8 *dest)
}
// Unused
static void sub_800DBF8(u8 *q1, u8 mode)
// Populates an array with a sequence of numbers (which numbers depends on the mode)
// and sets the final element to the total of the other elements
#define SEQ_ARRAY_MAX_SIZE 200
static void PopulateArrayWithSequence(u8 *arr, u8 mode)
{
s32 i;
u8 rval;
u16 r5 = 0;
u16 total = 0;
switch (mode)
{
case 0:
for (i = 0; i < 200; i++)
// Populate with numbers 1-200
// Total will be 20100
for (i = 0; i < SEQ_ARRAY_MAX_SIZE; i++)
{
q1[i] = i + 1;
r5 += i + 1;
arr[i] = i + 1;
total += i + 1;
}
*((u16 *)(q1 + i)) = r5;
*((u16 *)(arr + i)) = total;
break;
case 1:
// Populate with numbers 1-100
// Total will be 5050
for (i = 0; i < 100; i++)
{
q1[i] = i + 1;
r5 += i + 1;
arr[i] = i + 1;
total += i + 1;
}
*((u16 *)(q1 + 200)) = r5;
*((u16 *)(arr + SEQ_ARRAY_MAX_SIZE)) = total;
break;
case 2:
for (i = 0; i < 200; i++)
// Populate with random numbers 0-255
// Total will be a number 0-51000
for (i = 0; i < SEQ_ARRAY_MAX_SIZE; i++)
{
rval = Random();
q1[i] = rval;
r5 += rval;
arr[i] = rval;
total += rval;
}
*((u16 *)(q1 + i)) = r5;
*((u16 *)(arr + i)) = total;
break;
case 3:
for (i = 0; i < 200; i++)
// Populate with numbers 1-200 + sSequenceArrayValOffset
// Total will be a number 20100-51000
for (i = 0; i < SEQ_ARRAY_MAX_SIZE; i++)
{
q1[i] = i + 1 + sUnknown_03000D74;
r5 += (i + 1 + sUnknown_03000D74) & 0xFF;
arr[i] = i + 1 + sSequenceArrayValOffset;
total += (i + 1 + sSequenceArrayValOffset) & 0xFF;
}
*((u16 *)(q1 + i)) = r5;
sUnknown_03000D74++;
*((u16 *)(arr + i)) = total;
sSequenceArrayValOffset++;
break;
}
}
@ -606,9 +612,7 @@ static void PkmnStrToASCII(u8 *asciiStr, const u8 *pkmnStr)
s32 i;
for (i = 0; pkmnStr[i] != EOS; i++)
{
asciiStr[i] = sWireless_RSEtoASCIITable[pkmnStr[i]];
}
asciiStr[i] = 0;
}
@ -617,9 +621,7 @@ static void ASCIIToPkmnStr(u8 *pkmnStr, const u8 *asciiStr)
s32 i;
for (i = 0; asciiStr[i] != 0; i++)
{
pkmnStr[i] = sWireless_ASCIItoRSETable[asciiStr[i]];
}
pkmnStr[i] = EOS;
}
@ -655,33 +657,32 @@ static u8 GetConnectedChildStrength(u8 maxFlags)
return 0;
}
void InitHostRFUtgtGname(struct GFtgtGname *data, u8 activity, bool32 started, s32 child_sprite_genders)
void InitHostRfuGameData(struct RfuGameData *data, u8 activity, bool32 startedActivity, s32 partnerInfo)
{
s32 i;
for (i = 0; i < 2; i++)
{
data->unk_00.playerTrainerId[i] = gSaveBlock2Ptr->playerTrainerId[i];
}
for (i = 0; i < (s32)ARRAY_COUNT(data->compatibility.playerTrainerId); i++)
data->compatibility.playerTrainerId[i] = gSaveBlock2Ptr->playerTrainerId[i];
for (i = 0; i < RFU_CHILD_MAX; i++)
{
data->child_sprite_gender[i] = child_sprite_genders;
child_sprite_genders >>= 8;
data->partnerInfo[i] = partnerInfo;
partnerInfo >>= 8; // Each element is 1 byte
}
data->playerGender = gSaveBlock2Ptr->playerGender;
data->activity = activity;
data->started = started;
data->unk_00.language = GAME_LANGUAGE;
data->unk_00.version = GAME_VERSION;
data->unk_00.hasNews = FALSE;
data->unk_00.hasCard = FALSE;
data->unk_00.unknown = FALSE;
data->unk_00.isChampion = FlagGet(FLAG_IS_CHAMPION);
data->unk_00.hasNationalDex = IsNationalPokedexEnabled();
data->unk_00.gameClear = FlagGet(FLAG_SYS_GAME_CLEAR);
data->startedActivity = startedActivity;
data->compatibility.language = GAME_LANGUAGE;
data->compatibility.version = GAME_VERSION;
data->compatibility.hasNews = FALSE;
data->compatibility.hasCard = FALSE;
data->compatibility.unknown = FALSE;
data->compatibility.isChampion = FlagGet(FLAG_IS_CHAMPION);
data->compatibility.hasNationalDex = IsNationalPokedexEnabled();
data->compatibility.gameClear = FlagGet(FLAG_SYS_GAME_CLEAR);
}
bool8 LinkRfu_GetNameIfCompatible(struct GFtgtGname *buff1, u8 *buff2, u8 idx)
bool8 Rfu_GetCompatiblePlayerData(struct RfuGameData *gameData, u8 *username, u8 idx)
{
bool8 retVal;
@ -690,13 +691,13 @@ bool8 LinkRfu_GetNameIfCompatible(struct GFtgtGname *buff1, u8 *buff2, u8 idx)
retVal = TRUE;
if (IsRfuSerialNumberValid(gRfuLinkStatus->partner[idx].serialNo) && ((gRfuLinkStatus->getNameFlag >> idx) & 1))
{
memcpy(buff1, gRfuLinkStatus->partner[idx].gname, RFU_GAME_NAME_LENGTH);
memcpy(buff2, gRfuLinkStatus->partner[idx].uname, PLAYER_NAME_LENGTH + 1);
memcpy(gameData, gRfuLinkStatus->partner[idx].gname, RFU_GAME_NAME_LENGTH);
memcpy(username, gRfuLinkStatus->partner[idx].uname, RFU_USER_NAME_LENGTH);
}
else
{
memset(buff1, 0, RFU_GAME_NAME_LENGTH);
memset(buff2, 0, PLAYER_NAME_LENGTH + 1);
memset(gameData, 0, RFU_GAME_NAME_LENGTH);
memset(username, 0, RFU_USER_NAME_LENGTH);
}
}
else
@ -704,39 +705,39 @@ bool8 LinkRfu_GetNameIfCompatible(struct GFtgtGname *buff1, u8 *buff2, u8 idx)
retVal = FALSE;
if (IsRfuSerialNumberValid(gRfuLinkStatus->partner[idx].serialNo))
{
memcpy(buff1, gRfuLinkStatus->partner[idx].gname, RFU_GAME_NAME_LENGTH);
memcpy(buff2, gRfuLinkStatus->partner[idx].uname, PLAYER_NAME_LENGTH + 1);
memcpy(gameData, gRfuLinkStatus->partner[idx].gname, RFU_GAME_NAME_LENGTH);
memcpy(username, gRfuLinkStatus->partner[idx].uname, RFU_USER_NAME_LENGTH);
}
else
{
memset(buff1, 0, RFU_GAME_NAME_LENGTH);
memset(buff2, 0, PLAYER_NAME_LENGTH + 1);
memset(gameData, 0, RFU_GAME_NAME_LENGTH);
memset(username, 0, RFU_USER_NAME_LENGTH);
}
}
return retVal;
}
bool8 LinkRfu_GetNameIfSerial7F7D(struct GFtgtGname *buff1, u8 *buff2, u8 idx)
bool8 Rfu_GetWonderDistributorPlayerData(struct RfuGameData *gameData, u8 *username, u8 idx)
{
bool8 retVal = FALSE;
if (gRfuLinkStatus->partner[idx].serialNo == RFU_SERIAL_7F7D)
if (gRfuLinkStatus->partner[idx].serialNo == RFU_SERIAL_WONDER_DISTRIBUTOR)
{
memcpy(buff1, gRfuLinkStatus->partner[idx].gname, RFU_GAME_NAME_LENGTH);
memcpy(buff2, gRfuLinkStatus->partner[idx].uname, PLAYER_NAME_LENGTH + 1);
memcpy(gameData, gRfuLinkStatus->partner[idx].gname, RFU_GAME_NAME_LENGTH);
memcpy(username, gRfuLinkStatus->partner[idx].uname, RFU_USER_NAME_LENGTH);
retVal = TRUE;
}
else
{
memset(buff1, 0, RFU_GAME_NAME_LENGTH);
memset(buff2, 0, PLAYER_NAME_LENGTH + 1);
memset(gameData, 0, RFU_GAME_NAME_LENGTH);
memset(username, 0, RFU_USER_NAME_LENGTH);
}
return retVal;
}
void LinkRfu3_SetGnameUnameFromStaticBuffers(struct GFtgtGname *buff1, u8 *buff2)
void CopyHostRfuGameDataAndUsername(struct RfuGameData *gameData, u8 *username)
{
memcpy(buff1, &gHostRFUtgtGnameBuffer, RFU_GAME_NAME_LENGTH);
memcpy(buff2, gHostRFUtgtUnameBuffer, PLAYER_NAME_LENGTH + 1);
memcpy(gameData, &gHostRfuGameData, RFU_GAME_NAME_LENGTH);
memcpy(username, gHostRfuUsername, RFU_USER_NAME_LENGTH);
}
#define sNextAnimNum data[0]
@ -754,8 +755,8 @@ void CreateWirelessStatusIndicatorSprite(u8 x, u8 y)
if (x == 0 && y == 0)
{
x = 0xE7;
y = 0x08;
x = 231;
y = 8;
}
if (gRfuLinkStatus->parentChild == MODE_PARENT)
{
@ -788,9 +789,7 @@ void DestroyWirelessStatusIndicatorSprite(void)
void LoadWirelessStatusIndicatorSpriteGfx(void)
{
if (GetSpriteTileStartByTag(sWirelessStatusIndicatorSpriteSheet.tag) == 0xFFFF)
{
LoadCompressedSpriteSheet(&sWirelessStatusIndicatorSpriteSheet);
}
LoadSpritePalette(&sWirelessStatusIndicatorSpritePalette);
gWirelessStatusIndicatorSpriteId = SPRITE_NONE;
}
@ -802,9 +801,7 @@ static u8 GetParentSignalStrength(void)
for (i = 0; i < RFU_CHILD_MAX; i++)
{
if (flags & 1)
{
return gRfuLinkStatus->strength[i];
}
flags >>= 1;
}
return 0;
@ -827,40 +824,33 @@ void UpdateWirelessStatusIndicatorSprite(void)
struct Sprite *sprite = &gSprites[gWirelessStatusIndicatorSpriteId];
u8 signalStrength = RFU_LINK_ICON_LEVEL4_MAX;
u8 i = 0;
// Get weakest signal strength
if (gRfuLinkStatus->parentChild == MODE_PARENT)
{
for (i = 0; i < GetLinkPlayerCount() - 1; i++)
{
if (signalStrength >= GetConnectedChildStrength(i + 1))
{
signalStrength = GetConnectedChildStrength(i + 1);
}
}
}
else
{
signalStrength = GetParentSignalStrength();
}
// Set signal strength sprite anim number
if (IsRfuRecoveringFromLinkLoss() == TRUE)
{
sprite->sNextAnimNum = WIRELESS_STATUS_ANIM_ERROR;
}
else if (signalStrength <= RFU_LINK_ICON_LEVEL1_MAX)
{
sprite->sNextAnimNum = WIRELESS_STATUS_ANIM_SEARCHING;
}
else if (signalStrength >= RFU_LINK_ICON_LEVEL2_MIN && signalStrength <= RFU_LINK_ICON_LEVEL2_MAX)
{
sprite->sNextAnimNum = WIRELESS_STATUS_ANIM_1_BAR;
}
else if (signalStrength >= RFU_LINK_ICON_LEVEL3_MIN && signalStrength <= RFU_LINK_ICON_LEVEL3_MAX)
{
sprite->sNextAnimNum = WIRELESS_STATUS_ANIM_2_BARS;
}
else if (signalStrength >= RFU_LINK_ICON_LEVEL4_MIN)
{
sprite->sNextAnimNum = WIRELESS_STATUS_ANIM_3_BARS;
}
if (sprite->sNextAnimNum != sprite->sSavedAnimNum)
{
SetWirelessStatusIndicatorAnim(sprite, sprite->sNextAnimNum);
@ -871,9 +861,7 @@ void UpdateWirelessStatusIndicatorSprite(void)
sprite->sFrameIdx++;
sprite->sFrameDelay = 0;
if (sprite->anims[sprite->sCurrAnimNum][sprite->sFrameIdx].type == -2)
{
sprite->sFrameIdx = 0;
}
}
else
{
@ -884,11 +872,9 @@ void UpdateWirelessStatusIndicatorSprite(void)
gMain.oamBuffer[125].y = sprite->y + sprite->centerToCornerVecY;
gMain.oamBuffer[125].paletteNum = sprite->oam.paletteNum;
gMain.oamBuffer[125].tileNum = sprite->sTileStart + sprite->anims[sprite->sCurrAnimNum][sprite->sFrameIdx].frame.imageValue;
CpuCopy16(gMain.oamBuffer + 125, (struct OamData *)OAM + 125, sizeof(struct OamData));
CpuCopy16(&gMain.oamBuffer[125], (struct OamData *)OAM + 125, sizeof(struct OamData));
if (RfuGetStatus() == RFU_STATUS_FATAL_ERROR)
{
DestroyWirelessStatusIndicatorSprite();
}
}
}
@ -919,14 +905,14 @@ static bool32 NameIsNotEmpty(const u8 *name)
}
// Save the currently connected players into the trainer records, shifting all previous records down.
void RecordMixTrainerNames(void)
void SaveLinkTrainerNames(void)
{
if (gWirelessCommType != 0)
{
s32 i;
s32 j;
s32 nextSpace;
s32 connectedTrainerRecordIndices[5];
s32 connectedTrainerRecordIndices[MAX_RFU_PLAYERS];
struct TrainerNameRecord *newRecords = calloc(ARRAY_COUNT(gSaveBlock1Ptr->trainerNameRecords), sizeof(struct TrainerNameRecord));
// Check if we already have a record saved for connected trainers.
@ -936,9 +922,7 @@ void RecordMixTrainerNames(void)
for (j = 0; j < (int)ARRAY_COUNT(gSaveBlock1Ptr->trainerNameRecords); j++)
{
if ((u16)gLinkPlayers[i].trainerId == gSaveBlock1Ptr->trainerNameRecords[j].trainerId && StringCompare(gLinkPlayers[i].name, gSaveBlock1Ptr->trainerNameRecords[j].trainerName) == 0)
{
connectedTrainerRecordIndices[i] = j;
}
}
}
@ -952,9 +936,7 @@ void RecordMixTrainerNames(void)
// If we already had a record for this trainer, wipe it so that the next step doesn't duplicate it.
if (connectedTrainerRecordIndices[i] >= 0)
{
memset(gSaveBlock1Ptr->trainerNameRecords[connectedTrainerRecordIndices[i]].trainerName, 0, 8);
}
memset(gSaveBlock1Ptr->trainerNameRecords[connectedTrainerRecordIndices[i]].trainerName, 0, PLAYER_NAME_LENGTH + 1);
nextSpace++;
}
}
@ -967,9 +949,7 @@ void RecordMixTrainerNames(void)
{
CopyTrainerRecord(&newRecords[nextSpace], gSaveBlock1Ptr->trainerNameRecords[i].trainerId, gSaveBlock1Ptr->trainerNameRecords[i].trainerName);
if (++nextSpace >= (int)ARRAY_COUNT(gSaveBlock1Ptr->trainerNameRecords))
{
break;
}
}
}
@ -1001,6 +981,6 @@ void WipeTrainerNameRecords(void)
for (i = 0; i < (int)ARRAY_COUNT(gSaveBlock1Ptr->trainerNameRecords); i++)
{
gSaveBlock1Ptr->trainerNameRecords[i].trainerId = 0;
CpuFill16(0, gSaveBlock1Ptr->trainerNameRecords[i].trainerName, 8);
CpuFill16(0, gSaveBlock1Ptr->trainerNameRecords[i].trainerName, PLAYER_NAME_LENGTH + 1);
}
}

View File

@ -71,6 +71,7 @@ void ClearSav1(void)
CpuFill16(0, &gSaveblock1, sizeof(struct SaveBlock1) + sizeof(gSaveblock1_DMA));
}
// Offset is the sum of the trainer id bytes
void SetSaveBlocksPointers(u16 offset)
{
struct SaveBlock1** sav1_LocalVar = &gSaveBlock1Ptr;

View File

@ -510,13 +510,9 @@ void MG_DrawCheckerboardPattern(u32 bg)
for (j = 0; j < 32; j++)
{
if ((i & 1) != (j & 1))
{
FillBgTilemapBufferRect(bg, 1, j, i + 2, 1, 1, 0x11);
}
else
{
FillBgTilemapBufferRect(bg, 2, j, i + 2, 1, 1, 0x11);
}
}
}
}
@ -593,10 +589,8 @@ bool32 unref_HideDownArrowAndWaitButton(u8 * textState)
{
case 0:
HideDownArrow();
if (({JOY_NEW(A_BUTTON | B_BUTTON);}))
{
if (JOY_NEW(A_BUTTON | B_BUTTON))
(*textState)++;
}
break;
case 1:
ShowDownArrow();
@ -609,9 +603,8 @@ bool32 unref_HideDownArrowAndWaitButton(u8 * textState)
static bool32 PrintStringAndWait2Seconds(u8 * counter, const u8 * str)
{
if (*counter == 0)
{
AddTextPrinterToWindow1(str);
}
if (++(*counter) > 120)
{
*counter = 0;
@ -632,27 +625,20 @@ static u32 MysteryGift_HandleThreeOptionMenu(u8 * unused0, u16 * unused1, u8 whi
s32 response;
if (whichMenu == 0)
{
listMenuTemplate.items = sListMenuItems_CardsOrNews;
}
else
{
listMenuTemplate.items = sListMenuItems_WirelessOrFriend;
}
width = Intl_GetListMenuWidth(&listMenuTemplate);
if (width & 1)
{
width++;
}
windowTemplate.width = width;
if (width < 30)
{
windowTemplate.tilemapLeft = (30 - width) / 2;
}
else
{
windowTemplate.tilemapLeft = 0;
}
response = DoMysteryGiftListMenu(&windowTemplate, &listMenuTemplate, 1, 0x00A, 0xE0);
if (response != -1)
{
@ -672,13 +658,9 @@ s8 mevent_message_print_and_prompt_yes_no(u8 * textState, u16 * windowId, bool8
case 0:
StringExpandPlaceholders(gStringVar4, str);
if (yesNoBoxPlacement == 0)
{
*windowId = AddWindow(&sWindowTemplate_PromptYesOrNo_Width28);
}
else
{
*windowId = AddWindow(&sWindowTemplate_PromptYesOrNo_Width20);
}
FillWindowPixelBuffer(*windowId, 0x11);
AddTextPrinterParameterized4(*windowId, 1, 0, 1, 0, 0, sMG_Ereader_TextColor_2, 0, gStringVar4);
DrawTextBorderOuter(*windowId, 0x001, 0x0F);
@ -689,19 +671,15 @@ s8 mevent_message_print_and_prompt_yes_no(u8 * textState, u16 * windowId, bool8
case 1:
windowTemplate = sWindowTemplate_YesNoBox;
if (yesNoBoxPlacement == 0)
{
windowTemplate.tilemapTop = 9;
}
else
{
windowTemplate.tilemapTop = 15;
}
CreateYesNoMenu(&windowTemplate, 10, 14, 0);
(*textState)++;
break;
case 2:
input = Menu_ProcessInputNoWrapClearOnChoose();
if (input == -1 || input == 0 || input == 1)
if (input == MENU_B_PRESSED || input == 0 || input == 1)
{
*textState = 0;
rbox_fill_rectangle(*windowId);
@ -711,16 +689,16 @@ s8 mevent_message_print_and_prompt_yes_no(u8 * textState, u16 * windowId, bool8
return input;
}
break;
case 0xFF:
case (u8)MENU_B_PRESSED:
*textState = 0;
rbox_fill_rectangle(*windowId);
ClearWindowTilemap(*windowId);
CopyWindowToVram(*windowId, 1);
RemoveWindow(*windowId);
return -1;
return MENU_B_PRESSED;
}
return -2;
return MENU_NOTHING_CHOSEN;
}
static s32 HandleMysteryGiftListMenu(u8 * textState, u16 * windowId, bool32 cannotToss, bool32 cannotSend)
@ -1237,21 +1215,21 @@ void task00_mystery_gift(u8 taskId)
case 0:
if (data->source == 1)
{
MEvent_CreateTask_CardOrNewsWithFriend(ACTIVITY_WONDER_CARD2);
MEvent_CreateTask_CardOrNewsWithFriend(ACTIVITY_WONDER_CARD);
}
else if (data->source == 0)
{
MEvent_CreateTask_CardOrNewsOverWireless(ACTIVITY_WONDER_CARD2);
MEvent_CreateTask_CardOrNewsOverWireless(ACTIVITY_WONDER_CARD);
}
break;
case 1:
if (data->source == 1)
{
MEvent_CreateTask_CardOrNewsWithFriend(ACTIVITY_WONDER_NEWS2);
MEvent_CreateTask_CardOrNewsWithFriend(ACTIVITY_WONDER_NEWS);
}
else if (data->source == 0)
{
MEvent_CreateTask_CardOrNewsOverWireless(ACTIVITY_WONDER_NEWS2);
MEvent_CreateTask_CardOrNewsOverWireless(ACTIVITY_WONDER_NEWS);
}
break;
}
@ -1594,10 +1572,10 @@ void task00_mystery_gift(u8 taskId)
switch (data->IsCardOrNews)
{
case 0:
MEvent_CreateTask_Leader(ACTIVITY_WONDER_CARD2);
MEvent_CreateTask_Leader(ACTIVITY_WONDER_CARD);
break;
case 1:
MEvent_CreateTask_Leader(ACTIVITY_WONDER_NEWS2);
MEvent_CreateTask_Leader(ACTIVITY_WONDER_NEWS);
break;
}
data->source = 1;

View File

@ -286,19 +286,26 @@ static const struct WindowTemplate sWindowTemplates[WIN_COUNT + 1] =
// This handles what characters get inserted when a key is pressed
// The keys shown on the keyboard are handled separately by sNamingScreenKeyboardText
static const u8 sKeyboardChars[KBPAGE_COUNT * KBROW_COUNT * KBCOL_COUNT] = __(
"abcdef ."
"ghijkl ,"
"mnopqrs "
"tuvwxyz "
"ABCDEF ."
"GHIJKL ,"
"MNOPQRS "
"TUVWXYZ "
"01234 "
"56789 "
"!?♂♀/- "
"…“”‘' ");
static const u8 sKeyboardChars[KBPAGE_COUNT][KBROW_COUNT][KBCOL_COUNT] = {
[KEYBOARD_LETTERS_LOWER] = {
__("abcdef ."),
__("ghijkl ,"),
__("mnopqrs "),
__("tuvwxyz "),
},
[KEYBOARD_LETTERS_UPPER] = {
__("ABCDEF ."),
__("GHIJKL ,"),
__("MNOPQRS "),
__("TUVWXYZ "),
},
[KEYBOARD_SYMBOLS] = {
__("01234 "),
__("56789 "),
__("!?♂♀/- "),
__("…“”‘' "),
}
};
static const u8 sPageColumnCounts[KBPAGE_COUNT] = {
[KEYBOARD_LETTERS_LOWER] = KBCOL_COUNT,
@ -1780,7 +1787,7 @@ static void DrawGenderIcon(void)
static u8 GetCharAtKeyboardPos(s16 x, s16 y)
{
return sKeyboardChars[x + y * KBCOL_COUNT + CurrentPageToKeyboardId() * KBCOL_COUNT * KBROW_COUNT];
return sKeyboardChars[CurrentPageToKeyboardId()][y][x];
}

View File

@ -2898,7 +2898,7 @@ bool32 IsSendingKeysOverCable(void)
static u32 GetLinkSendQueueLength(void)
{
if (gWirelessCommType != 0)
return Rfu.sendQueue.count;
return gRfu.sendQueue.count;
else
return gLink.sendQueue.count;
}

View File

@ -3522,7 +3522,7 @@ static void CursorCb_Register(u8 taskId)
u16 species = GetMonData(&gPlayerParty[gPartyMenu.slotId], MON_DATA_SPECIES);
u8 isEventLegal = GetMonData(&gPlayerParty[gPartyMenu.slotId], MON_DATA_EVENT_LEGAL);
switch (CanRegisterMonForTradingBoard(*(struct GFtgtGnameSub *)GetHostRFUtgtGname(), species2, species, isEventLegal))
switch (CanRegisterMonForTradingBoard(*(struct RfuGameCompatibilityData *)GetHostRfuGameData(), species2, species, isEventLegal))
{
case CANT_REGISTER_MON:
StringExpandPlaceholders(gStringVar4, gText_PkmnCantBeTradedNow);
@ -3548,7 +3548,7 @@ static void CursorCb_Trade1(u8 taskId)
u16 species2 = GetMonData(&gPlayerParty[gPartyMenu.slotId], MON_DATA_SPECIES2);
u16 species = GetMonData(&gPlayerParty[gPartyMenu.slotId], MON_DATA_SPECIES);
u8 isEventLegal = GetMonData(&gPlayerParty[gPartyMenu.slotId], MON_DATA_EVENT_LEGAL);
u32 stringId = GetUnionRoomTradeMessageId(*(struct GFtgtGnameSub *)GetHostRFUtgtGname(), gPartnerTgtGnameSub, species2, gUnionRoomOfferedSpecies, gUnionRoomRequestedMonType, species, isEventLegal);
u32 stringId = GetUnionRoomTradeMessageId(*(struct RfuGameCompatibilityData *)GetHostRfuGameData(), gRfuPartnerCompatibilityData, species2, gUnionRoomOfferedSpecies, gUnionRoomRequestedMonType, species, isEventLegal);
if (stringId != UR_TRADE_MSG_NONE)
{

View File

@ -2202,7 +2202,7 @@ static int GetPlayersAtJumpPeak(void)
static bool32 AreLinkQueuesEmpty(void)
{
return !Rfu.recvQueue.count && !Rfu.sendQueue.count;
return !gRfu.recvQueue.count && !gRfu.sendQueue.count;
}
static int GetNumPlayersForBonus(u8 *arg0)
@ -3945,7 +3945,7 @@ static bool32 RecvPacket_MonInfo(int multiplayerId, struct PokemonJump_MonInfo *
{
struct MonInfoPacket packet;
if ((gRecvCmds[multiplayerId][0] & 0xFF00) != RFUCMD_SEND_PACKET)
if ((gRecvCmds[multiplayerId][0] & RFUCMD_MASK) != RFUCMD_SEND_PACKET)
return FALSE;
memcpy(&packet, &gRecvCmds[multiplayerId][1], sizeof(packet));
@ -4010,7 +4010,7 @@ static bool32 RecvPacket_LeaderState(struct PokemonJump_Player *player, struct P
{
struct LeaderStatePacket packet;
if ((gRecvCmds[0][0] & 0xFF00) != RFUCMD_SEND_PACKET)
if ((gRecvCmds[0][0] & RFUCMD_MASK) != RFUCMD_SEND_PACKET)
return FALSE;
memcpy(&packet, &gRecvCmds[0][1], sizeof(packet));
@ -4057,7 +4057,7 @@ static bool32 RecvPacket_MemberStateToLeader(struct PokemonJump_Player *player,
{
struct MemberStatePacket packet;
if ((gRecvCmds[multiplayerId][0] & 0xFF00) != RFUCMD_SEND_PACKET)
if ((gRecvCmds[multiplayerId][0] & RFUCMD_MASK) != RFUCMD_SEND_PACKET)
return FALSE;
memcpy(&packet, &gRecvCmds[multiplayerId][1], sizeof(packet));
@ -4078,7 +4078,7 @@ static bool32 RecvPacket_MemberStateToMember(struct PokemonJump_Player *player,
{
struct MemberStatePacket packet;
if ((gRecvCmds[multiplayerId][0] & 0xFF00) != RFUCMD_SEND_PACKET)
if ((gRecvCmds[multiplayerId][0] & RFUCMD_MASK) != RFUCMD_SEND_PACKET)
return FALSE;
memcpy(&packet, &gRecvCmds[multiplayerId][1], sizeof(packet));

View File

@ -499,7 +499,7 @@ static void Task_SendPacket(u8 taskId)
break;
case 1:
if (GetMultiplayerId() == 0)
SendBlockRequest(1);
SendBlockRequest(BLOCK_REQ_SIZE_200);
task->data[0]++;
break;
case 2:
@ -981,7 +981,7 @@ static void Task_DoRecordMixing(u8 taskId)
// Mixing Emerald records.
case 6:
if (!sub_801048C(FALSE))
if (!Rfu_SetLinkRecovery(FALSE))
{
CreateTask(Task_LinkSave, 5);
task->data[0]++;
@ -992,7 +992,7 @@ static void Task_DoRecordMixing(u8 taskId)
{
if (gWirelessCommType)
{
sub_801048C(TRUE);
Rfu_SetLinkRecovery(TRUE);
task->data[0] = 8;
}
else

View File

@ -8,17 +8,17 @@
#include "overworld.h"
#include "malloc.h"
void sub_81700F8(void)
// Reloads the game, continuing from the point of the last save
// Used to gracefully exit after a link connection error
void ReloadSave(void)
{
u16 imeBackup;
imeBackup = REG_IME;
u16 imeBackup = REG_IME;
REG_IME = 0;
RegisterRamReset(RESET_EWRAM);
ClearGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_FORCED_BLANK);
REG_IME = imeBackup;
gMain.inBattle = FALSE;
SetSaveBlocksPointers(sub_815355C());
SetSaveBlocksPointers(GetSaveBlocksPointersBaseOffset());
ResetMenuAndMonGlobals();
Save_ResetSaveCounters();
Save_LoadGameData(SAVE_NORMAL);

View File

@ -43,11 +43,12 @@ static u8 HandleWriteSector(u16 a1, const struct SaveSectionLocation *location);
// (u8 *)structure was removed from the first statement of the macro in Emerald.
// This is because malloc is used to allocate addresses so storing the raw
// addresses should not be done in the offsets information.
#define SAVEBLOCK_CHUNK(structure, chunkNum) \
{ \
chunkNum * SECTOR_DATA_SIZE, \
min(sizeof(structure) - chunkNum * SECTOR_DATA_SIZE, SECTOR_DATA_SIZE) \
} \
#define SAVEBLOCK_CHUNK(structure, chunkNum) \
{ \
chunkNum * SECTOR_DATA_SIZE, \
sizeof(structure) >= chunkNum * SECTOR_DATA_SIZE ? \
min(sizeof(structure) - chunkNum * SECTOR_DATA_SIZE, SECTOR_DATA_SIZE) : 0 \
}
static const struct SaveSectionOffsets sSaveSectionOffsets[] =
{
@ -126,16 +127,16 @@ static bool32 SetDamagedSectorBits(u8 op, u8 bit)
return retVal;
}
static u8 SaveWriteToFlash(u16 a1, const struct SaveSectionLocation *location)
static u8 SaveWriteToFlash(u16 sectorId, const struct SaveSectionLocation *location)
{
u32 status;
u16 i;
gFastSaveSection = &gSaveDataBuffer;
if (a1 != 0xFFFF) // for link
if (sectorId != 0xFFFF) // for link
{
status = HandleWriteSector(a1, location);
status = HandleWriteSector(sectorId, location);
}
else
{
@ -169,7 +170,7 @@ static u8 HandleWriteSector(u16 sectorId, const struct SaveSectionLocation *loca
sector = sectorId + gLastWrittenSector;
sector %= SECTOR_SAVE_SLOT_LENGTH;
sector += SECTOR_SAVE_SLOT_LENGTH * (gSaveCounter % 2);
sector += SECTOR_SAVE_SLOT_LENGTH * (gSaveCounter % NUM_SAVE_SLOTS);
data = location[sectorId].data;
size = location[sectorId].size;
@ -292,7 +293,7 @@ static u8 ClearSaveData_2(u16 sectorId, const struct SaveSectionLocation *locati
sector = sectorId + gLastWrittenSector;
sector %= SECTOR_SAVE_SLOT_LENGTH;
sector += SECTOR_SAVE_SLOT_LENGTH * (gSaveCounter % 2);
sector += SECTOR_SAVE_SLOT_LENGTH * (gSaveCounter % NUM_SAVE_SLOTS);
data = location[sectorId].data;
size = location[sectorId].size;
@ -362,7 +363,7 @@ static u8 sav12_xor_get(u16 sectorId, const struct SaveSectionLocation *location
sector = sectorId + gLastWrittenSector; // no sub 1?
sector %= SECTOR_SAVE_SLOT_LENGTH;
sector += SECTOR_SAVE_SLOT_LENGTH * (gSaveCounter % 2);
sector += SECTOR_SAVE_SLOT_LENGTH * (gSaveCounter % NUM_SAVE_SLOTS);
if (ProgramFlashByte(sector, sizeof(struct UnkSaveSection), 0x25))
{
@ -385,7 +386,7 @@ static u8 sub_8152CAC(u16 sectorId, const struct SaveSectionLocation *location)
sector = sectorId + gLastWrittenSector - 1;
sector %= SECTOR_SAVE_SLOT_LENGTH;
sector += SECTOR_SAVE_SLOT_LENGTH * (gSaveCounter % 2);
sector += SECTOR_SAVE_SLOT_LENGTH * (gSaveCounter % NUM_SAVE_SLOTS);
if (ProgramFlashByte(sector, sizeof(struct UnkSaveSection), ((u8 *)gFastSaveSection)[sizeof(struct UnkSaveSection)]))
{
@ -408,7 +409,7 @@ static u8 sub_8152D44(u16 sectorId, const struct SaveSectionLocation *location)
sector = sectorId + gLastWrittenSector - 1; // no sub 1?
sector %= SECTOR_SAVE_SLOT_LENGTH;
sector += SECTOR_SAVE_SLOT_LENGTH * (gSaveCounter % 2);
sector += SECTOR_SAVE_SLOT_LENGTH * (gSaveCounter % NUM_SAVE_SLOTS);
if (ProgramFlashByte(sector, sizeof(struct UnkSaveSection), 0x25))
{
@ -446,12 +447,12 @@ static u8 sub_8152E10(u16 a1, const struct SaveSectionLocation *location)
{
u16 i;
u16 checksum;
u16 v3 = SECTOR_SAVE_SLOT_LENGTH * (gSaveCounter % 2);
u16 slotOffset = SECTOR_SAVE_SLOT_LENGTH * (gSaveCounter % NUM_SAVE_SLOTS);
u16 id;
for (i = 0; i < SECTOR_SAVE_SLOT_LENGTH; i++)
{
DoReadFlashWholeSection(i + v3, gFastSaveSection);
DoReadFlashWholeSection(i + slotOffset, gFastSaveSection);
id = gFastSaveSection->id;
if (id == 0)
gLastWrittenSector = i;
@ -824,27 +825,29 @@ u8 Save_LoadGameData(u8 saveType)
return status;
}
u16 sub_815355C(void)
u16 GetSaveBlocksPointersBaseOffset(void)
{
u16 i, v3;
u16 i, slotOffset;
struct SaveSection* savSection;
savSection = gFastSaveSection = &gSaveDataBuffer;
if (gFlashMemoryPresent != TRUE)
return SAVE_STATUS_EMPTY;
return 0;
UpdateSaveAddresses();
GetSaveValidStatus(gRamSaveSectionLocations);
v3 = SECTOR_SAVE_SLOT_LENGTH * (gSaveCounter % 2);
slotOffset = SECTOR_SAVE_SLOT_LENGTH * (gSaveCounter % NUM_SAVE_SLOTS);
for (i = 0; i < SECTOR_SAVE_SLOT_LENGTH; i++)
{
DoReadFlashWholeSection(i + v3, gFastSaveSection);
if (gFastSaveSection->id == 0)
return savSection->data[10] +
savSection->data[11] +
savSection->data[12] +
savSection->data[13];
DoReadFlashWholeSection(i + slotOffset, gFastSaveSection);
// Base offset for SaveBlock2 is calculated using the trainer id
if (gFastSaveSection->id == SECTOR_ID_SAVEBLOCK2)
return savSection->data[offsetof(struct SaveBlock2, playerTrainerId[0])] +
savSection->data[offsetof(struct SaveBlock2, playerTrainerId[1])] +
savSection->data[offsetof(struct SaveBlock2, playerTrainerId[2])] +
savSection->data[offsetof(struct SaveBlock2, playerTrainerId[3])];
}
return SAVE_STATUS_EMPTY;
return 0;
}
u32 TryReadSpecialSaveSection(u8 sector, u8* dst)

View File

@ -274,7 +274,7 @@ static bool32 IsLinkTradeTaskFinished(void)
{
if (gPlayerCurrActivity == ACTIVITY_29)
{
if (gRfuSlotStatusNI[sub_800E87C(lman.acceptSlot_flag)]->send.state == 0)
if (gRfuSlotStatusNI[Rfu_GetIndexOfNewestChild(lman.acceptSlot_flag)]->send.state == 0)
return TRUE;
else
return FALSE;
@ -459,7 +459,7 @@ static void CB2_CreateTradeMenu(void)
sTradeMenuData->timer = 0;
if (gWirelessCommType)
{
sub_801048C(TRUE);
Rfu_SetLinkRecovery(TRUE);
SetLinkStandbyCallback();
}
}
@ -1008,9 +1008,7 @@ static bool8 BufferTradeParties(void)
break;
case 3:
if (id == 0)
{
RequestLinkData(1);
}
RequestLinkData(BLOCK_REQ_SIZE_200);
sTradeMenuData->bufferPartyState++;
break;
case 4:
@ -1027,9 +1025,7 @@ static bool8 BufferTradeParties(void)
break;
case 7:
if (id == 0)
{
RequestLinkData(1);
}
RequestLinkData(BLOCK_REQ_SIZE_200);
sTradeMenuData->bufferPartyState++;
break;
case 8:
@ -1046,9 +1042,7 @@ static bool8 BufferTradeParties(void)
break;
case 11:
if (id == 0)
{
RequestLinkData(1);
}
RequestLinkData(BLOCK_REQ_SIZE_200);
sTradeMenuData->bufferPartyState++;
break;
case 12:
@ -1065,9 +1059,7 @@ static bool8 BufferTradeParties(void)
break;
case 15:
if (id == 0)
{
RequestLinkData(3);
}
RequestLinkData(BLOCK_REQ_SIZE_220);
sTradeMenuData->bufferPartyState++;
break;
case 16:
@ -1084,9 +1076,7 @@ static bool8 BufferTradeParties(void)
break;
case 19:
if (id == 0)
{
RequestLinkData(4);
}
RequestLinkData(BLOCK_REQ_SIZE_40);
sTradeMenuData->bufferPartyState++;
break;
case 20:
@ -1719,7 +1709,7 @@ static void CancelTrade_2(void)
static void LinkTradeWaitForQueue(void)
{
if (!sub_801048C(FALSE) && GetNumQueuedActions() == 0)
if (!Rfu_SetLinkRecovery(FALSE) && GetNumQueuedActions() == 0)
{
SetLinkStandbyCallback();
sTradeMenuData->tradeMenuFunc = TRADEMENUFUNC_START_LINK_TRADE;
@ -2448,80 +2438,70 @@ static bool32 IsDeoxysOrMewUntradable(u16 species, bool8 isEventLegal)
return FALSE;
}
int GetUnionRoomTradeMessageId(struct GFtgtGnameSub rfuPlayer, struct GFtgtGnameSub rfuPartner, u16 playerSpecies2, u16 partnerSpecies, u8 requestedType, u16 playerSpecies, u8 isEventLegal)
int GetUnionRoomTradeMessageId(struct RfuGameCompatibilityData player, struct RfuGameCompatibilityData partner, u16 playerSpecies2, u16 partnerSpecies, u8 requestedType, u16 playerSpecies, u8 isEventLegal)
{
bool8 playerHasNationalDex = rfuPlayer.hasNationalDex;
bool8 playerIsChampion = rfuPlayer.isChampion;
bool8 partnerHasNationalDex = rfuPartner.hasNationalDex;
bool8 partnerIsChampion = rfuPartner.isChampion;
u8 r1 = rfuPartner.version;
bool8 playerHasNationalDex = player.hasNationalDex;
bool8 playerIsChampion = player.isChampion;
bool8 partnerHasNationalDex = partner.hasNationalDex;
bool8 partnerIsChampion = partner.isChampion;
u8 partnerVersion = partner.version;
if (r1 != VERSION_EMERALD)
// If partner is not using Emerald, both players must be champion
if (partnerVersion != VERSION_EMERALD)
{
if (!playerIsChampion)
{
return UR_TRADE_MSG_CANT_TRADE_WITH_PARTNER_1;
}
else if (!partnerIsChampion)
{
return UR_TRADE_MSG_CANT_TRADE_WITH_PARTNER_2;
}
}
// Cannot trade illegitimate Deoxys/Mew
if (IsDeoxysOrMewUntradable(playerSpecies, isEventLegal))
{
return UR_TRADE_MSG_MON_CANT_BE_TRADED_2;
}
if (partnerSpecies == SPECIES_EGG)
{
// If partner is trading an Egg then the player must also be trading an Egg
if (playerSpecies2 != partnerSpecies)
{
return UR_TRADE_MSG_NOT_EGG;
}
}
else
{
if (gBaseStats[playerSpecies2].type1 != requestedType && gBaseStats[playerSpecies2].type2 != requestedType)
{
// Player's Pokémon must be of the type the partner requested
if (gBaseStats[playerSpecies2].type1 != requestedType
&& gBaseStats[playerSpecies2].type2 != requestedType)
return UR_TRADE_MSG_NOT_MON_PARTNER_WANTS;
}
}
// If the player is trading an Egg then the partner must also be trading an Egg
// Odd that this wasn't checked earlier, as by this point we know either the partner doesn't have an Egg or that both do.
if (playerSpecies2 == SPECIES_EGG && playerSpecies2 != partnerSpecies)
{
return UR_TRADE_MSG_MON_CANT_BE_TRADED_1;
}
// If the player doesn't have the National Dex then Eggs and non-Hoenn Pokémon can't be traded
if (!playerHasNationalDex)
{
if (playerSpecies2 == SPECIES_EGG)
{
return UR_TRADE_MSG_EGG_CANT_BE_TRADED;
}
if (!IsSpeciesInHoennDex(playerSpecies2))
{
return UR_TRADE_MSG_MON_CANT_BE_TRADED_2;
}
if (!IsSpeciesInHoennDex(partnerSpecies))
{
return UR_TRADE_MSG_PARTNERS_MON_CANT_BE_TRADED;
}
}
// If the partner doesn't have the National Dex then the player's offer has to be a Hoenn Pokémon
if (!partnerHasNationalDex && !IsSpeciesInHoennDex(playerSpecies2))
{
return UR_TRADE_MSG_PARTNER_CANT_ACCEPT_MON;
}
// Trade is allowed
return UR_TRADE_MSG_NONE;
}
int CanRegisterMonForTradingBoard(struct GFtgtGnameSub rfuPlayer, u16 species2, u16 species, u8 isEventLegal)
int CanRegisterMonForTradingBoard(struct RfuGameCompatibilityData player, u16 species2, u16 species, u8 isEventLegal)
{
bool8 hasNationalDex = rfuPlayer.hasNationalDex;
bool8 hasNationalDex = player.hasNationalDex;
if (IsDeoxysOrMewUntradable(species, isEventLegal))
return CANT_REGISTER_MON;
@ -2551,9 +2531,7 @@ int CanSpinTradeMon(struct Pokemon *mon, u16 monIdx)
{
speciesArray[i] = GetMonData(&mon[i], MON_DATA_SPECIES2);
if (speciesArray[i] == SPECIES_EGG)
{
speciesArray[i] = SPECIES_NONE;
}
}
versions = 0;
@ -2563,13 +2541,9 @@ int CanSpinTradeMon(struct Pokemon *mon, u16 monIdx)
version = gLinkPlayers[i].version & 0xFF;
if (version == VERSION_FIRE_RED ||
version == VERSION_LEAF_GREEN)
{
versions = 0;
}
else
{
versions |= 1;
}
}
for (i = 0; i < GetLinkPlayerCount(); i++)
@ -2600,9 +2574,7 @@ int CanSpinTradeMon(struct Pokemon *mon, u16 monIdx)
for (i = 0; i < gPlayerPartyCount; i++)
{
if (monIdx != i)
{
numMonsLeft += speciesArray[i];
}
}
if (!numMonsLeft)
@ -3096,7 +3068,7 @@ static void TrySendTradeFinishData(void)
case 1:
if (IsLinkTaskFinished())
{
SendBlock(bitmask_all_link_players_but_self(), sTradeData->linkData, sizeof(sTradeData->linkData));
SendBlock(BitmaskAllOtherLinkPlayers(), sTradeData->linkData, sizeof(sTradeData->linkData));
sTradeData->sendTradeFinishState++;
}
// fallthrough
@ -4632,7 +4604,7 @@ static void CB2_TryFinishTrade(void)
&& sTradeData->partnerLinkFlagFinishTrade == READY_FINISH_TRADE)
{
sTradeData->linkData[0] = LINKCMD_CONFIRM_FINISH_TRADE;
SendBlock(bitmask_all_link_players_but_self(), sTradeData->linkData, sizeof(sTradeData->linkData));
SendBlock(BitmaskAllOtherLinkPlayers(), sTradeData->linkData, sizeof(sTradeData->linkData));
sTradeData->playerLinkFlagFinishTrade = FINISH_TRADE;
sTradeData->partnerLinkFlagFinishTrade = FINISH_TRADE;
}

File diff suppressed because it is too large Load Diff

View File

@ -997,7 +997,7 @@ static void Chat_Join(void)
sChat->funcState++;
// fall through
case 1:
if (IsLinkTaskFinished() && !sub_8011A9C())
if (IsLinkTaskFinished() && !Rfu_IsPlayerExchangeActive())
{
if (SendBlock(0, sChat->sendMessageBuffer, sizeof(sChat->sendMessageBuffer)))
sChat->funcState++;
@ -1198,7 +1198,7 @@ static void Chat_AskQuitChatting(void)
sChat->funcState = 3;
break;
case 0:
sub_80104B0();
Rfu_StopPartnerSearch();
PrepareSendBuffer_Disband(sChat->sendMessageBuffer);
sChat->funcState = 4;
sChat->tryQuitAgainTimer = 0;
@ -1206,7 +1206,7 @@ static void Chat_AskQuitChatting(void)
}
break;
case 4:
if (IsLinkTaskFinished() && !sub_8011A9C() && SendBlock(0, sChat->sendMessageBuffer, sizeof(sChat->sendMessageBuffer)))
if (IsLinkTaskFinished() && !Rfu_IsPlayerExchangeActive() && SendBlock(0, sChat->sendMessageBuffer, sizeof(sChat->sendMessageBuffer)))
{
if (!sChat->multiplayerId)
sChat->funcState = 6;
@ -1257,15 +1257,15 @@ static void Chat_Exit(void)
}
break;
case 3:
if (IsLinkTaskFinished() && !sub_8011A9C() && SendBlock(0, sChat->sendMessageBuffer, sizeof(sChat->sendMessageBuffer)))
if (IsLinkTaskFinished() && !Rfu_IsPlayerExchangeActive() && SendBlock(0, sChat->sendMessageBuffer, sizeof(sChat->sendMessageBuffer)))
sChat->funcState++;
break;
case 4:
if ((GetBlockReceivedStatus() & 1) && !sub_8011A9C())
if ((GetBlockReceivedStatus() & 1) && !Rfu_IsPlayerExchangeActive())
sChat->funcState++;
break;
case 5:
if (IsLinkTaskFinished() && !sub_8011A9C())
if (IsLinkTaskFinished() && !Rfu_IsPlayerExchangeActive())
{
SetCloseLinkCallback();
sChat->exitDelayTimer = 0;
@ -1300,7 +1300,7 @@ static void Chat_Drop(void)
}
break;
case 1:
if (!IsDisplaySubtaskActive(0) && IsLinkTaskFinished() && !sub_8011A9C())
if (!IsDisplaySubtaskActive(0) && IsLinkTaskFinished() && !Rfu_IsPlayerExchangeActive())
{
SetCloseLinkCallback();
sChat->exitDelayTimer = 0;
@ -1346,7 +1346,7 @@ static void Chat_Disbanded(void)
}
break;
case 2:
if (IsDisplaySubtaskActive(0) != TRUE && IsLinkTaskFinished() && !sub_8011A9C())
if (IsDisplaySubtaskActive(0) != TRUE && IsLinkTaskFinished() && !Rfu_IsPlayerExchangeActive())
{
SetCloseLinkCallback();
sChat->exitDelayTimer = 0;
@ -1384,7 +1384,7 @@ static void Chat_SendMessage(void)
sChat->funcState++;
// fall through
case 1:
if (IsLinkTaskFinished() == TRUE && !sub_8011A9C() && SendBlock(0, sChat->sendMessageBuffer, sizeof(sChat->sendMessageBuffer)))
if (IsLinkTaskFinished() == TRUE && !Rfu_IsPlayerExchangeActive() && SendBlock(0, sChat->sendMessageBuffer, sizeof(sChat->sendMessageBuffer)))
sChat->funcState++;
break;
case 2:
@ -1819,7 +1819,7 @@ static void PrepareSendBuffer_Leave(u8 *buffer)
buffer[0] = CHAT_MESSAGE_LEAVE;
StringCopy(&buffer[1], gSaveBlock2Ptr->playerName);
buffer[1 + (PLAYER_NAME_LENGTH + 1)] = sChat->multiplayerId;
sub_8011A50();
RfuSetNormalDisconnectMode();
}
static void PrepareSendBuffer_Drop(u8 *buffer)
@ -2028,7 +2028,7 @@ static void Task_ReceiveChatMessage(u8 taskId)
}
tBlockReceivedStatus = GetBlockReceivedStatus();
if (!tBlockReceivedStatus && sub_8011A9C())
if (!tBlockReceivedStatus && Rfu_IsPlayerExchangeActive())
return;
tI = 0;
@ -2079,13 +2079,12 @@ static void Task_ReceiveChatMessage(u8 taskId)
{
if (GetLinkPlayerCount() == 2)
{
sub_80104B0();
Rfu_StopPartnerSearch();
sChat->exitType = 1;
DestroyTask(taskId);
return;
}
sub_8011DE0(tCurrLinkPlayer);
Rfu_DisconnectPlayerById(tCurrLinkPlayer);
}
tState = 3;
@ -2101,10 +2100,10 @@ static void Task_ReceiveChatMessage(u8 taskId)
DestroyTask(taskId);
break;
case 2:
if (!sub_8011A9C())
if (!Rfu_IsPlayerExchangeActive())
{
if (!sChat->multiplayerId)
sub_80110B8(sChat->linkPlayerCount);
SetUnionRoomChatPlayerData(sChat->linkPlayerCount);
tState = 1;
}

View File

@ -9,8 +9,12 @@
#include "constants/event_objects.h"
#include "constants/event_object_movement.h"
#define UR_SPRITE_START_ID (MAX_SPRITES - MAX_UNION_ROOM_PLAYERS)
#define UR_PLAYER_SPRITE_ID(playerIdx, facingDir)(5 * playerIdx + facingDir)
#define UR_SPRITE_START_ID (MAX_SPRITES - MAX_UNION_ROOM_LEADERS)
// Each parent player can lead a group of up to MAX_RFU_PLAYERS (including themselves).
// Multiply the leader's id by MAX_RFU_PLAYERS and add the member's id (0 if the leader) to
// get the sprite index of that player.
#define UR_PLAYER_SPRITE_ID(leaderId, memberId)(MAX_RFU_PLAYERS * leaderId + memberId)
static EWRAM_DATA struct UnionRoomObject * sUnionObjWork = NULL;
static EWRAM_DATA u32 sUnionObjRefreshTimer = 0;
@ -19,7 +23,8 @@ static u8 CreateTask_AnimateUnionRoomPlayers(void);
static u32 IsUnionRoomPlayerInvisible(u32, u32);
static void SetUnionRoomObjectFacingDirection(s32, s32, u8);
static const u8 sUnionRoomObjGfxIds[GENDER_COUNT][MAX_UNION_ROOM_PLAYERS + 2] = {
// + 2 is just to match, those elements are empty and never read
static const u8 sUnionRoomObjGfxIds[GENDER_COUNT][MAX_UNION_ROOM_LEADERS + 2] = {
[MALE] = {
OBJ_EVENT_GFX_MAN_3,
OBJ_EVENT_GFX_BLACK_BELT,
@ -42,7 +47,7 @@ static const u8 sUnionRoomObjGfxIds[GENDER_COUNT][MAX_UNION_ROOM_PLAYERS + 2] =
}
};
static const s16 sUnionRoomPlayerCoords[MAX_UNION_ROOM_PLAYERS][2] = {
static const s16 sUnionRoomPlayerCoords[MAX_UNION_ROOM_LEADERS][2] = {
{ 4, 6},
{13, 8},
{10, 6},
@ -53,12 +58,16 @@ static const s16 sUnionRoomPlayerCoords[MAX_UNION_ROOM_PLAYERS][2] = {
{ 7, 8}
};
static const s8 sFacingDirectionOffsets[][2] = {
[DIR_NONE] = { 0, 0},
[DIR_SOUTH] = { 1, 0},
[DIR_NORTH] = { 0, -1},
[DIR_WEST] = {-1, 0},
[DIR_EAST] = { 0, 1}
// If there's a group of players interacting in the Union Room, the group
// leader will be at one of the positions above and each member in the group
// will be at one of the offsets from that position below. The leader will
// be at the first offset (0,0), as they're at the center.
static const s8 sUnionRoomGroupOffsets[MAX_RFU_PLAYERS][2] = {
{ 0, 0}, // Center
{ 1, 0}, // Left
{ 0, -1}, // Top
{-1, 0}, // Right
{ 0, 1} // Bottom
};
static const u8 sOppositeFacingDirection[] = {
@ -69,12 +78,14 @@ static const u8 sOppositeFacingDirection[] = {
[DIR_EAST] = DIR_WEST
};
static const u8 sNextFacingDirection[] = {
[DIR_NONE] = DIR_SOUTH,
[DIR_SOUTH] = DIR_WEST,
[DIR_NORTH] = DIR_SOUTH,
[DIR_WEST] = DIR_EAST,
[DIR_EAST] = DIR_NORTH
// Compare to sUnionRoomGroupOffsets, the direction each group member
// needs to be facing in order to face the group leader in the center.
static const u8 sMemberFacingDirections[MAX_RFU_PLAYERS] = {
DIR_SOUTH, // Leader, but never read
DIR_WEST,
DIR_SOUTH,
DIR_EAST,
DIR_NORTH
};
static const u8 sUnionRoomLocalIds[] = {
@ -118,21 +129,22 @@ static bool32 IsPlayerStandingStill(void)
return FALSE;
}
// Gender and trainer id are used to determine which sprite a player appears as
static u8 GetUnionRoomPlayerGraphicsId(u32 gender, u32 id)
{
return sUnionRoomObjGfxIds[gender][id % MAX_UNION_ROOM_PLAYERS];
return sUnionRoomObjGfxIds[gender][id % MAX_UNION_ROOM_LEADERS];
}
static void GetUnionRoomPlayerFacingCoords(u32 playerIdx, u32 direction, s32 * x, s32 * y)
static void GetUnionRoomPlayerCoords(u32 leaderId, u32 memberId, s32 * x, s32 * y)
{
*x = sUnionRoomPlayerCoords[playerIdx][0] + sFacingDirectionOffsets[direction][0] + 7;
*y = sUnionRoomPlayerCoords[playerIdx][1] + sFacingDirectionOffsets[direction][1] + 7;
*x = sUnionRoomPlayerCoords[leaderId][0] + sUnionRoomGroupOffsets[memberId][0] + 7;
*y = sUnionRoomPlayerCoords[leaderId][1] + sUnionRoomGroupOffsets[memberId][1] + 7;
}
static bool32 IsUnionRoomPlayerFacingTileAt(u32 playerIdx, u32 direction, s32 x, s32 y)
static bool32 IsUnionRoomPlayerAt(u32 leaderId, u32 memberId, s32 x, s32 y)
{
if ((sUnionRoomPlayerCoords[playerIdx][0] + sFacingDirectionOffsets[direction][0] + 7 == x)
&& (sUnionRoomPlayerCoords[playerIdx][1] + sFacingDirectionOffsets[direction][1] + 7 == y))
if ((sUnionRoomPlayerCoords[leaderId][0] + sUnionRoomGroupOffsets[memberId][0] + 7 == x)
&& (sUnionRoomPlayerCoords[leaderId][1] + sUnionRoomGroupOffsets[memberId][1] + 7 == y))
return TRUE;
else
return FALSE;
@ -153,62 +165,50 @@ static void ShowUnionRoomPlayer(u32 player_idx)
FlagClear(FLAG_HIDE_UNION_ROOM_PLAYER_1 + player_idx);
}
static void SetUnionRoomPlayerGfx(u32 playerIdx, u32 gfxId)
static void SetUnionRoomPlayerGfx(u32 leaderId, u32 gfxId)
{
VarSet(VAR_OBJ_GFX_ID_0 + playerIdx, gfxId);
VarSet(VAR_OBJ_GFX_ID_0 + leaderId, gfxId);
}
static void CreateUnionRoomPlayerObjectEvent(u32 playerIdx)
static void CreateUnionRoomPlayerObjectEvent(u32 leaderId)
{
TrySpawnObjectEvent(sUnionRoomLocalIds[playerIdx], gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup);
TrySpawnObjectEvent(sUnionRoomLocalIds[leaderId], gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup);
}
static void RemoveUnionRoomPlayerObjectEvent(u32 playerIdx)
static void RemoveUnionRoomPlayerObjectEvent(u32 leaderId)
{
RemoveObjectEventByLocalIdAndMap(sUnionRoomLocalIds[playerIdx], gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup);
RemoveObjectEventByLocalIdAndMap(sUnionRoomLocalIds[leaderId], gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup);
}
static bool32 SetUnionRoomPlayerEnterExitMovement(u32 playerIdx, const u8 * movement)
static bool32 SetUnionRoomPlayerEnterExitMovement(u32 leaderId, const u8 * movement)
{
u8 objectId;
struct ObjectEvent * object;
if (TryGetObjectEventIdByLocalIdAndMap(sUnionRoomLocalIds[playerIdx], gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, &objectId))
{
if (TryGetObjectEventIdByLocalIdAndMap(sUnionRoomLocalIds[leaderId], gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, &objectId))
return FALSE;
}
object = &gObjectEvents[objectId];
if (ObjectEventIsMovementOverridden(object))
{
return FALSE;
}
if (ObjectEventSetHeldMovement(object, *movement))
{
return FALSE;
}
return TRUE;
}
static bool32 TryReleaseUnionRoomPlayerObjectEvent(u32 playerIdx)
static bool32 TryReleaseUnionRoomPlayerObjectEvent(u32 leaderId)
{
u8 objectId;
struct ObjectEvent * object;
if (TryGetObjectEventIdByLocalIdAndMap(sUnionRoomLocalIds[playerIdx], gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, &objectId))
{
if (TryGetObjectEventIdByLocalIdAndMap(sUnionRoomLocalIds[leaderId], gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, &objectId))
return TRUE;
}
object = &gObjectEvents[objectId];
if (!ObjectEventClearHeldMovementIfFinished(object))
{
return FALSE;
}
if (!ScriptContext2_IsEnabled())
{
UnfreezeObjectEvent(object);
}
else
{
FreezeObjectEvent(object);
}
return TRUE;
}
@ -218,7 +218,7 @@ u8 InitUnionRoomPlayerObjects(struct UnionRoomObject * players)
sUnionObjRefreshTimer = 0;
sUnionObjWork = players;
for (i = 0; i < MAX_UNION_ROOM_PLAYERS; i++)
for (i = 0; i < MAX_UNION_ROOM_LEADERS; i++)
{
players[i].state = 0;
players[i].gfxId = 0;
@ -228,22 +228,22 @@ u8 InitUnionRoomPlayerObjects(struct UnionRoomObject * players)
return CreateTask_AnimateUnionRoomPlayers();
}
static bool32 AnimateUnionRoomPlayerDespawn(s8 * state, u32 playerIdx, struct UnionRoomObject * ptr)
static bool32 AnimateUnionRoomPlayerDespawn(s8 * state, u32 leaderId, struct UnionRoomObject * object)
{
switch (*state)
{
case 0:
if (SetUnionRoomPlayerEnterExitMovement(playerIdx, sMovement_UnionPlayerExit) == TRUE)
if (SetUnionRoomPlayerEnterExitMovement(leaderId, sMovement_UnionPlayerExit) == TRUE)
{
HideUnionRoomPlayer(playerIdx);
HideUnionRoomPlayer(leaderId);
(*state)++;
}
break;
case 1:
if (TryReleaseUnionRoomPlayerObjectEvent(playerIdx))
if (TryReleaseUnionRoomPlayerObjectEvent(leaderId))
{
RemoveUnionRoomPlayerObjectEvent(playerIdx);
HideUnionRoomPlayer(playerIdx);
RemoveUnionRoomPlayerObjectEvent(leaderId);
HideUnionRoomPlayer(leaderId);
*state = 0;
return TRUE;
}
@ -252,7 +252,7 @@ static bool32 AnimateUnionRoomPlayerDespawn(s8 * state, u32 playerIdx, struct Un
return FALSE;
}
static bool32 AnimateUnionRoomPlayerSpawn(s8 * state, u32 playerIdx, struct UnionRoomObject * ptr)
static bool32 AnimateUnionRoomPlayerSpawn(s8 * state, u32 leaderId, struct UnionRoomObject * object)
{
s16 x, y;
@ -260,32 +260,24 @@ static bool32 AnimateUnionRoomPlayerSpawn(s8 * state, u32 playerIdx, struct Unio
{
case 0:
if (!IsPlayerStandingStill())
{
break;
}
PlayerGetDestCoords(&x, &y);
if (IsUnionRoomPlayerFacingTileAt(playerIdx, 0, x, y) == TRUE)
{
if (IsUnionRoomPlayerAt(leaderId, 0, x, y) == TRUE)
break;
}
player_get_pos_including_state_based_drift(&x, &y);
if (IsUnionRoomPlayerFacingTileAt(playerIdx, 0, x, y) == TRUE)
{
if (IsUnionRoomPlayerAt(leaderId, 0, x, y) == TRUE)
break;
}
SetUnionRoomPlayerGfx(playerIdx, ptr->gfxId);
CreateUnionRoomPlayerObjectEvent(playerIdx);
ShowUnionRoomPlayer(playerIdx);
SetUnionRoomPlayerGfx(leaderId, object->gfxId);
CreateUnionRoomPlayerObjectEvent(leaderId);
ShowUnionRoomPlayer(leaderId);
(*state)++;
// fallthrough
case 3: // incorrect?
if (SetUnionRoomPlayerEnterExitMovement(playerIdx, sMovement_UnionPlayerEnter) == TRUE)
{
if (SetUnionRoomPlayerEnterExitMovement(leaderId, sMovement_UnionPlayerEnter) == TRUE)
(*state)++;
}
break;
case 2:
if (TryReleaseUnionRoomPlayerObjectEvent(playerIdx))
if (TryReleaseUnionRoomPlayerObjectEvent(leaderId))
{
*state = 0;
return TRUE;
@ -295,38 +287,38 @@ static bool32 AnimateUnionRoomPlayerSpawn(s8 * state, u32 playerIdx, struct Unio
return FALSE;
}
static bool32 SpawnGroupLeader(u32 playerIdx, u32 gender, u32 id)
static bool32 SpawnGroupLeader(u32 leaderId, u32 gender, u32 id)
{
struct UnionRoomObject * ptr = &sUnionObjWork[playerIdx];
ptr->schedAnim = UNION_ROOM_SPAWN_IN;
ptr->gfxId = GetUnionRoomPlayerGraphicsId(gender, id);
struct UnionRoomObject * object = &sUnionObjWork[leaderId];
object->schedAnim = UNION_ROOM_SPAWN_IN;
object->gfxId = GetUnionRoomPlayerGraphicsId(gender, id);
if (ptr->state == 0)
if (object->state == 0)
return TRUE;
else
return FALSE;
}
static bool32 DespawnGroupLeader(u32 playerIdx)
static bool32 DespawnGroupLeader(u32 leaderId)
{
struct UnionRoomObject * ptr = &sUnionObjWork[playerIdx];
ptr->schedAnim = UNION_ROOM_SPAWN_OUT;
struct UnionRoomObject * object = &sUnionObjWork[leaderId];
object->schedAnim = UNION_ROOM_SPAWN_OUT;
if (ptr->state == 1)
if (object->state == 1)
return TRUE;
else
return FALSE;
}
static void AnimateUnionRoomPlayer(u32 playerIdx, struct UnionRoomObject * ptr)
static void AnimateUnionRoomPlayer(u32 leaderId, struct UnionRoomObject * object)
{
switch (ptr->state)
switch (object->state)
{
case 0:
if (ptr->schedAnim == UNION_ROOM_SPAWN_IN)
if (object->schedAnim == UNION_ROOM_SPAWN_IN)
{
ptr->state = 2;
ptr->animState = 0;
object->state = 2;
object->animState = 0;
}
else
{
@ -334,23 +326,23 @@ static void AnimateUnionRoomPlayer(u32 playerIdx, struct UnionRoomObject * ptr)
}
// fallthrough
case 2:
if (!IsUnionRoomPlayerInvisible(playerIdx, 0) && ptr->schedAnim == UNION_ROOM_SPAWN_OUT)
if (!IsUnionRoomPlayerInvisible(leaderId, 0) && object->schedAnim == UNION_ROOM_SPAWN_OUT)
{
ptr->state = 0;
ptr->animState = 0;
RemoveUnionRoomPlayerObjectEvent(playerIdx);
HideUnionRoomPlayer(playerIdx);
object->state = 0;
object->animState = 0;
RemoveUnionRoomPlayerObjectEvent(leaderId);
HideUnionRoomPlayer(leaderId);
}
else if (AnimateUnionRoomPlayerSpawn(&ptr->animState, playerIdx, ptr) == TRUE)
else if (AnimateUnionRoomPlayerSpawn(&object->animState, leaderId, object) == TRUE)
{
ptr->state = 1;
object->state = 1;
}
break;
case 1:
if (ptr->schedAnim == UNION_ROOM_SPAWN_OUT)
if (object->schedAnim == UNION_ROOM_SPAWN_OUT)
{
ptr->state = 3;
ptr->animState = 0;
object->state = 3;
object->animState = 0;
}
else
{
@ -358,19 +350,17 @@ static void AnimateUnionRoomPlayer(u32 playerIdx, struct UnionRoomObject * ptr)
}
// fallthrough
case 3:
if (AnimateUnionRoomPlayerDespawn(&ptr->animState, playerIdx, ptr) == 1)
{
ptr->state = 0;
}
if (AnimateUnionRoomPlayerDespawn(&object->animState, leaderId, object) == 1)
object->state = 0;
break;
}
ptr->schedAnim = UNION_ROOM_SPAWN_NONE;
object->schedAnim = UNION_ROOM_SPAWN_NONE;
}
static void Task_AnimateUnionRoomPlayers(u8 taskId)
{
s32 i;
for (i = 0; i < MAX_UNION_ROOM_PLAYERS; i++)
for (i = 0; i < MAX_UNION_ROOM_LEADERS; i++)
AnimateUnionRoomPlayer(i, &sUnionObjWork[i]);
}
@ -386,15 +376,13 @@ static void DestroyTask_AnimateUnionRoomPlayers(void)
{
u8 taskId = FindTaskIdByFunc(Task_AnimateUnionRoomPlayers);
if (taskId < NUM_TASKS)
{
DestroyTask(taskId);
}
}
void DestroyUnionRoomPlayerObjects(void)
{
s32 i;
for (i = 0; i < MAX_UNION_ROOM_PLAYERS; i++)
for (i = 0; i < MAX_UNION_ROOM_LEADERS; i++)
{
if (!IsUnionRoomPlayerHidden(i))
{
@ -406,120 +394,119 @@ void DestroyUnionRoomPlayerObjects(void)
DestroyTask_AnimateUnionRoomPlayers();
}
void CreateGroupMemberSpritesInvisible(u8 * spriteIds, s32 playerIdx)
void CreateUnionRoomPlayerSprites(u8 * spriteIds, s32 leaderId)
{
s32 direction;
for (direction = DIR_NONE; direction <= DIR_EAST; direction++)
s32 memberId;
for (memberId = 0; memberId < MAX_RFU_PLAYERS; memberId++)
{
s32 id = UR_PLAYER_SPRITE_ID(playerIdx, direction);
s32 id = UR_PLAYER_SPRITE_ID(leaderId, memberId);
spriteIds[id] = CreateObjectSprite(OBJ_EVENT_GFX_MAN_4,
id - UR_SPRITE_START_ID,
sUnionRoomPlayerCoords[playerIdx][0] + sFacingDirectionOffsets[direction][0],
sUnionRoomPlayerCoords[playerIdx][1] + sFacingDirectionOffsets[direction][1],
sUnionRoomPlayerCoords[leaderId][0] + sUnionRoomGroupOffsets[memberId][0],
sUnionRoomPlayerCoords[leaderId][1] + sUnionRoomGroupOffsets[memberId][1],
3, 1);
SetObjectEventSpriteInvisibility(id - UR_SPRITE_START_ID, TRUE);
}
}
void DestroyGroupMemberSprites(u8 * spriteIds)
void DestroyUnionRoomPlayerSprites(u8 * spriteIds)
{
s32 i;
for (i = 0; i < UR_PLAYER_SPRITE_ID(MAX_UNION_ROOM_PLAYERS, 0); i++)
for (i = 0; i < NUM_UNION_ROOM_SPRITES; i++)
DestroySprite(&gSprites[spriteIds[i]]);
}
// Clear the impassable metatiles around the group leaders that get set
// to prevent the player from walking through the group member sprites.
void SetTilesAroundUnionRoomPlayersPassable(void)
{
s32 i, direction, x, y;
for (i = 0; i < MAX_UNION_ROOM_PLAYERS; i++)
s32 i, memberId, x, y;
for (i = 0; i < MAX_UNION_ROOM_LEADERS; i++)
{
for (direction = DIR_NONE; direction <= DIR_EAST; direction++)
for (memberId = 0; memberId < MAX_RFU_PLAYERS; memberId++)
{
GetUnionRoomPlayerFacingCoords(i, direction, &x, &y);
GetUnionRoomPlayerCoords(i, memberId, &x, &y);
MapGridSetMetatileImpassabilityAt(x, y, FALSE);
}
}
}
static u8 GetNewFacingDirectionForUnionRoomPlayer(u32 direction, u32 playerIdx, struct GFtgtGname * gname)
static u8 GetNewFacingDirectionForUnionRoomPlayer(u32 memberId, u32 leaderId, struct RfuGameData * gameData)
{
if (direction != DIR_NONE)
return sNextFacingDirection[direction];
else if (gname->activity == (ACTIVITY_CHAT | IN_UNION_ROOM))
if (memberId) // If not leader
return sMemberFacingDirections[memberId];
else if (gameData->activity == (ACTIVITY_CHAT | IN_UNION_ROOM))
return DIR_SOUTH;
else
return DIR_EAST;
}
static bool32 IsUnionRoomPlayerInvisible(u32 playerIdx, u32 direction)
static bool32 IsUnionRoomPlayerInvisible(u32 leaderId, u32 memberId)
{
return IsObjectEventSpriteInvisible(UR_PLAYER_SPRITE_ID(playerIdx, direction) - UR_SPRITE_START_ID);
return IsObjectEventSpriteInvisible(UR_PLAYER_SPRITE_ID(leaderId, memberId) - UR_SPRITE_START_ID);
}
static void SpawnGroupMember(u32 playerIdx, u32 direction, u8 graphicsId, struct GFtgtGname * gname)
static void SpawnGroupMember(u32 leaderId, u32 memberId, u8 graphicsId, struct RfuGameData * gameData)
{
s32 x, y;
s32 id = UR_PLAYER_SPRITE_ID(playerIdx, direction);
if (IsUnionRoomPlayerInvisible(playerIdx, direction) == TRUE)
s32 id = UR_PLAYER_SPRITE_ID(leaderId, memberId);
if (IsUnionRoomPlayerInvisible(leaderId, memberId) == TRUE)
{
SetObjectEventSpriteInvisibility(id - UR_SPRITE_START_ID, FALSE);
SetObjectEventSpriteAnim(id - UR_SPRITE_START_ID, UNION_ROOM_SPAWN_IN);
}
SetObjectEventSpriteGraphics(id - UR_SPRITE_START_ID, graphicsId);
SetUnionRoomObjectFacingDirection(direction, playerIdx, GetNewFacingDirectionForUnionRoomPlayer(direction, playerIdx, gname));
GetUnionRoomPlayerFacingCoords(playerIdx, direction, &x, &y);
SetUnionRoomObjectFacingDirection(memberId, leaderId, GetNewFacingDirectionForUnionRoomPlayer(memberId, leaderId, gameData));
GetUnionRoomPlayerCoords(leaderId, memberId, &x, &y);
MapGridSetMetatileImpassabilityAt(x, y, TRUE);
}
static void DespawnGroupMember(u32 playerIdx, u32 direction)
static void DespawnGroupMember(u32 leaderId, u32 memberId)
{
s32 x, y;
SetObjectEventSpriteAnim(UR_PLAYER_SPRITE_ID(playerIdx, direction) - UR_SPRITE_START_ID, UNION_ROOM_SPAWN_OUT);
GetUnionRoomPlayerFacingCoords(playerIdx, direction, &x, &y);
SetObjectEventSpriteAnim(UR_PLAYER_SPRITE_ID(leaderId, memberId) - UR_SPRITE_START_ID, UNION_ROOM_SPAWN_OUT);
GetUnionRoomPlayerCoords(leaderId, memberId, &x, &y);
MapGridSetMetatileImpassabilityAt(x, y, FALSE);
}
static void AssembleGroup(u32 playerIdx, struct GFtgtGname * gname)
static void AssembleGroup(u32 leaderId, struct RfuGameData * gameData)
{
s16 x, y, x2, y2;
s32 i;
PlayerGetDestCoords(&x, &y);
player_get_pos_including_state_based_drift(&x2, &y2);
if (IsObjectEventSpriteInvisible(UR_PLAYER_SPRITE_ID(playerIdx, 0) - UR_SPRITE_START_ID) == TRUE)
if (IsObjectEventSpriteInvisible(UR_PLAYER_SPRITE_ID(leaderId, 0) - UR_SPRITE_START_ID) == TRUE)
{
if (IsUnionRoomPlayerFacingTileAt(playerIdx, 0, x, y) == TRUE || IsUnionRoomPlayerFacingTileAt(playerIdx, 0, x2, y2) == TRUE)
{
if (IsUnionRoomPlayerAt(leaderId, 0, x, y) == TRUE || IsUnionRoomPlayerAt(leaderId, 0, x2, y2) == TRUE)
return;
}
SpawnGroupMember(playerIdx, 0, GetUnionRoomPlayerGraphicsId(gname->playerGender, gname->unk_00.playerTrainerId[0]), gname);
SpawnGroupMember(leaderId, 0, GetUnionRoomPlayerGraphicsId(gameData->playerGender, gameData->compatibility.playerTrainerId[0]), gameData);
}
for (i = 1; i < 5; i++)
for (i = 1; i < MAX_RFU_PLAYERS; i++)
{
if (gname->child_sprite_gender[i - 1] == 0)
if (gameData->partnerInfo[i - 1] == 0)
{
DespawnGroupMember(playerIdx, i);
DespawnGroupMember(leaderId, i);
}
else if (IsUnionRoomPlayerFacingTileAt(playerIdx, i, x, y) == FALSE && IsUnionRoomPlayerFacingTileAt(playerIdx, i, x2, y2) == FALSE)
else if (IsUnionRoomPlayerAt(leaderId, i, x, y) == FALSE && IsUnionRoomPlayerAt(leaderId, i, x2, y2) == FALSE)
{
SpawnGroupMember(playerIdx, i, GetUnionRoomPlayerGraphicsId((gname->child_sprite_gender[i - 1] >> 3) & 1, gname->child_sprite_gender[i - 1] & 7), gname);
SpawnGroupMember(leaderId, i, GetUnionRoomPlayerGraphicsId((gameData->partnerInfo[i - 1] >> PINFO_GENDER_SHIFT) & 1,
gameData->partnerInfo[i - 1] & PINFO_TID_MASK),
gameData);
}
}
}
static void SpawnGroupLeaderAndMembers(u32 playerIdx, struct GFtgtGname * gname)
static void SpawnGroupLeaderAndMembers(u32 leaderId, struct RfuGameData * gameData)
{
u32 i;
switch (gname->activity)
switch (gameData->activity)
{
case ACTIVITY_NONE | IN_UNION_ROOM:
case ACTIVITY_PLYRTALK | IN_UNION_ROOM:
SpawnGroupLeader(playerIdx, gname->playerGender, gname->unk_00.playerTrainerId[0]);
for (i = 0; i < 5; i++)
{
DespawnGroupMember(playerIdx, i);
}
SpawnGroupLeader(leaderId, gameData->playerGender, gameData->compatibility.playerTrainerId[0]);
for (i = 0; i < MAX_RFU_PLAYERS; i++)
DespawnGroupMember(leaderId, i);
break;
case ACTIVITY_BATTLE_SINGLE | IN_UNION_ROOM:
case ACTIVITY_TRADE | IN_UNION_ROOM:
@ -528,37 +515,31 @@ static void SpawnGroupLeaderAndMembers(u32 playerIdx, struct GFtgtGname * gname)
case ACTIVITY_ACCEPT | IN_UNION_ROOM:
case ACTIVITY_DECLINE | IN_UNION_ROOM:
case ACTIVITY_NPCTALK | IN_UNION_ROOM:
DespawnGroupLeader(playerIdx);
AssembleGroup(playerIdx, gname);
DespawnGroupLeader(leaderId);
AssembleGroup(leaderId, gameData);
break;
}
}
static void DespawnGroupLeaderAndMembers(u32 r5, struct GFtgtGname *gname)
static void DespawnGroupLeaderAndMembers(u32 leaderId, struct RfuGameData *gameData)
{
s32 i;
DespawnGroupLeader(r5);
for (i = 0; i < 5; i++)
{
DespawnGroupMember(r5, i);
}
DespawnGroupLeader(leaderId);
for (i = 0; i < MAX_RFU_PLAYERS; i++)
DespawnGroupMember(leaderId, i);
}
static void UpdateUnionRoomPlayerSprites(struct WirelessLink_URoom *uroom)
{
s32 i;
struct UnkStruct_x20 * r4;
struct RfuPlayer * leaders;
sUnionObjRefreshTimer = 0;
for (i = 0, r4 = uroom->field_0->arr; i < MAX_UNION_ROOM_PLAYERS; i++)
for (i = 0, leaders = uroom->playerList->players; i < MAX_UNION_ROOM_LEADERS; i++)
{
if (r4[i].groupScheduledAnim == UNION_ROOM_SPAWN_IN)
{
SpawnGroupLeaderAndMembers(i, &r4[i].gname_uname.gname);
}
else if (r4[i].groupScheduledAnim == UNION_ROOM_SPAWN_OUT)
{
DespawnGroupLeaderAndMembers(i, &r4[i].gname_uname.gname);
}
if (leaders[i].groupScheduledAnim == UNION_ROOM_SPAWN_IN)
SpawnGroupLeaderAndMembers(i, &leaders[i].rfu.data);
else if (leaders[i].groupScheduledAnim == UNION_ROOM_SPAWN_OUT)
DespawnGroupLeaderAndMembers(i, &leaders[i].rfu.data);
}
}
@ -570,64 +551,56 @@ void ScheduleUnionRoomPlayerRefresh(struct WirelessLink_URoom *uroom)
void HandleUnionRoomPlayerRefresh(struct WirelessLink_URoom *uroom)
{
if (++sUnionObjRefreshTimer > 300)
{
UpdateUnionRoomPlayerSprites(uroom);
}
}
bool32 TryInteractWithUnionRoomMember(struct UnkStruct_Main0 *main0, s16 *directionPtr, s16 *playerIdxPtr, u8 *spriteIds)
bool32 TryInteractWithUnionRoomMember(struct RfuPlayerList *list, s16 *memberIdPtr, s16 *leaderIdPtr, u8 *spriteIds)
{
s16 x, y;
s32 i, direction;
struct UnkStruct_x20 * r4;
s32 i, memberId;
struct RfuPlayer * leaders;
if (!IsPlayerStandingStill())
{
return FALSE;
}
GetXYCoordsOneStepInFrontOfPlayer(&x, &y);
for (i = 0, r4 = main0->arr; i < MAX_UNION_ROOM_PLAYERS; i++)
for (i = 0, leaders = list->players; i < MAX_UNION_ROOM_LEADERS; i++)
{
for (direction = DIR_NONE; direction <= DIR_EAST; direction++)
for (memberId = 0; memberId < MAX_RFU_PLAYERS; memberId++)
{
s32 id = UR_PLAYER_SPRITE_ID(i, direction);
if (x != sUnionRoomPlayerCoords[i][0] + sFacingDirectionOffsets[direction][0] + 7)
{
s32 id = UR_PLAYER_SPRITE_ID(i, memberId);
// Is the player in front of a group member position?
if (x != sUnionRoomPlayerCoords[i][0] + sUnionRoomGroupOffsets[memberId][0] + 7)
continue;
}
if (y != sUnionRoomPlayerCoords[i][1] + sFacingDirectionOffsets[direction][1] + 7)
{
if (y != sUnionRoomPlayerCoords[i][1] + sUnionRoomGroupOffsets[memberId][1] + 7)
continue;
}
// Has a group member spawned at this position?
if (IsObjectEventSpriteInvisible(id - UR_SPRITE_START_ID))
{
continue;
}
if (IsObjectEventSpriteAnimating(id - UR_SPRITE_START_ID))
{
continue;
}
if (r4[i].groupScheduledAnim != UNION_ROOM_SPAWN_IN)
{
if (leaders[i].groupScheduledAnim != UNION_ROOM_SPAWN_IN)
continue;
}
// Face player
SetUnionRoomObjectFacingDirection(direction, i, sOppositeFacingDirection[GetPlayerFacingDirection()]);
*directionPtr = direction;
*playerIdxPtr = i;
// Interaction attempt successful, face player
SetUnionRoomObjectFacingDirection(memberId, i, sOppositeFacingDirection[GetPlayerFacingDirection()]);
*memberIdPtr = memberId;
*leaderIdPtr = i;
return TRUE;
}
}
return FALSE;
}
static void SetUnionRoomObjectFacingDirection(s32 currDirection, s32 playerIdx, u8 newDirection)
static void SetUnionRoomObjectFacingDirection(s32 memberId, s32 leaderId, u8 newDirection)
{
TurnObjectEventSprite(5 * playerIdx - UR_SPRITE_START_ID + currDirection, newDirection);
TurnObjectEventSprite(MAX_RFU_PLAYERS * leaderId - UR_SPRITE_START_ID + memberId, newDirection);
// should be line below, but order is swapped here
// TurnObjectEventSprite(UR_PLAYER_SPRITE_ID(playerIdx, currDirection) - UR_SPRITE_START_ID, newDirection);
// TurnObjectEventSprite(UR_PLAYER_SPRITE_ID(leaderId, memberId) - UR_SPRITE_START_ID, newDirection);
}
void UpdateUnionRoomMemberFacing(u32 currDirection, u32 playerIdx, struct UnkStruct_Main0 *main0)
void UpdateUnionRoomMemberFacing(u32 memberId, u32 leaderId, struct RfuPlayerList *list)
{
return SetUnionRoomObjectFacingDirection(currDirection, playerIdx, GetNewFacingDirectionForUnionRoomPlayer(currDirection, playerIdx, &main0->arr[playerIdx].gname_uname.gname));
return SetUnionRoomObjectFacingDirection(memberId, leaderId, GetNewFacingDirectionForUnionRoomPlayer(memberId, leaderId, &list->players[leaderId].rfu.data));
}

View File

@ -114,8 +114,8 @@ static const u8 sActivityGroupInfo[][3] = {
{ACTIVITY_BATTLE_DOUBLE, GROUPTYPE_BATTLE, 2},
{ACTIVITY_BATTLE_MULTI, GROUPTYPE_BATTLE, 4},
{ACTIVITY_TRADE, GROUPTYPE_TRADE, 2},
{ACTIVITY_WONDER_CARD, GROUPTYPE_TOTAL, 2},
{ACTIVITY_WONDER_NEWS, GROUPTYPE_TOTAL, 2},
{ACTIVITY_WONDER_CARD_DUP, GROUPTYPE_TOTAL, 2},
{ACTIVITY_WONDER_NEWS_DUP, GROUPTYPE_TOTAL, 2},
{ACTIVITY_POKEMON_JUMP, GROUPTYPE_TOTAL, 0},
{ACTIVITY_BERRY_CRUSH, GROUPTYPE_TOTAL, 0},
{ACTIVITY_BERRY_PICK, GROUPTYPE_TOTAL, 0},
@ -132,8 +132,8 @@ static const u8 sActivityGroupInfo[][3] = {
{ACTIVITY_NPCTALK | IN_UNION_ROOM, GROUPTYPE_UNION, 2},
{ACTIVITY_ACCEPT | IN_UNION_ROOM, GROUPTYPE_UNION, 1},
{ACTIVITY_DECLINE | IN_UNION_ROOM, GROUPTYPE_UNION, 1},
{ACTIVITY_WONDER_CARD2, GROUPTYPE_TOTAL, 2},
{ACTIVITY_WONDER_NEWS2, GROUPTYPE_TOTAL, 2},
{ACTIVITY_WONDER_CARD, GROUPTYPE_TOTAL, 2},
{ACTIVITY_WONDER_NEWS, GROUPTYPE_TOTAL, 2},
{ACTIVITY_CONTEST_COOL, GROUPTYPE_TOTAL, 0},
{ACTIVITY_CONTEST_BEAUTY, GROUPTYPE_TOTAL, 0},
{ACTIVITY_CONTEST_CUTE, GROUPTYPE_TOTAL, 0},
@ -347,10 +347,10 @@ static void WCSS_AddTextPrinterParameterized(u8 windowId, u8 fontId, const u8 *
AddTextPrinterParameterized4(windowId, fontId, x, y, 0, 0, color, -1, str);
}
static u32 CountPlayersInGroupAndGetActivity(struct UnkStruct_x20 * unk20, u32 * groupCounts)
static u32 CountPlayersInGroupAndGetActivity(struct RfuPlayer * player, u32 * groupCounts)
{
int i, j, k;
u32 activity = unk20->gname_uname.gname.activity;
u32 activity = player->rfu.data.activity;
#define group_activity(i) (sActivityGroupInfo[(i)][0])
#define group_type(i) (sActivityGroupInfo[(i)][1])
@ -358,15 +358,13 @@ static u32 CountPlayersInGroupAndGetActivity(struct UnkStruct_x20 * unk20, u32 *
for (i = 0; i < ARRAY_COUNT(sActivityGroupInfo); i++)
{
if (activity == group_activity(i) && unk20->groupScheduledAnim == UNION_ROOM_SPAWN_IN)
if (activity == group_activity(i) && player->groupScheduledAnim == UNION_ROOM_SPAWN_IN)
{
if (group_players(i) == 0)
{
k = 0;
for (j = 0; j < RFU_CHILD_MAX; j++)
{
if (unk20->gname_uname.gname.child_sprite_gender[j] != 0) k++;
}
if (player->rfu.data.partnerInfo[j] != 0) k++;
k++;
groupCounts[group_type(i)] += k;
}
@ -398,12 +396,12 @@ static bool32 UpdateCommunicationCounts(u32 * groupCounts, u32 * prevGroupCounts
{
bool32 activitiesChanged = FALSE;
u32 groupCountBuffer[NUM_GROUPTYPES] = {0, 0, 0, 0};
struct UnkStruct_x20 ** data = (void *)gTasks[taskId].data;
struct RfuPlayer ** players = (void *)gTasks[taskId].data;
s32 i;
for (i = 0; i < NUM_TASK_DATA; i++)
{
u32 activity = CountPlayersInGroupAndGetActivity(&(*data)[i], groupCountBuffer);
u32 activity = CountPlayersInGroupAndGetActivity(&(*players)[i], groupCountBuffer);
if (activity != activities[i])
{
activities[i] = activity;