summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/battle_main.c9
-rw-r--r--src/battle_setup.c27
-rw-r--r--src/daycare.c30
-rw-r--r--src/fame_checker.c2
-rw-r--r--src/link_rfu_2.c31
-rw-r--r--src/link_rfu_3.c4
-rw-r--r--src/mail_data.c4
-rw-r--r--src/new_game.c4
-rw-r--r--src/oak_speech.c4
-rw-r--r--src/pokemon.c4
-rw-r--r--src/quest_log.c44
-rw-r--r--src/seagallop.c28
-rw-r--r--src/trade.c25
-rw-r--r--src/union_room.c4
-rw-r--r--src/union_room_chat.c1452
-rw-r--r--src/union_room_chat_display.c1339
-rw-r--r--src/union_room_chat_objects.c318
17 files changed, 3203 insertions, 126 deletions
diff --git a/src/battle_main.c b/src/battle_main.c
index fd8aeffbc..76f373f8f 100644
--- a/src/battle_main.c
+++ b/src/battle_main.c
@@ -50,6 +50,7 @@
#include "cable_club.h"
#include "constants/abilities.h"
#include "constants/battle_move_effects.h"
+#include "constants/battle_setup.h"
#include "constants/hold_effects.h"
#include "constants/items.h"
#include "constants/moves.h"
@@ -3716,12 +3717,12 @@ static void HandleEndTurn_BattleLost(void)
}
else
{
- if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && ScrSpecial_GetTrainerBattleMode() == 9)
+ if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && ScrSpecial_GetTrainerBattleMode() == TRAINER_BATTLE_EARLY_RIVAL)
{
- if (sub_80803D8() & 1)
- gBattleCommunication[MULTISTRING_CHOOSER] = 1;
+ if (GetRivalBattleFlags() & RIVAL_BATTLE_HEAL_AFTER)
+ gBattleCommunication[MULTISTRING_CHOOSER] = 1; // Dont do white out text
else
- gBattleCommunication[MULTISTRING_CHOOSER] = 2;
+ gBattleCommunication[MULTISTRING_CHOOSER] = 2; // Do white out text
gBattlerAttacker = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
}
else
diff --git a/src/battle_setup.c b/src/battle_setup.c
index 102a1b969..ae6aaf8be 100644
--- a/src/battle_setup.c
+++ b/src/battle_setup.c
@@ -78,7 +78,7 @@ static EWRAM_DATA u8 *sTrainerVictorySpeech = NULL;
static EWRAM_DATA u8 *sTrainerCannotBattleSpeech = NULL;
static EWRAM_DATA u8 *sTrainerBattleEndScript = NULL;
static EWRAM_DATA u8 *sTrainerABattleScriptRetAddr = NULL;
-static EWRAM_DATA u16 gUnknown_20386CC = 0;
+static EWRAM_DATA u16 sRivalBattleFlags = 0;
static const u8 sBattleTransitionTable_Wild[][2] =
{
@@ -148,11 +148,11 @@ static const struct TrainerBattleParameter sOrdinaryNoIntroBattleParams[] =
{&sTrainerBattleEndScript, TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR},
};
-static const struct TrainerBattleParameter sTutorialBattleParams[] =
+static const struct TrainerBattleParameter sEarlyRivalBattleParams[] =
{
{&sTrainerBattleMode, TRAINER_PARAM_LOAD_VAL_8BIT},
{&gTrainerBattleOpponent_A, TRAINER_PARAM_LOAD_VAL_16BIT},
- {&gUnknown_20386CC, TRAINER_PARAM_LOAD_VAL_16BIT},
+ {&sRivalBattleFlags, TRAINER_PARAM_LOAD_VAL_16BIT},
{&sTrainerAIntroSpeech, TRAINER_PARAM_CLEAR_VAL_32BIT},
{&sTrainerADefeatSpeech, TRAINER_PARAM_LOAD_VAL_32BIT},
{&sTrainerVictorySpeech, TRAINER_PARAM_LOAD_VAL_32BIT},
@@ -706,7 +706,7 @@ static void InitTrainerBattleVariables(void)
sTrainerCannotBattleSpeech = NULL;
sTrainerBattleEndScript = NULL;
sTrainerABattleScriptRetAddr = NULL;
- gUnknown_20386CC = 0;
+ sRivalBattleFlags = 0;
}
static inline void SetU8(void *ptr, u8 value)
@@ -808,8 +808,8 @@ const u8 *BattleSetup_ConfigureTrainerBattle(const u8 *data)
SetMapVarsToTrainer();
gTrainerBattleOpponent_A = GetRematchTrainerId(gTrainerBattleOpponent_A);
return EventScript_TryDoRematchBattle;
- case TRAINER_BATTLE_TUTORIAL:
- TrainerBattleLoadArgs(sTutorialBattleParams, data);
+ case TRAINER_BATTLE_EARLY_RIVAL:
+ TrainerBattleLoadArgs(sEarlyRivalBattleParams, data);
return EventScript_DoTrainerBattle;
default:
TrainerBattleLoadArgs(sOrdinaryBattleParams, data);
@@ -846,9 +846,9 @@ u8 ScrSpecial_GetTrainerBattleMode(void)
return sTrainerBattleMode;
}
-u16 sub_80803D8(void)
+u16 GetRivalBattleFlags(void)
{
- return gUnknown_20386CC;
+ return sRivalBattleFlags;
}
u16 ScrSpecial_HasTrainerBeenFought(void)
@@ -885,8 +885,7 @@ void ClearTrainerFlag(u16 trainerId)
void BattleSetup_StartTrainerBattle(void)
{
gBattleTypeFlags = BATTLE_TYPE_TRAINER;
- if (ScrSpecial_GetTrainerBattleMode() == TRAINER_BATTLE_TUTORIAL
- && sub_80803D8() & 3)
+ if (ScrSpecial_GetTrainerBattleMode() == TRAINER_BATTLE_EARLY_RIVAL && GetRivalBattleFlags() & RIVAL_BATTLE_TUTORIAL)
gBattleTypeFlags |= BATTLE_TYPE_FIRST_BATTLE;
gMain.savedCallback = CB2_EndTrainerBattle;
DoTrainerBattle();
@@ -895,12 +894,12 @@ void BattleSetup_StartTrainerBattle(void)
static void CB2_EndTrainerBattle(void)
{
- if (sTrainerBattleMode == TRAINER_BATTLE_TUTORIAL)
+ if (sTrainerBattleMode == TRAINER_BATTLE_EARLY_RIVAL)
{
if (IsPlayerDefeated(gBattleOutcome) == TRUE)
{
- gSpecialVar_Result = 1;
- if (gUnknown_20386CC & 1)
+ gSpecialVar_Result = TRUE;
+ if (sRivalBattleFlags & RIVAL_BATTLE_HEAL_AFTER)
{
HealPlayerParty();
}
@@ -915,7 +914,7 @@ static void CB2_EndTrainerBattle(void)
}
else
{
- gSpecialVar_Result = 0;
+ gSpecialVar_Result = FALSE;
SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic);
SetBattledTrainerFlag();
sub_81139BC();
diff --git a/src/daycare.c b/src/daycare.c
index a377e97f5..277a382c7 100644
--- a/src/daycare.c
+++ b/src/daycare.c
@@ -1,44 +1,34 @@
#include "global.h"
-#include "pokemon.h"
+#include "gflib.h"
#include "battle.h"
#include "daycare.h"
-#include "string_util.h"
#include "constants/species.h"
#include "constants/items.h"
#include "mail_data.h"
#include "pokemon_storage_system.h"
#include "event_data.h"
#include "random.h"
-#include "main.h"
#include "constants/moves.h"
-#include "text.h"
#include "menu.h"
#include "new_menu_helpers.h"
#include "script.h"
#include "strings.h"
-#include "task.h"
-#include "window.h"
#include "party_menu.h"
#include "list_menu.h"
#include "overworld.h"
#include "pokedex.h"
#include "decompress.h"
-#include "palette.h"
-#include "sound.h"
#include "constants/songs.h"
#include "text_window.h"
#include "trig.h"
-#include "malloc.h"
-#include "gpu_regs.h"
-#include "bg.h"
#include "m4a.h"
#include "graphics.h"
#include "scanline_effect.h"
#include "naming_screen.h"
#include "help_system.h"
#include "field_fadetransition.h"
+#include "trade.h"
#include "constants/daycare.h"
-#include "constants/pokemon.h"
#include "constants/region_map.h"
// Combination of RSE's Day-Care (re-used on Four Island), FRLG's Day-Care, and egg_hatch.c
@@ -60,20 +50,6 @@ struct EggHatchData
u8 textColor[3];
};
-extern const u8 gText_MaleSymbol4[];
-extern const u8 gText_FemaleSymbol4[];
-extern const u8 gText_GenderlessSymbol[];
-extern const u8 gText_Lv[];
-extern const u8 gDaycareText_GetAlongVeryWell[];
-extern const u8 gDaycareText_GetAlong[];
-extern const u8 gDaycareText_DontLikeOther[];
-extern const u8 gDaycareText_PlayOther[];
-extern const u8 gExpandedPlaceholder_Empty[];
-
-extern const u32 gUnknown_826601C[]; // tilemap gameboy circle
-extern const u8 gText_HatchedFromEgg[];
-extern const u8 gText_NickHatchPrompt[];
-
// this file's functions
static void ClearDaycareMonMail(struct DayCareMail *mail);
static void SetInitialEggData(struct Pokemon *mon, u16 species, struct DayCare *daycare);
@@ -638,7 +614,7 @@ static void ClearDaycareMonMail(struct DayCareMail *mail)
{
s32 i;
- for (i = 0; i < PLAYER_NAME_LENGTH/* + 1*/; i++)
+ for (i = 0; i < PLAYER_NAME_LENGTH + 1; i++)
mail->OT_name[i] = 0;
for (i = 0; i < POKEMON_NAME_LENGTH + 1; i++)
mail->monName[i] = 0;
diff --git a/src/fame_checker.c b/src/fame_checker.c
index b8f2c0055..6f60b4a44 100644
--- a/src/fame_checker.c
+++ b/src/fame_checker.c
@@ -33,7 +33,7 @@
#define SPRITETAG_QUESTION_MARK 1001
#define SPRITETAG_SPINNING_POKEBALL 1002
#define SPRITETAG_SCROLL_INDICATORS 1004
-#define SPRITETAG_DAISY 1006
+#define SPRITETAG_DAISY 1006 // TODO: Investigate, seems to be used for other NPCs (e.g. Fan Club Chairman)
#define SPRITETAG_FUJI 1007
#define SPRITETAG_OAK 1008
#define SPRITETAG_BILL 1009
diff --git a/src/link_rfu_2.c b/src/link_rfu_2.c
index 17f604ee8..a27948650 100644
--- a/src/link_rfu_2.c
+++ b/src/link_rfu_2.c
@@ -30,7 +30,7 @@ static u16 gUnknown_3002008[7];
struct GFtgtGname gHostRFUtgtGnameBuffer;
struct UnkRfuStruct_2 Rfu;
-u8 gHostRFUtgtUnameBuffer[PLAYER_NAME_LENGTH];
+u8 gHostRFUtgtUnameBuffer[PLAYER_NAME_LENGTH + 1];
static void sub_80F8AA4(void);
static void sub_80F8AEC(void);
@@ -448,7 +448,7 @@ static void sub_80F8B34(u8 taskId)
gTasks[taskId].data[1] = 8;
Rfu.unk_0c = 1;
CreateTask(sub_80FA834, 5);
- Rfu.unk_ce8 = 1;
+ Rfu.unk_ce8 = TRUE;
DestroyTask(taskId);
break;
}
@@ -1337,7 +1337,7 @@ static void sub_80FA1C4(void)
static void sub_80FA224(void)
{
- if (gSendCmd[0] == 0 && Rfu.unk_ce8 == 0)
+ if (gSendCmd[0] == 0 && !Rfu.unk_ce8)
{
sub_80F9D04(0x5f00);
Rfu.RfuFunc = sub_80FA1C4;
@@ -1620,7 +1620,7 @@ static void sub_80FA834(u8 taskId)
if (Rfu.unk_f1 == 1 || Rfu.unk_f1 == 2)
{
- Rfu.unk_ce8 = 0;
+ Rfu.unk_ce8 = FALSE;
DestroyTask(taskId);
}
switch (gTasks[taskId].data[0])
@@ -1681,7 +1681,7 @@ static void sub_80FA834(u8 taskId)
case 6:
DestroyTask(taskId);
gReceivedRemoteLinkPlayers = 1;
- Rfu.unk_ce8 = 0;
+ Rfu.unk_ce8 = FALSE;
sub_80FEA34(1, 0x258);
if (Rfu.unk_ce6)
{
@@ -1740,7 +1740,7 @@ static void sub_80FAA94(u8 taskId)
u8 r4 = Rfu.unk_cde[gUnknown_843EC38[Rfu.unk_ce9]];
if (Rfu.unk_f1 == 1 || Rfu.unk_f1 == 2)
{
- Rfu.unk_ce8 = 0;
+ Rfu.unk_ce8 = FALSE;
DestroyTask(taskId);
}
switch (gTasks[taskId].data[0])
@@ -1790,7 +1790,7 @@ static void sub_80FAA94(u8 taskId)
{
CpuFill16(0, gBlockRecvBuffer, sizeof(struct UnkRfuStruct_8010A14));
ResetBlockReceivedFlag(0);
- Rfu.unk_ce8 = 0;
+ Rfu.unk_ce8 = FALSE;
if (Rfu.unk_ce6)
{
for (i = 0; i < RFU_CHILD_MAX; i++)
@@ -1799,7 +1799,7 @@ static void sub_80FAA94(u8 taskId)
{
Rfu.unk_ce5 = 1 << i;
Rfu.unk_ce6 ^= (1 << i);
- Rfu.unk_ce8 = 1;
+ Rfu.unk_ce8 = TRUE;
break;
}
}
@@ -1948,7 +1948,7 @@ void sub_80FB008(u8 a0, u32 a1, u32 a2)
rfu_REQ_configGameData(0, 2, (void *)&gHostRFUtgtGnameBuffer, gHostRFUtgtUnameBuffer);
}
-void sub_80FB030(u32 a0)
+void sub_80FB030(u32 linkPlayerCount)
{
s32 i;
u32 r5;
@@ -1964,9 +1964,10 @@ void sub_80FB030(u32 a0)
{
if ((r8 >> i) & 1)
{
- r7 |= ((0x80 | ((gLinkPlayers[Rfu.unk_cde[i]].gender & 1) << 3) | (gLinkPlayers[Rfu.unk_cde[i]].trainerId & 7)) << (r5 << 3));
+ r7 |= ((
+ 0x80 | ((gLinkPlayers[Rfu.unk_cde[i]].gender & 1) << 3) | (gLinkPlayers[Rfu.unk_cde[i]].trainerId & 7)) << (r5 << 3));
r5++;
- if (r5 == a0 - 1)
+ if (r5 == linkPlayerCount - 1)
break;
}
}
@@ -2214,11 +2215,11 @@ static void sub_80FB5EC(u8 a0, u8 unused1)
if (idx != 0)
{
r1 = 1 << sub_80F886C(idx);
- if (Rfu.unk_ce6 == 0 && Rfu.unk_ce8 == 0)
+ if (Rfu.unk_ce6 == 0 && !Rfu.unk_ce8)
{
Rfu.unk_ce5 = r1;
Rfu.unk_ce6 |= (r1 ^ idx);
- Rfu.unk_ce8 = 1;
+ Rfu.unk_ce8 = TRUE;
}
else
{
@@ -2360,7 +2361,7 @@ bool32 sub_80FBA00(void)
return FALSE;
}
-bool32 sub_80FBA1C(void)
+bool32 GetRfuUnkCE8(void)
{
return Rfu.unk_ce8;
}
@@ -2534,7 +2535,7 @@ void sub_80FBD6C(u32 a0)
static void sub_80FBDB8(u8 taskId)
{
- if (gSendCmd[0] == 0 && Rfu.unk_ce8 == 0)
+ if (gSendCmd[0] == 0 && !Rfu.unk_ce8)
{
sub_80F9D04(0xED00);
gSendCmd[1] = gTasks[taskId].data[0];
diff --git a/src/link_rfu_3.c b/src/link_rfu_3.c
index 31ea0830b..69b6603a8 100644
--- a/src/link_rfu_3.c
+++ b/src/link_rfu_3.c
@@ -848,7 +848,7 @@ static void ZeroName(u8 *name)
{
s32 i;
- for (i = 0; i < PLAYER_NAME_LENGTH; i++)
+ for (i = 0; i < PLAYER_NAME_LENGTH + 1; i++)
{
*name++ = 0;
}
@@ -858,7 +858,7 @@ static bool32 NameIsEmpty(const u8 *name)
{
s32 i;
- for (i = 0; i < PLAYER_NAME_LENGTH; i++)
+ for (i = 0; i < PLAYER_NAME_LENGTH + 1; i++)
{
if (*name++ != 0)
{
diff --git a/src/mail_data.c b/src/mail_data.c
index d4fa649e1..43ca1d0e6 100644
--- a/src/mail_data.c
+++ b/src/mail_data.c
@@ -20,7 +20,7 @@ void ClearMailStruct(struct MailStruct *mail)
for (i = 0; i < MAIL_WORDS_COUNT; i++)
mail->words[i] = 0xFFFF;
- for (i = 0; i < PLAYER_NAME_LENGTH; i++)
+ for (i = 0; i < PLAYER_NAME_LENGTH + 1; i++)
mail->playerName[i] = EOS;
for (i = 0; i < 4; i++)
mail->trainerId[i] = 0;
@@ -52,7 +52,7 @@ u8 GiveMailToMon(struct Pokemon *mon, u16 itemId)
{
for (i = 0; i < MAIL_WORDS_COUNT; i++)
gSaveBlock1Ptr->mail[id].words[i] = 0xFFFF;
- for (i = 0; i < PLAYER_NAME_LENGTH - 1 && gSaveBlock2Ptr->playerName[i] != EOS; i++)
+ for (i = 0; i < PLAYER_NAME_LENGTH && gSaveBlock2Ptr->playerName[i] != EOS; i++)
gSaveBlock1Ptr->mail[id].playerName[i] = gSaveBlock2Ptr->playerName[i];
for (; i <= 5; i++)
gSaveBlock1Ptr->mail[id].playerName[i] = CHAR_SPACE;
diff --git a/src/new_game.c b/src/new_game.c
index 381ba28c8..05fb9c83e 100644
--- a/src/new_game.c
+++ b/src/new_game.c
@@ -108,7 +108,7 @@ void ResetMenuAndMonGlobals(void)
void NewGameInitData(void)
{
- u8 rivalName[PLAYER_NAME_LENGTH];
+ u8 rivalName[PLAYER_NAME_LENGTH + 1];
StringCopy(rivalName, gSaveBlock1Ptr->rivalName);
gDifferentSaveFile = TRUE;
@@ -143,7 +143,7 @@ void NewGameInitData(void)
sub_809C794();
InitEasyChatPhrases();
ResetTrainerFanClub();
- copy_strings_to_sav1();
+ UnionRoomChat_InitializeRegisteredTexts();
ResetMiniGamesResults();
sub_8143D24();
SetAllRenewableItemFlags();
diff --git a/src/oak_speech.c b/src/oak_speech.c
index 0ad5d6a6f..6887ff85a 100644
--- a/src/oak_speech.c
+++ b/src/oak_speech.c
@@ -1902,8 +1902,8 @@ static void GetDefaultName(u8 arg0, u8 namePick)
src = sRivalNameChoices[namePick];
dest = gSaveBlock1Ptr->rivalName;
}
- for (i = 0; i < PLAYER_NAME_LENGTH - 1 && src[i] != EOS; i++)
+ for (i = 0; i < PLAYER_NAME_LENGTH && src[i] != EOS; i++)
dest[i] = src[i];
- for (; i < PLAYER_NAME_LENGTH; i++)
+ for (; i < PLAYER_NAME_LENGTH + 1; i++)
dest[i] = EOS;
}
diff --git a/src/pokemon.c b/src/pokemon.c
index d1305861a..09e2ed998 100644
--- a/src/pokemon.c
+++ b/src/pokemon.c
@@ -2991,7 +2991,7 @@ u32 GetBoxMonData(struct BoxPokemon *boxMon, s32 field, u8 *data)
{
retVal = 0;
- // FRLG changed this to 7 which used to be PLAYER_NAME_LENGTH
+ // FRLG changed this to 7 which used to be PLAYER_NAME_LENGTH + 1
while (retVal < 7)
{
data[retVal] = boxMon->otName[retVal];
@@ -5769,7 +5769,7 @@ s8 GetFlavorRelationByPersonality(u32 personality, u8 flavor)
bool8 IsTradedMon(struct Pokemon *mon)
{
- u8 otName[7 + 1]; // change PLAYER_NAME_LENGTH to 7
+ u8 otName[PLAYER_NAME_LENGTH];
u32 otId;
GetMonData(mon, MON_DATA_OT_NAME, otName);
otId = GetMonData(mon, MON_DATA_OT_ID, 0);
diff --git a/src/quest_log.c b/src/quest_log.c
index 0cda4eb77..a02aea302 100644
--- a/src/quest_log.c
+++ b/src/quest_log.c
@@ -2411,8 +2411,8 @@ static void BufferFanClubTrainerName(struct LinkBattleRecords *linkRecords, u8 w
else
{
str = gStringVar1;
- StringCopyN(str, linkTrainerName, PLAYER_NAME_LENGTH - 1);
- str[PLAYER_NAME_LENGTH - 1] = EOS;
+ StringCopyN(str, linkTrainerName, PLAYER_NAME_LENGTH);
+ str[PLAYER_NAME_LENGTH] = EOS;
if ( str[0] == EXT_CTRL_CODE_BEGIN
&& str[1] == EXT_CTRL_CODE_JPN)
{
@@ -3401,8 +3401,8 @@ static const u16 *BufferQuestLogText_LinkTraded(const u16 *a0)
{
const u16 *r6 = a0 + 4;
- memset(gStringVar1, EOS, PLAYER_NAME_LENGTH);
- memcpy(gStringVar1, r6, PLAYER_NAME_LENGTH - 1);
+ memset(gStringVar1, EOS, PLAYER_NAME_LENGTH + 1);
+ memcpy(gStringVar1, r6, PLAYER_NAME_LENGTH);
BufferLinkPartnersName(gStringVar1);
QuestLog_GetSpeciesName(a0[3], gStringVar2, 0); // Mon received
@@ -3435,7 +3435,7 @@ static u16 *BufferQuestLogData_LinkBattledSingle(u16 *a0, const u16 *eventData)
a0[0] = QL_EVENT_LINK_BATTLED_SINGLE;
a0[1] = sQuestLogIdx;
*((u8 *)a0 + 4) = *((const u8 *)eventData + 0);
- memcpy((u8 *)a0 + 5, (const u8 *)eventData + 1, PLAYER_NAME_LENGTH - 1);
+ memcpy((u8 *)a0 + 5, (const u8 *)eventData + 1, PLAYER_NAME_LENGTH);
a0 += 6;
return a0;
}
@@ -3444,8 +3444,8 @@ static const u16 *BufferQuestLogText_LinkBattledSingle(const u16 *a0)
{
DynamicPlaceholderTextUtil_Reset();
- memset(gStringVar1, EOS, PLAYER_NAME_LENGTH);
- memcpy(gStringVar1, (const u8 *)a0 + 5, PLAYER_NAME_LENGTH - 1);
+ memset(gStringVar1, EOS, PLAYER_NAME_LENGTH + 1);
+ memcpy(gStringVar1, (const u8 *)a0 + 5, PLAYER_NAME_LENGTH);
BufferLinkPartnersName(gStringVar1);
DynamicPlaceholderTextUtil_SetPlaceholderPtr(0, gStringVar1);
DynamicPlaceholderTextUtil_SetPlaceholderPtr(1, sBattleOutcomeTexts[((const u8 *)a0)[4]]);
@@ -3459,7 +3459,7 @@ static u16 *BufferQuestLogData_LinkBattledDouble(u16 *a0, const u16 *eventData)
a0[0] = QL_EVENT_LINK_BATTLED_DOUBLE;
a0[1] = sQuestLogIdx;
*((u8 *)a0 + 4) = *((const u8 *)eventData + 0);
- memcpy((u8 *)a0 + 5, (const u8 *)eventData + 1, PLAYER_NAME_LENGTH - 1);
+ memcpy((u8 *)a0 + 5, (const u8 *)eventData + 1, PLAYER_NAME_LENGTH);
a0 += 6;
return a0;
}
@@ -3468,8 +3468,8 @@ static const u16 *BufferQuestLogText_LinkBattledDouble(const u16 *a0)
{
DynamicPlaceholderTextUtil_Reset();
- memset(gStringVar1, EOS, PLAYER_NAME_LENGTH);
- memcpy(gStringVar1, (const u8 *)a0 + 5, PLAYER_NAME_LENGTH - 1);
+ memset(gStringVar1, EOS, PLAYER_NAME_LENGTH + 1);
+ memcpy(gStringVar1, (const u8 *)a0 + 5, PLAYER_NAME_LENGTH);
BufferLinkPartnersName(gStringVar1);
DynamicPlaceholderTextUtil_SetPlaceholderPtr(0, gStringVar1);
DynamicPlaceholderTextUtil_SetPlaceholderPtr(1, sBattleOutcomeTexts[((const u8 *)a0)[4]]);
@@ -3483,9 +3483,9 @@ static u16 *BufferQuestLogData_LinkBattledMulti(u16 *a0, const u16 *eventData)
a0[0] = QL_EVENT_LINK_BATTLED_MULTI;
a0[1] = sQuestLogIdx;
*((u8 *)a0 + 4) = *((const u8 *)eventData + 0);
- memcpy((u8 *)a0 + 5, (const u8 *)eventData + 1, PLAYER_NAME_LENGTH - 1);
- memcpy((u8 *)a0 + 12, (const u8 *)eventData + 8, PLAYER_NAME_LENGTH - 1);
- memcpy((u8 *)a0 + 19, (const u8 *)eventData + 15, PLAYER_NAME_LENGTH - 1);
+ memcpy((u8 *)a0 + 5, (const u8 *)eventData + 1, PLAYER_NAME_LENGTH);
+ memcpy((u8 *)a0 + 12, (const u8 *)eventData + 8, PLAYER_NAME_LENGTH);
+ memcpy((u8 *)a0 + 19, (const u8 *)eventData + 15, PLAYER_NAME_LENGTH);
a0 += 13;
return a0;
}
@@ -3494,9 +3494,9 @@ static const u16 *BufferQuestLogText_LinkBattledMulti(const u16 *a0)
{
DynamicPlaceholderTextUtil_Reset();
- memset(gStringVar1, EOS, PLAYER_NAME_LENGTH);
- memset(gStringVar2, EOS, PLAYER_NAME_LENGTH);
- memset(gStringVar3, EOS, PLAYER_NAME_LENGTH);
+ memset(gStringVar1, EOS, PLAYER_NAME_LENGTH + 1);
+ memset(gStringVar2, EOS, PLAYER_NAME_LENGTH + 1);
+ memset(gStringVar3, EOS, PLAYER_NAME_LENGTH + 1);
StringCopy7(gStringVar1, (const u8 *)a0 + 5);
StringCopy7(gStringVar2, (const u8 *)a0 + 12);
StringCopy7(gStringVar3, (const u8 *)a0 + 19);
@@ -3548,7 +3548,7 @@ static u16 *BufferQuestLogData_LinkTradedUnionRoom(u16 *a0, const u16 *eventData
a0[1] = sQuestLogIdx;
a0[2] = eventData[0];
a0[3] = eventData[1];
- memcpy(r4, eventData + 2, PLAYER_NAME_LENGTH - 1);
+ memcpy(r4, eventData + 2, PLAYER_NAME_LENGTH);
r4 += 8;
return (u16 *)r4;
}
@@ -3556,8 +3556,8 @@ static u16 *BufferQuestLogData_LinkTradedUnionRoom(u16 *a0, const u16 *eventData
static const u16 *BufferQuestLogText_LinkTradedUnionRoom(const u16 *a0)
{
const u8 *r6 = (const u8 *)(a0 + 4);
- memset(gStringVar1, EOS, PLAYER_NAME_LENGTH);
- memcpy(gStringVar1, r6, PLAYER_NAME_LENGTH - 1);
+ memset(gStringVar1, EOS, PLAYER_NAME_LENGTH + 1);
+ memcpy(gStringVar1, r6, PLAYER_NAME_LENGTH);
BufferLinkPartnersName(gStringVar1);
QuestLog_GetSpeciesName(a0[3], gStringVar2, 0);
QuestLog_GetSpeciesName(a0[2], gStringVar3, 0);
@@ -3571,15 +3571,15 @@ static u16 *BufferQuestLogData_LinkBattledUnionRoom(u16 *a0, const u16 *eventDat
a0[0] = QL_EVENT_LINK_BATTLED_UNION;
a0[1] = sQuestLogIdx;
*(u8 *)&a0[2] = *(const u8 *)&eventData[0];
- memcpy((u8 *)a0 + 5, (const u8 *)eventData + 1, PLAYER_NAME_LENGTH - 1);
+ memcpy((u8 *)a0 + 5, (const u8 *)eventData + 1, PLAYER_NAME_LENGTH);
a0 += 6;
return a0;
}
static const u16 *BufferQuestLogText_LinkBattledUnionRoom(const u16 *a0)
{
- memset(gStringVar1, EOS, PLAYER_NAME_LENGTH);
- memcpy(gStringVar1, (const u8 *)a0 + 5, PLAYER_NAME_LENGTH - 1);
+ memset(gStringVar1, EOS, PLAYER_NAME_LENGTH + 1);
+ memcpy(gStringVar1, (const u8 *)a0 + 5, PLAYER_NAME_LENGTH);
BufferLinkPartnersName(gStringVar1);
StringCopy(gStringVar2, sBattleOutcomeTexts[*(const u8 *)&a0[2]]);
StringExpandPlaceholders(gStringVar4, QuestLog_Text_BattledTrainerEndedInOutcome);
diff --git a/src/seagallop.c b/src/seagallop.c
index 10ea97fec..aa0c48da1 100644
--- a/src/seagallop.c
+++ b/src/seagallop.c
@@ -176,7 +176,7 @@ static const struct SpriteTemplate sWakeSpriteTemplate = {
SpriteCB_Wake
};
-void ScrSpecial_SeagallopFerry(void)
+void DoSeagallopFerryScene(void)
{
SetVBlankCallback(NULL);
HelpSystem_Disable();
@@ -459,7 +459,8 @@ static bool8 GetDirectionOfTravel(void)
return (sTravelDirectionMatrix[gSpecialVar_0x8004] >> gSpecialVar_0x8006) & 1;
}
-u8 sub_8147500(void)
+// For "All aboard SEAGALLOP HI-SPEED ##" text
+u8 GetSeagallopNumber(void)
{
u16 originId, destId;
@@ -478,21 +479,34 @@ u8 sub_8147500(void)
if (originId == SEAGALLOP_BIRTH_ISLAND || destId == SEAGALLOP_BIRTH_ISLAND)
return 12;
- if ((originId == SEAGALLOP_ONE_ISLAND || originId == SEAGALLOP_TWO_ISLAND || originId == SEAGALLOP_THREE_ISLAND) && (destId == SEAGALLOP_ONE_ISLAND || destId == SEAGALLOP_TWO_ISLAND || destId == SEAGALLOP_THREE_ISLAND))
+ if ((originId == SEAGALLOP_ONE_ISLAND
+ || originId == SEAGALLOP_TWO_ISLAND
+ || originId == SEAGALLOP_THREE_ISLAND)
+ && (destId == SEAGALLOP_ONE_ISLAND
+ || destId == SEAGALLOP_TWO_ISLAND
+ || destId == SEAGALLOP_THREE_ISLAND))
return 2;
- if ((originId == SEAGALLOP_FOUR_ISLAND || originId == SEAGALLOP_FIVE_ISLAND) && (destId == SEAGALLOP_FOUR_ISLAND || destId == SEAGALLOP_FIVE_ISLAND))
+ if ((originId == SEAGALLOP_FOUR_ISLAND
+ || originId == SEAGALLOP_FIVE_ISLAND)
+ && (destId == SEAGALLOP_FOUR_ISLAND
+ || destId == SEAGALLOP_FIVE_ISLAND))
return 3;
- if ((originId == SEAGALLOP_SIX_ISLAND || originId == SEAGALLOP_SEVEN_ISLAND) && (destId == SEAGALLOP_SIX_ISLAND || destId == SEAGALLOP_SEVEN_ISLAND))
+ if ((originId == SEAGALLOP_SIX_ISLAND
+ || originId == SEAGALLOP_SEVEN_ISLAND)
+ && (destId == SEAGALLOP_SIX_ISLAND
+ || destId == SEAGALLOP_SEVEN_ISLAND))
return 5;
return 6;
}
-bool8 sub_8147594(void)
+bool8 IsPlayerLeftOfVermilionSailor(void)
{
- if (gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(VERMILION_CITY) && gSaveBlock1Ptr->location.mapNum == MAP_NUM(VERMILION_CITY) && gSaveBlock1Ptr->pos.x < 24)
+ if (gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(VERMILION_CITY)
+ && gSaveBlock1Ptr->location.mapNum == MAP_NUM(VERMILION_CITY)
+ && gSaveBlock1Ptr->pos.x < 24)
return TRUE;
return FALSE;
diff --git a/src/trade.c b/src/trade.c
index 05a259e60..fe5f53be9 100644
--- a/src/trade.c
+++ b/src/trade.c
@@ -1,41 +1,22 @@
#include "global.h"
-#include "palette.h"
+#include "gflib.h"
#include "task.h"
#include "decompress.h"
-#include "gpu_regs.h"
-#include "malloc.h"
-#include "bg.h"
-#include "text.h"
-#include "window.h"
-#include "librfu.h"
#include "text_window.h"
-#include "evolution_scene.h"
#include "pokemon_icon.h"
-#include "pokedex.h"
-#include "mail_data.h"
#include "graphics.h"
#include "link.h"
-#include "random.h"
-#include "save.h"
#include "load_save.h"
-#include "quest_log.h"
-#include "field_fadetransition.h"
-#include "mevent.h"
-#include "help_system.h"
#include "link_rfu.h"
#include "cable_club.h"
#include "data.h"
-#include "sound.h"
-#include "string_util.h"
#include "strings.h"
#include "menu.h"
#include "overworld.h"
#include "battle_anim.h"
#include "pokeball.h"
#include "party_menu.h"
-#include "util.h"
#include "daycare.h"
-#include "script.h"
#include "event_data.h"
#include "battle_interface.h"
#include "pokemon_summary_screen.h"
@@ -43,11 +24,7 @@
#include "new_menu_helpers.h"
#include "trade.h"
#include "trade_scene.h"
-#include "constants/species.h"
-#include "constants/items.h"
-#include "constants/easy_chat.h"
#include "constants/songs.h"
-#include "constants/region_map.h"
#include "constants/moves.h"
struct TradeMenuResources
diff --git a/src/union_room.c b/src/union_room.c
index 4e3428cc6..f942fb7d3 100644
--- a/src/union_room.c
+++ b/src/union_room.c
@@ -1852,7 +1852,7 @@ static void sub_81175BC(u8 taskId)
sub_80F8D14();
SetHostRFUtgtGname(69, 0, 1);
}
- sub_8128420();
+ EnterUnionRoomChat();
break;
case 8:
case 72:
@@ -3385,7 +3385,7 @@ static void sub_81199FC(u8 taskId)
case 2:
if (sUnionRoomPlayerName[0] == EOS)
{
- for (i = 0; i < PLAYER_NAME_LENGTH; i++)
+ for (i = 0; i < PLAYER_NAME_LENGTH + 1; i++)
{
if (structPtr->field_0->arr[i].field_1A_0 == 1)
{
diff --git a/src/union_room_chat.c b/src/union_room_chat.c
new file mode 100644
index 000000000..15601c028
--- /dev/null
+++ b/src/union_room_chat.c
@@ -0,0 +1,1452 @@
+#include "global.h"
+#include "gflib.h"
+#include "dynamic_placeholder_text_util.h"
+#include "help_system.h"
+#include "link.h"
+#include "link_rfu.h"
+#include "load_save.h"
+#include "menu.h"
+#include "overworld.h"
+#include "quest_log.h"
+#include "save.h"
+#include "scanline_effect.h"
+#include "strings.h"
+#include "task.h"
+#include "union_room_chat.h"
+#include "union_room_chat_display.h"
+#include "data_8479668.h"
+#include "constants/songs.h"
+
+#define MESSAGE_BUFFER_NCHAR 15
+
+#define CHAT_MESSAGE_0 0
+#define CHAT_MESSAGE_CHAT 1
+#define CHAT_MESSAGE_JOIN 2
+#define CHAT_MESSAGE_LEAVE 3
+#define CHAT_MESSAGE_DROP 4
+#define CHAT_MESSAGE_DISBAND 5
+
+#define CHATENTRYROUTINE_JOIN 0
+#define CHATNETRYROUTINE_HANDLE_INPUT 1
+#define CHATENTRYROUTINE_SWITCH 2
+#define CHATENTRYROUTINE_ASKQUITCHATTING 3
+#define CHATENTRYROUTINE_SEND 4
+#define CHATENTRYROUTINE_REGISTER 5
+#define CHATENTRYROUTINE_EXITCHAT 6
+#define CHATENTRYROUTINE_DROP 7
+#define CHATENTRYROUTINE_DISBANDED 8
+#define CHATENTRYROUTINE_SAVEANDEXIT 9
+
+#define CHATEXIT_NONE 0
+#define CHATEXIT_LEADER_LAST 1
+#define CHATEXIT_DROPPED 2
+#define CHATEXIT_DISBANDED 3
+
+struct UnionRoomChat
+{
+ u8 filler0[0x4];
+ u16 routineNo;
+ u16 routineState;
+ u8 filler8[0x2];
+ u16 exitDelayTimer;
+ u8 fillerC[0x1];
+ u8 linkPlayerCount;
+ u8 handleInputTask;
+ u8 receiveMessagesTask;
+ u8 currentPage;
+ u8 currentCol;
+ u8 currentRow;
+ u8 multiplayerId;
+ u8 lastBufferCursorPos;
+ u8 bufferCursorPos;
+ u8 receivedPlayerIndex;
+ u8 exitType;
+ bool8 changedRegisteredTexts;
+ u8 afterSaveTimer;
+ u8 messageEntryBuffer[2 * MESSAGE_BUFFER_NCHAR + 1];
+ u8 receivedMessage[0x40];
+ u8 hostName[0x40];
+ u8 registeredTexts[UNION_ROOM_KB_ROW_COUNT][21];
+ u8 filler18B[0x5];
+ u8 sendMessageBuffer[0x28];
+};
+
+static EWRAM_DATA struct UnionRoomChat * sWork = NULL;
+
+static void InitChatWork(struct UnionRoomChat * unionRoomChat);
+static void CB2_LoadInterface(void);
+static void VBlankCB_UnionRoomChatMain(void);
+static void CB2_UnionRoomChatMain(void);
+static void Task_HandlePlayerInput(u8 taskId);
+static void ChatEntryRoutine_Join(void);
+static void ChatEntryRoutine_HandleInput(void);
+static void ChatEntryRoutine_Switch(void);
+static void ChatEntryRoutine_AskQuitChatting(void);
+static void ChatEntryRoutine_ExitChat(void);
+static void ChatEntryRoutine_Drop(void);
+static void ChatEntryRoutine_Disbanded(void);
+static void ChatEntryRoutine_SendMessage(void);
+static void ChatEntryRoutine_Register(void);
+static void ChatEntryRoutine_SaveAndExit(void);
+static void GoToRoutine(u16 routineNo);
+static bool32 TypeChatMessage_HandleDPad(void);
+static void AppendCharacterToChatMessageBuffer(void);
+static void DeleteLastCharacterOfChatMessageBuffer(void);
+static void ToggleCaseOfLastCharacterInChatMessageBuffer(void);
+static bool32 ChatMsgHasAtLeastOneCharcter(void);
+static void RegisterTextAtRow(void);
+static void ResetMessageEntryBuffer(void);
+static void SaveRegisteredTextsToSB1(void);
+static u8 *GetEndOfUnk1A(void);
+static u8 *GetPtrToLastCharOfUnk1A(void);
+static void PrepareSendBuffer_Null(u8 *ptr);
+static void PrepareSendBuffer_Join(u8 *ptr);
+static void PrepareSendBuffer_Chat(u8 *ptr);
+static void PrepareSendBuffer_Leave(u8 *ptr);
+static void PrepareSendBuffer_Drop(u8 *ptr);
+static void PrepareSendBuffer_Disband(u8 *ptr);
+static void Task_ReceiveChatMessage(u8 taskId);
+
+static void (*const sChatEntryRoutines[])(void) = {
+ [CHATENTRYROUTINE_JOIN] = ChatEntryRoutine_Join,
+ [CHATNETRYROUTINE_HANDLE_INPUT] = ChatEntryRoutine_HandleInput,
+ [CHATENTRYROUTINE_SWITCH] = ChatEntryRoutine_Switch,
+ [CHATENTRYROUTINE_ASKQUITCHATTING] = ChatEntryRoutine_AskQuitChatting,
+ [CHATENTRYROUTINE_SEND] = ChatEntryRoutine_SendMessage,
+ [CHATENTRYROUTINE_REGISTER] = ChatEntryRoutine_Register,
+ [CHATENTRYROUTINE_EXITCHAT] = ChatEntryRoutine_ExitChat,
+ [CHATENTRYROUTINE_DROP] = ChatEntryRoutine_Drop,
+ [CHATENTRYROUTINE_DISBANDED] = ChatEntryRoutine_Disbanded,
+ [CHATENTRYROUTINE_SAVEANDEXIT] = ChatEntryRoutine_SaveAndExit
+};
+
+static const u8 sKeyboardPageMaxRow[] =
+{
+ [UNION_ROOM_KB_PAGE_UPPER] = 9,
+ [UNION_ROOM_KB_PAGE_LOWER] = 9,
+ [UNION_ROOM_KB_PAGE_EMOJI] = 9,
+ 9
+};
+
+static const u8 sCaseToggleTable[] = {
+ 0x00, 0x16, 0x17, 0x68, 0x19, 0x1A, 0x1B, 0x1C,
+ 0x1D, 0x1E, 0x00, 0x20, 0x21, 0x22, 0x23, 0x24,
+ 0x25, 0x26, 0x27, 0x28, 0x29, 0x15, 0x01, 0x02,
+ 0x00, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00,
+ 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12,
+ 0x13, 0x14, 0x2A, 0x2B, 0x2C, 0x2D, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x36, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x53, 0x54, 0x55, 0x56, 0x00,
+ 0x00, 0x00, 0x6F, 0x5B, 0x5C, 0x5D, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x84, 0x85, 0x86, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
+ 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
+ 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
+ 0xB8, 0xB9, 0xBA, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9,
+ 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1,
+ 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9,
+ 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xBB, 0xBC, 0xBD,
+ 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5,
+ 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD,
+ 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xEF,
+ 0xF0, 0xF4, 0xF5, 0xF6, 0xF1, 0xF2, 0xF3, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+const u8 *const gUnionRoomKeyboardText[UNION_ROOM_KB_PAGE_COUNT][UNION_ROOM_KB_ROW_COUNT] = {
+ [UNION_ROOM_KB_PAGE_UPPER] = {
+ gText_UnionRoomChatKeyboard_ABCDE,
+ gText_UnionRoomChatKeyboard_FGHIJ,
+ gText_UnionRoomChatKeyboard_KLMNO,
+ gText_UnionRoomChatKeyboard_PQRST,
+ gText_UnionRoomChatKeyboard_UVWXY,
+ gText_UnionRoomChatKeyboard_Z,
+ gText_UnionRoomChatKeyboard_01234Upper,
+ gText_UnionRoomChatKeyboard_56789Upper,
+ gText_UnionRoomChatKeyboard_PunctuationUpper,
+ gText_UnionRoomChatKeyboard_SymbolsUpper
+ },
+ [UNION_ROOM_KB_PAGE_LOWER] = {
+ gText_UnionRoomChatKeyboard_abcde,
+ gText_UnionRoomChatKeyboard_fghij,
+ gText_UnionRoomChatKeyboard_klmno,
+ gText_UnionRoomChatKeyboard_pqrst,
+ gText_UnionRoomChatKeyboard_uvwxy,
+ gText_UnionRoomChatKeyboard_z,
+ gText_UnionRoomChatKeyboard_01234Lower,
+ gText_UnionRoomChatKeyboard_56789Lower,
+ gText_UnionRoomChatKeyboard_PunctuationLower,
+ gText_UnionRoomChatKeyboard_SymbolsLower
+ },
+ [UNION_ROOM_KB_PAGE_EMOJI] = {
+ gText_UnionRoomChatKeyboard_Emoji1,
+ gText_UnionRoomChatKeyboard_Emoji2,
+ gText_UnionRoomChatKeyboard_Emoji3,
+ gText_UnionRoomChatKeyboard_Emoji4,
+ gText_UnionRoomChatKeyboard_Emoji5,
+ gText_UnionRoomChatKeyboard_Emoji6,
+ gText_UnionRoomChatKeyboard_Emoji7,
+ gText_UnionRoomChatKeyboard_Emoji8,
+ gText_UnionRoomChatKeyboard_Emoji9,
+ gText_UnionRoomChatKeyboard_Emoji10
+ }
+};
+
+void EnterUnionRoomChat(void)
+{
+ sWork = Alloc(sizeof(struct UnionRoomChat));
+ InitChatWork(sWork);
+ gKeyRepeatStartDelay = 20;
+ sub_812B4AC();
+ SetVBlankCallback(NULL);
+ SetMainCallback2(CB2_LoadInterface);
+}
+
+static void InitChatWork(struct UnionRoomChat * unionRoomChat)
+{
+ int i;
+
+ unionRoomChat->routineNo = CHATENTRYROUTINE_JOIN;
+ unionRoomChat->routineState = 0;
+ unionRoomChat->currentPage = UNION_ROOM_KB_PAGE_UPPER;
+ unionRoomChat->currentCol = 0;
+ unionRoomChat->currentRow = 0;
+ unionRoomChat->lastBufferCursorPos = 0;
+ unionRoomChat->bufferCursorPos = 0;
+ unionRoomChat->receivedPlayerIndex = 0;
+ unionRoomChat->messageEntryBuffer[0] = EOS;
+ unionRoomChat->linkPlayerCount = GetLinkPlayerCount();
+ unionRoomChat->multiplayerId = GetMultiplayerId();
+ unionRoomChat->exitType = 0;
+ unionRoomChat->changedRegisteredTexts = FALSE;
+ PrepareSendBuffer_Null(unionRoomChat->sendMessageBuffer);
+ for (i = 0; i < UNION_ROOM_KB_ROW_COUNT; i++)
+ StringCopy(unionRoomChat->registeredTexts[i], gSaveBlock1Ptr->registeredTexts[i]);
+}
+
+static void FreeChatWork(void)
+{
+ DestroyTask(sWork->handleInputTask);
+ DestroyTask(sWork->receiveMessagesTask);
+ Free(sWork);
+}
+
+static void CB2_LoadInterface(void)
+{
+ switch (gMain.state)
+ {
+ case 0:
+ ResetTasks();
+ ResetSpriteData();
+ FreeAllSpritePalettes();
+ UnionRoomChat_TryAllocGraphicsWork();
+ gMain.state++;
+ break;
+ case 1:
+ UnionRoomChat_RunDisplaySubtasks();
+ if (!UnionRoomChat_RunDisplaySubtask0())
+ {
+ BlendPalettes(0xFFFFFFFF, 16, RGB_BLACK);
+ BeginNormalPaletteFade(0xFFFFFFFF, -1, 16, 0, RGB_BLACK);
+ SetVBlankCallback(VBlankCB_UnionRoomChatMain);
+ gMain.state++;
+ }
+ break;
+ case 2:
+ UpdatePaletteFade();
+ if (!gPaletteFade.active)
+ {
+ SetMainCallback2(CB2_UnionRoomChatMain);
+ SetQuestLogEvent(QL_EVENT_USED_UNION_ROOM_CHAT, NULL);
+ sWork->handleInputTask = CreateTask(Task_HandlePlayerInput, 8);
+ sWork->receiveMessagesTask = CreateTask(Task_ReceiveChatMessage, 7);
+ LoadWirelessStatusIndicatorSpriteGfx();
+ CreateWirelessStatusIndicatorSprite(232, 150);
+ }
+ break;
+ }
+}
+
+static void VBlankCB_UnionRoomChatMain(void)
+{
+ TransferPlttBuffer();
+ LoadOam();
+ ProcessSpriteCopyRequests();
+ ScanlineEffect_InitHBlankDmaTransfer();
+}
+
+static void CB2_UnionRoomChatMain(void)
+{
+ RunTasks();
+ UnionRoomChat_RunDisplaySubtasks();
+ AnimateSprites();
+ BuildOamBuffer();
+ UpdatePaletteFade();
+}
+
+static void Task_HandlePlayerInput(u8 taskId)
+{
+ switch (sWork->exitType)
+ {
+ case CHATEXIT_LEADER_LAST:
+ GoToRoutine(CHATENTRYROUTINE_EXITCHAT);
+ sWork->exitType = CHATEXIT_NONE;
+ break;
+ case CHATEXIT_DROPPED:
+ GoToRoutine(CHATENTRYROUTINE_DROP);
+ sWork->exitType = CHATEXIT_NONE;
+ break;
+ case CHATEXIT_DISBANDED:
+ GoToRoutine(CHATENTRYROUTINE_DISBANDED);
+ sWork->exitType = CHATEXIT_NONE;
+ break;
+ }
+
+ sChatEntryRoutines[sWork->routineNo]();
+}
+
+static void ChatEntryRoutine_Join(void)
+{
+ switch (sWork->routineState)
+ {
+ case 0:
+ PrepareSendBuffer_Join(sWork->sendMessageBuffer);
+ sWork->routineState++;
+ // fall through
+ case 1:
+ if (IsLinkTaskFinished() && !GetRfuUnkCE8())
+ {
+ if (SendBlock(0, sWork->sendMessageBuffer, sizeof(sWork->sendMessageBuffer)))
+ sWork->routineState++;
+ }
+ break;
+ case 2:
+ if (IsLinkTaskFinished())
+ GoToRoutine(CHATNETRYROUTINE_HANDLE_INPUT);
+ break;
+ }
+}
+
+static void ChatEntryRoutine_HandleInput(void)
+{
+ bool8 var0, var1;
+
+ switch (sWork->routineState)
+ {
+ case 0:
+ if (JOY_NEW(START_BUTTON))
+ {
+ if (sWork->bufferCursorPos)
+ GoToRoutine(CHATENTRYROUTINE_SEND);
+ }
+ else if (JOY_NEW(SELECT_BUTTON))
+ {
+ GoToRoutine(CHATENTRYROUTINE_SWITCH);
+ }
+ else if (JOY_REPT(B_BUTTON))
+ {
+ if (sWork->bufferCursorPos)
+ {
+ DeleteLastCharacterOfChatMessageBuffer();
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_PRINTMSG, 0);
+ sWork->routineState = 1;
+ }
+ else
+ {
+ GoToRoutine(CHATENTRYROUTINE_ASKQUITCHATTING);
+ }
+ }
+ else if (JOY_NEW(A_BUTTON))
+ {
+ AppendCharacterToChatMessageBuffer();
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_PRINTMSG, 0);
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_CURSORBLINK, 1);
+ sWork->routineState = 1;
+ }
+ else if (JOY_NEW(R_BUTTON))
+ {
+ if (sWork->currentPage != UNION_ROOM_KB_PAGE_COUNT)
+ {
+ ToggleCaseOfLastCharacterInChatMessageBuffer();
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_PRINTMSG, 0);
+ sWork->routineState = 1;
+ }
+ else
+ {
+ GoToRoutine(CHATENTRYROUTINE_REGISTER);
+ }
+ }
+ else if (TypeChatMessage_HandleDPad())
+ {
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_MOVEKBCURSOR, 0);
+ sWork->routineState = 1;
+ }
+ break;
+ case 1:
+ var0 = RunDisplaySubtask(0);
+ var1 = RunDisplaySubtask(1);
+ if (!var0 && !var1)
+ sWork->routineState = 0;
+ break;
+ }
+}
+
+static void ChatEntryRoutine_Switch(void)
+{
+ s16 input;
+ bool32 shouldSwitchPages;
+
+ switch (sWork->routineState)
+ {
+ case 0:
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_SHOWKBSWAPMENU, 0);
+ sWork->routineState++;
+ break;
+ case 1:
+ if (!RunDisplaySubtask(0))
+ sWork->routineState++;
+ break;
+ case 2:
+ input = Menu_ProcessInput();
+ switch (input)
+ {
+ default:
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_HIDEKBSWAPMENU, 0);
+ shouldSwitchPages = TRUE;
+ if (sWork->currentPage == input || input > UNION_ROOM_KB_PAGE_COUNT)
+ shouldSwitchPages = FALSE;
+ break;
+ case MENU_NOTHING_CHOSEN:
+ if (JOY_NEW(SELECT_BUTTON))
+ {
+ PlaySE(SE_SELECT);
+ Menu_MoveCursor(1);
+ }
+ return;
+ case MENU_B_PRESSED:
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_HIDEKBSWAPMENU, 0);
+ sWork->routineState = 3;
+ return;
+ }
+
+ if (!shouldSwitchPages)
+ {
+ sWork->routineState = 3;
+ return;
+ }
+
+ sWork->currentCol = 0;
+ sWork->currentRow = 0;
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_SWITCHPAGES, 1);
+ sWork->currentPage = input;
+ sWork->routineState = 4;
+ break;
+ case 3:
+ // Wait Return To Prev Page
+ if (!RunDisplaySubtask(0))
+ GoToRoutine(CHATNETRYROUTINE_HANDLE_INPUT);
+ break;
+ case 4:
+ // Wait Page Switch
+ if (!RunDisplaySubtask(0) && !RunDisplaySubtask(1))
+ GoToRoutine(CHATNETRYROUTINE_HANDLE_INPUT);
+ break;
+ }
+}
+
+static void ChatEntryRoutine_AskQuitChatting(void)
+{
+ s8 input;
+
+ switch (sWork->routineState)
+ {
+ case 0:
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_SHOWQUITCHATTINGDIALOG, 0);
+ sWork->routineState = 1;
+ break;
+ case 1:
+ if (!RunDisplaySubtask(0))
+ sWork->routineState = 2;
+ break;
+ case 2:
+ input = UnionRoomChat_ProcessInput();
+ switch (input)
+ {
+ case -1:
+ case 1:
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_DESTROYSTDMSGANDYESNO, 0);
+ sWork->routineState = 3;
+ break;
+ case 0:
+ if (sWork->multiplayerId == 0)
+ {
+ PrepareSendBuffer_Disband(sWork->sendMessageBuffer);
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_DESTROYSTDMSGANDYESNO, 0);
+ sWork->routineState = 9;
+ }
+ else
+ {
+ PrepareSendBuffer_Leave(sWork->sendMessageBuffer);
+ sWork->routineState = 4;
+ }
+ break;
+ }
+ break;
+ case 3:
+ if (!RunDisplaySubtask(0))
+ GoToRoutine(CHATNETRYROUTINE_HANDLE_INPUT);
+ break;
+ case 9:
+ if (!RunDisplaySubtask(0))
+ {
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_SHOWCONFIRMLEADERLEAVEDIALOG, 0);
+ sWork->routineState = 10;
+ }
+ break;
+ case 10:
+ if (!RunDisplaySubtask(0))
+ sWork->routineState = 8;
+ break;
+ case 8:
+ input = UnionRoomChat_ProcessInput();
+ switch (input)
+ {
+ case -1:
+ case 1:
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_DESTROYSTDMSGANDYESNO, 0);
+ sWork->routineState = 3;
+ break;
+ case 0:
+ sub_80FA4A8();
+ PrepareSendBuffer_Disband(sWork->sendMessageBuffer);
+ sWork->routineState = 4;
+ break;
+ }
+ break;
+ case 4:
+ if (IsLinkTaskFinished() && !GetRfuUnkCE8() && SendBlock(0, sWork->sendMessageBuffer, sizeof(sWork->sendMessageBuffer)))
+ {
+ if (sWork->multiplayerId == 0)
+ sWork->routineState = 6;
+ else
+ sWork->routineState = 5;
+ }
+ break;
+ case 5:
+ if (gReceivedRemoteLinkPlayers == 0)
+ {
+ GoToRoutine(CHATENTRYROUTINE_SAVEANDEXIT);
+ }
+ break;
+ }
+}
+
+static void ChatEntryRoutine_ExitChat(void)
+{
+ switch (sWork->routineState)
+ {
+ case 0:
+ if (!FuncIsActiveTask(Task_ReceiveChatMessage))
+ {
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_DESTROYSTDMSGANDYESNO, 0);
+ sWork->routineState++;
+ }
+ break;
+ case 1:
+ if (!RunDisplaySubtask(0))
+ {
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_PRINTEXITINGCHAT, 0);
+ sWork->routineState++;
+ }
+ break;
+ case 2:
+ if (!RunDisplaySubtask(0))
+ {
+ PrepareSendBuffer_Drop(sWork->sendMessageBuffer);
+ sWork->routineState++;
+ }
+ break;
+ case 3:
+ if (IsLinkTaskFinished() && !GetRfuUnkCE8() && SendBlock(0, sWork->sendMessageBuffer, sizeof(sWork->sendMessageBuffer)))
+ sWork->routineState++;
+ break;
+ case 4:
+ if ((GetBlockReceivedStatus() & 1) && !GetRfuUnkCE8())
+ sWork->routineState++;
+ break;
+ case 5:
+ if (IsLinkTaskFinished() && !GetRfuUnkCE8())
+ {
+ sub_800AAC0();
+ sWork->exitDelayTimer = 0;
+ sWork->routineState++;
+ }
+ break;
+ case 6:
+ if (sWork->exitDelayTimer < 150)
+ sWork->exitDelayTimer++;
+
+ if (!gReceivedRemoteLinkPlayers)
+ sWork->routineState++;
+ break;
+ case 7:
+ if (sWork->exitDelayTimer >= 150)
+ GoToRoutine(CHATENTRYROUTINE_SAVEANDEXIT);
+ else
+ sWork->exitDelayTimer++;
+ break;
+ }
+}
+
+static void ChatEntryRoutine_Drop(void)
+{
+ switch (sWork->routineState)
+ {
+ case 0:
+ if (!FuncIsActiveTask(Task_ReceiveChatMessage))
+ {
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_DESTROYSTDMSGANDYESNO, 0);
+ sWork->routineState++;
+ }
+ break;
+ case 1:
+ if (!RunDisplaySubtask(0) && IsLinkTaskFinished() && !GetRfuUnkCE8())
+ {
+ sub_800AAC0();
+ sWork->exitDelayTimer = 0;
+ sWork->routineState++;
+ }
+ break;
+ case 2:
+ if (sWork->exitDelayTimer < 150)
+ sWork->exitDelayTimer++;
+
+ if (!gReceivedRemoteLinkPlayers)
+ sWork->routineState++;
+ break;
+ case 3:
+ if (sWork->exitDelayTimer >= 150)
+ GoToRoutine(CHATENTRYROUTINE_SAVEANDEXIT);
+ else
+ sWork->exitDelayTimer++;
+ break;
+ }
+}
+
+static void ChatEntryRoutine_Disbanded(void)
+{
+ switch (sWork->routineState)
+ {
+ case 0:
+ if (!FuncIsActiveTask(Task_ReceiveChatMessage))
+ {
+ if (sWork->multiplayerId)
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_DESTROYSTDMSGANDYESNO, 0);
+
+ sWork->routineState++;
+ }
+ break;
+ case 1:
+ if (!RunDisplaySubtask(0))
+ {
+ if (sWork->multiplayerId != 0)
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_PRINTLEADERLEFT, 0);
+
+ sWork->routineState++;
+ }
+ break;
+ case 2:
+ if (RunDisplaySubtask(0) != TRUE && IsLinkTaskFinished() && !GetRfuUnkCE8())
+ {
+ sub_800AAC0();
+ sWork->exitDelayTimer = 0;
+ sWork->routineState++;
+ }
+ break;
+ case 3:
+ if (sWork->exitDelayTimer < 150)
+ sWork->exitDelayTimer++;
+
+ if (!gReceivedRemoteLinkPlayers)
+ sWork->routineState++;
+ break;
+ case 4:
+ if (sWork->exitDelayTimer >= 150)
+ GoToRoutine(CHATENTRYROUTINE_SAVEANDEXIT);
+ else
+ sWork->exitDelayTimer++;
+ break;
+ }
+}
+
+static void ChatEntryRoutine_SendMessage(void)
+{
+ switch (sWork->routineState)
+ {
+ case 0:
+ if (!gReceivedRemoteLinkPlayers)
+ {
+ GoToRoutine(CHATNETRYROUTINE_HANDLE_INPUT);
+ break;
+ }
+
+ PrepareSendBuffer_Chat(sWork->sendMessageBuffer);
+ sWork->routineState++;
+ // fall through
+ case 1:
+ if (IsLinkTaskFinished() == TRUE && !GetRfuUnkCE8() && SendBlock(0, sWork->sendMessageBuffer, sizeof(sWork->sendMessageBuffer)))
+ sWork->routineState++;
+ break;
+ case 2:
+ ResetMessageEntryBuffer();
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_PRINTMSG, 0);
+ sWork->routineState++;
+ break;
+ case 3:
+ if (!RunDisplaySubtask(0))
+ sWork->routineState++;
+ break;
+ case 4:
+ if (IsLinkTaskFinished())
+ GoToRoutine(CHATNETRYROUTINE_HANDLE_INPUT);
+ break;
+ }
+}
+
+static void ChatEntryRoutine_Register(void)
+{
+ switch (sWork->routineState)
+ {
+ case 0:
+ if (ChatMsgHasAtLeastOneCharcter())
+ {
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_PRINTREGISTERWHERE, 0);
+ sWork->routineState = 2;
+ }
+ else
+ {
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_PRINTINPUTTEXT, 0);
+ sWork->routineState = 5;
+ }
+ break;
+ case 1:
+ if (JOY_NEW(A_BUTTON))
+ {
+ RegisterTextAtRow();
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_RETURNTOKB, 0);
+ sWork->routineState = 3;
+ }
+ else if (JOY_NEW(B_BUTTON))
+ {
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_CANCELREGISTER, 0);
+ sWork->routineState = 4;
+ }
+ else if (TypeChatMessage_HandleDPad())
+ {
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_MOVEKBCURSOR, 0);
+ sWork->routineState = 2;
+ }
+ break;
+ case 2:
+ if (!RunDisplaySubtask(0))
+ sWork->routineState = 1;
+ break;
+ case 3:
+ if (!RunDisplaySubtask(0))
+ {
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_CANCELREGISTER, 0);
+ sWork->routineState = 4;
+ }
+ break;
+ case 4:
+ if (!RunDisplaySubtask(0))
+ GoToRoutine(CHATNETRYROUTINE_HANDLE_INPUT);
+ break;
+ case 5:
+ if (!RunDisplaySubtask(0))
+ sWork->routineState = 6;
+ break;
+ case 6:
+ if (JOY_NEW(A_BUTTON | B_BUTTON))
+ {
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_DESTROYSTDMSGANDYESNO, 0);
+ sWork->routineState = 4;
+ }
+ break;
+ }
+}
+
+static void ChatEntryRoutine_SaveAndExit(void)
+{
+ s8 input;
+
+ switch (sWork->routineState)
+ {
+ case 0:
+ if (!sWork->changedRegisteredTexts)
+ {
+ sWork->routineState = 12;
+ }
+ else
+ {
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_DESTROYSTDMSGANDYESNO, 0);
+ sWork->routineState = 1;
+ }
+ break;
+ case 1:
+ if (!RunDisplaySubtask(0))
+ {
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_ASKSAVE, 0);
+ sWork->routineState = 2;
+ }
+ break;
+ case 2:
+ input = UnionRoomChat_ProcessInput();
+ switch (input)
+ {
+ case -1:
+ case 1:
+ sWork->routineState = 12;
+ break;
+ case 0:
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_DESTROYSTDMSGANDYESNO, 0);
+ sWork->routineState = 3;
+ break;
+ }
+ break;
+ case 3:
+ if (!RunDisplaySubtask(0))
+ {
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_ASKOVERWRITESAVE, 0);
+ sWork->routineState = 4;
+ }
+ break;
+ case 4:
+ if (!RunDisplaySubtask(0))
+ sWork->routineState = 5;
+ break;
+ case 5:
+ input = UnionRoomChat_ProcessInput();
+ switch (input)
+ {
+ case -1:
+ case 1:
+ sWork->routineState = 12;
+ break;
+ case 0:
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_DESTROYSTDMSGANDYESNO, 0);
+ sWork->routineState = 6;
+ break;
+ }
+ break;
+ case 6:
+ if (!RunDisplaySubtask(0))
+ {
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_PRINTSAVING, 0);
+ SaveRegisteredTextsToSB1();
+ sWork->routineState = 7;
+ }
+ break;
+ case 7:
+ if (!RunDisplaySubtask(0))
+ {
+ SetContinueGameWarpStatusToDynamicWarp();
+ TrySavingData(SAVE_NORMAL);
+ sWork->routineState = 8;
+ }
+ break;
+ case 8:
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_PRINTSAVEDTHEGAME, 0);
+ sWork->routineState = 9;
+ break;
+ case 9:
+ if (!RunDisplaySubtask(0))
+ {
+ PlaySE(SE_SAVE);
+ ClearContinueGameWarpStatus2();
+ sWork->routineState = 10;
+ }
+ break;
+ case 10:
+ sWork->afterSaveTimer = 0;
+ sWork->routineState = 11;
+ break;
+ case 11:
+ sWork->afterSaveTimer++;
+ if (sWork->afterSaveTimer > 120)
+ sWork->routineState = 12;
+ break;
+ case 12:
+ BeginNormalPaletteFade(0xFFFFFFFF, -1, 0, 16, RGB_BLACK);
+ sWork->routineState = 13;
+ break;
+ case 13:
+ if (!gPaletteFade.active)
+ {
+ sub_812B4B8();
+ UnionRoomChat_FreeGraphicsWork();
+ FreeChatWork();
+ SetMainCallback2(CB2_ReturnToField);
+ }
+ break;
+ }
+}
+
+static void GoToRoutine(u16 routineNo)
+{
+ sWork->routineNo = routineNo;
+ sWork->routineState = 0;
+}
+
+static bool32 TypeChatMessage_HandleDPad(void)
+{
+ do
+ {
+ if (JOY_REPT(DPAD_UP))
+ {
+ if (sWork->currentRow)
+ sWork->currentRow--;
+ else
+ sWork->currentRow = sKeyboardPageMaxRow[sWork->currentPage];
+
+ break;
+ }
+ if (JOY_REPT(DPAD_DOWN))
+ {
+ if (sWork->currentRow < sKeyboardPageMaxRow[sWork->currentPage])
+ {
+ sWork->currentRow++;
+ }
+ else
+ {
+ sWork->currentRow = 0;
+ }
+
+ break;
+ }
+ if (sWork->currentPage != UNION_ROOM_KB_PAGE_COUNT)
+ {
+ if (JOY_REPT(DPAD_LEFT))
+ {
+ if (sWork->currentCol)
+ sWork->currentCol--;
+ else
+ sWork->currentCol = 4;
+ break;
+ }
+ if (JOY_REPT(DPAD_RIGHT))
+ {
+ if (sWork->currentCol < 4)
+ sWork->currentCol++;
+ else
+ sWork->currentCol = 0;
+ break;
+ }
+ }
+
+ return FALSE;
+ } while (0);
+ return TRUE;
+}
+
+static void AppendCharacterToChatMessageBuffer(void)
+{
+ int i;
+ const u8 *charsStr;
+ int strLength;
+ u8 *str;
+ u8 buffer[21];
+
+ if (sWork->currentPage != UNION_ROOM_KB_PAGE_COUNT)
+ {
+ charsStr = gUnionRoomKeyboardText[sWork->currentPage][sWork->currentRow];
+ for (i = 0; i < sWork->currentCol; i++)
+ {
+ if (*charsStr == CHAR_EXTRA_EMOJI)
+ charsStr++;
+ charsStr++;
+ }
+
+ strLength = 1;
+ }
+ else
+ {
+ u8 *tempStr = StringCopy(buffer, sWork->registeredTexts[sWork->currentRow]);
+ tempStr[0] = CHAR_SPACE;
+ tempStr[1] = EOS;
+ charsStr = buffer;
+ strLength = StringLength_Multibyte(buffer);
+ }
+
+ sWork->lastBufferCursorPos = sWork->bufferCursorPos;
+ if (!charsStr)
+ return;
+
+ str = GetEndOfUnk1A();
+ while (--strLength != -1 && sWork->bufferCursorPos < MESSAGE_BUFFER_NCHAR)
+ {
+ if (*charsStr == CHAR_EXTRA_EMOJI)
+ {
+ *str = *charsStr;
+ charsStr++;
+ str++;
+ }
+
+ *str = *charsStr;
+ charsStr++;
+ str++;
+
+ sWork->bufferCursorPos++;
+ }
+
+ *str = EOS;
+}
+
+static void DeleteLastCharacterOfChatMessageBuffer(void)
+{
+ sWork->lastBufferCursorPos = sWork->bufferCursorPos;
+ if (sWork->bufferCursorPos)
+ {
+ u8 *str = GetPtrToLastCharOfUnk1A();
+ *str = EOS;
+ sWork->bufferCursorPos--;
+ }
+}
+
+static void ToggleCaseOfLastCharacterInChatMessageBuffer(void)
+{
+ u8 *str;
+ u8 character;
+
+ sWork->lastBufferCursorPos = sWork->bufferCursorPos - 1;
+ str = GetPtrToLastCharOfUnk1A();
+ if (*str != CHAR_EXTRA_EMOJI)
+ {
+ character = sCaseToggleTable[*str];
+ if (character)
+ *str = character;
+ }
+}
+
+static bool32 ChatMsgHasAtLeastOneCharcter(void)
+{
+ if (sWork->bufferCursorPos)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+static void RegisterTextAtRow(void)
+{
+ u8 *src = UnionRoomChat_GetEndOfMessageEntryBuffer();
+ StringCopy(sWork->registeredTexts[sWork->currentRow], src);
+ sWork->changedRegisteredTexts = TRUE;
+}
+
+static void ResetMessageEntryBuffer(void)
+{
+ sWork->messageEntryBuffer[0] = EOS;
+ sWork->lastBufferCursorPos = MESSAGE_BUFFER_NCHAR;
+ sWork->bufferCursorPos = 0;
+}
+
+static void SaveRegisteredTextsToSB1(void)
+{
+ int i;
+ for (i = 0; i < UNION_ROOM_KB_ROW_COUNT; i++)
+ StringCopy(gSaveBlock1Ptr->registeredTexts[i], sWork->registeredTexts[i]);
+}
+
+u8 *UnionRoomChat_GetWorkRegisteredText(int arg0)
+{
+ return sWork->registeredTexts[arg0];
+}
+
+static u8 *GetEndOfUnk1A(void)
+{
+ u8 *str = sWork->messageEntryBuffer;
+ while (*str != EOS)
+ str++;
+
+ return str;
+}
+
+static u8 *GetPtrToLastCharOfUnk1A(void)
+{
+ u8 *str = sWork->messageEntryBuffer;
+ u8 *str2 = str;
+ while (*str != EOS)
+ {
+ str2 = str;
+ if (*str == CHAR_EXTRA_EMOJI)
+ str++;
+ str++;
+ }
+
+ return str2;
+}
+
+static u16 GetNumCharsInMessageEntryBuffer(void)
+{
+ u8 *str;
+ u32 i, numChars, strLength;
+
+ strLength = StringLength_Multibyte(sWork->messageEntryBuffer);
+ str = sWork->messageEntryBuffer;
+ numChars = 0;
+ if (strLength > 10)
+ {
+ strLength -= 10;
+ for (i = 0; i < strLength; i++)
+ {
+ if (*str == CHAR_EXTRA_EMOJI)
+ str++;
+
+ str++;
+ numChars++;
+ }
+ }
+
+ return numChars;
+}
+
+static void PrepareSendBuffer_Null(u8 *arg0)
+{
+ arg0[0] = CHAT_MESSAGE_0;
+}
+
+static void PrepareSendBuffer_Join(u8 *arg0)
+{
+ arg0[0] = CHAT_MESSAGE_JOIN;
+ StringCopy(&arg0[1], gSaveBlock2Ptr->playerName);
+ arg0[1 + (PLAYER_NAME_LENGTH + 1)] = sWork->multiplayerId;
+}
+
+static void PrepareSendBuffer_Chat(u8 *arg0)
+{
+ arg0[0] = CHAT_MESSAGE_CHAT;
+ StringCopy(&arg0[1], gSaveBlock2Ptr->playerName);
+ StringCopy(&arg0[1 + (PLAYER_NAME_LENGTH + 1)], sWork->messageEntryBuffer);
+}
+
+static void PrepareSendBuffer_Leave(u8 *arg0)
+{
+ arg0[0] = CHAT_MESSAGE_LEAVE;
+ StringCopy(&arg0[1], gSaveBlock2Ptr->playerName);
+ arg0[1 + (PLAYER_NAME_LENGTH + 1)] = sWork->multiplayerId;
+ sub_80FB9D0();
+}
+
+static void PrepareSendBuffer_Drop(u8 *arg0)
+{
+ arg0[0] = CHAT_MESSAGE_DROP;
+ StringCopy(&arg0[1], gSaveBlock2Ptr->playerName);
+ arg0[1 + (PLAYER_NAME_LENGTH + 1)] = sWork->multiplayerId;
+}
+
+static void PrepareSendBuffer_Disband(u8 *arg0)
+{
+ arg0[0] = CHAT_MESSAGE_DISBAND;
+ StringCopy(&arg0[1], gSaveBlock2Ptr->playerName);
+ arg0[1 + (PLAYER_NAME_LENGTH + 1)] = sWork->multiplayerId;
+}
+
+static bool32 ProcessReceivedChatMessage(u8 *dest, u8 *recvMessage)
+{
+ u8 *tempStr;
+ u8 cmd = *recvMessage;
+ u8 *name = recvMessage + 1;
+ recvMessage = name;
+ recvMessage += PLAYER_NAME_LENGTH + 1;
+
+ switch (cmd)
+ {
+ case CHAT_MESSAGE_JOIN:
+ if (sWork->multiplayerId != name[PLAYER_NAME_LENGTH + 1])
+ {
+ DynamicPlaceholderTextUtil_Reset();
+ DynamicPlaceholderTextUtil_SetPlaceholderPtr(0, name);
+ DynamicPlaceholderTextUtil_ExpandPlaceholders(dest, gText_F700JoinedChat);
+ return TRUE;
+ }
+ break;
+ case CHAT_MESSAGE_CHAT:
+ tempStr = StringCopy(dest, name);
+ *(tempStr++) = EXT_CTRL_CODE_BEGIN;
+ *(tempStr++) = EXT_CTRL_CODE_CLEAR_TO;
+ *(tempStr++) = 42;
+ *(tempStr++) = CHAR_COLON;
+ StringCopy(tempStr, recvMessage);
+ return TRUE;
+ case CHAT_MESSAGE_DISBAND:
+ StringCopy(sWork->hostName, name);
+ // fall through
+ case CHAT_MESSAGE_LEAVE:
+ if (sWork->multiplayerId != *recvMessage)
+ {
+ DynamicPlaceholderTextUtil_Reset();
+ DynamicPlaceholderTextUtil_SetPlaceholderPtr(0, name);
+ DynamicPlaceholderTextUtil_ExpandPlaceholders(dest, gText_F700LeftChat);
+ return TRUE;
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+u8 GetCurrentKeyboardPage(void)
+{
+ return sWork->currentPage;
+}
+
+void UnionRoomChat_GetCursorColAndRow(u8 *colp, u8 *rowp)
+{
+ *colp = sWork->currentCol;
+ *rowp = sWork->currentRow;
+}
+
+u8 *UnionRoomChat_GetMessageEntryBuffer(void)
+{
+ return sWork->messageEntryBuffer;
+}
+
+int UnionRoomChat_LenMessageEntryBuffer(void)
+{
+ u8 *str = UnionRoomChat_GetMessageEntryBuffer();
+ return StringLength_Multibyte(str);
+}
+
+void UnionRoomChat_GetBufferSelectionRegion(u32 *startp, u32 *diffp)
+{
+ int diff = sWork->bufferCursorPos - sWork->lastBufferCursorPos;
+ if (diff < 0)
+ {
+ diff *= -1;
+ *startp = sWork->bufferCursorPos;
+ }
+ else
+ {
+ *startp = sWork->lastBufferCursorPos;
+ }
+
+ *diffp = diff;
+}
+
+u8 *UnionRoomChat_GetEndOfMessageEntryBuffer(void)
+{
+ int i;
+ u16 numChars = GetNumCharsInMessageEntryBuffer();
+ u8 *str = sWork->messageEntryBuffer;
+ for (i = 0; i < numChars; i++)
+ {
+ if (*str == CHAR_EXTRA_EMOJI)
+ str++;
+
+ str++;
+ }
+
+ return str;
+}
+
+// Useless overhead
+u16 UnionRoomChat_GetNumCharsInMessageEntryBuffer(void)
+{
+ u16 count;
+ u32 i;
+ u16 numChars = GetNumCharsInMessageEntryBuffer();
+ u8 *str = sWork->messageEntryBuffer;
+ for (count = 0, i = 0; i < numChars; count++, i++)
+ {
+ if (*str == CHAR_EXTRA_EMOJI)
+ str++;
+
+ str++;
+ }
+
+ return count;
+}
+
+u8 *UnionRoomChat_GetLastReceivedMessage(void)
+{
+ return sWork->receivedMessage;
+}
+
+u16 UnionRoomChat_GetReceivedPlayerIndex(void)
+{
+ return sWork->receivedPlayerIndex;
+}
+
+int UnionRoomChat_GetMessageEntryCursorPosition(void)
+{
+ return sWork->bufferCursorPos;
+}
+
+// This probably does more in the Japanese titles.
+int UnionRoomChat_GetWhetherShouldShowCaseToggleIcon(void)
+{
+ u8 *str = GetPtrToLastCharOfUnk1A();
+ u32 character = *str;
+ if (character > 0xFF || sCaseToggleTable[character] == character || sCaseToggleTable[character] == 0)
+ return 3;
+ else
+ return 0;
+}
+
+u8 *UnionRoomChat_GetNameOfPlayerWhoDisbandedChat(void)
+{
+ return sWork->hostName;
+}
+
+void UnionRoomChat_InitializeRegisteredTexts(void)
+{
+ StringCopy(gSaveBlock1Ptr->registeredTexts[0], gText_Hello);
+ StringCopy(gSaveBlock1Ptr->registeredTexts[1], gText_Pokemon2);
+ StringCopy(gSaveBlock1Ptr->registeredTexts[2], gText_Trade);
+ StringCopy(gSaveBlock1Ptr->registeredTexts[3], gText_Battle);
+ StringCopy(gSaveBlock1Ptr->registeredTexts[4], gText_Lets);
+ StringCopy(gSaveBlock1Ptr->registeredTexts[5], gText_Ok);
+ StringCopy(gSaveBlock1Ptr->registeredTexts[6], gText_Sorry);
+ StringCopy(gSaveBlock1Ptr->registeredTexts[7], gText_YaySmileEmoji);
+ StringCopy(gSaveBlock1Ptr->registeredTexts[8], gText_ThankYou);
+ StringCopy(gSaveBlock1Ptr->registeredTexts[9], gText_ByeBye);
+}
+
+#define tState data[0]
+#define tI data[1]
+#define tCurrLinkPlayer data[2]
+#define tBlockReceivedStatus data[3]
+#define tLinkPlayerCount data[4]
+#define tNextState data[5]
+
+static void Task_ReceiveChatMessage(u8 taskId)
+{
+ u8 *buffer;
+ s16 *data = gTasks[taskId].data;
+
+ switch (tState)
+ {
+ case 0:
+ if (!gReceivedRemoteLinkPlayers)
+ {
+ DestroyTask(taskId);
+ return;
+ }
+
+ tState = 1;
+ // fall through
+ case 1:
+ tLinkPlayerCount = GetLinkPlayerCount();
+ if (sWork->linkPlayerCount != tLinkPlayerCount)
+ {
+ tState = 2;
+ sWork->linkPlayerCount = tLinkPlayerCount;
+ return;
+ }
+
+ tBlockReceivedStatus = GetBlockReceivedStatus();
+ if (!tBlockReceivedStatus && GetRfuUnkCE8())
+ return;
+
+ tI = 0;
+ tState = 3;
+ // fall through
+ case 3:
+ // Idle listen
+ for (; tI < 5 && ((tBlockReceivedStatus >> tI) & 1) == 0; tI++)
+ ;
+
+ if (tI == 5)
+ {
+ tState = 1;
+ return;
+ }
+
+ tCurrLinkPlayer = tI;
+ ResetBlockReceivedFlag(tCurrLinkPlayer);
+ buffer = (u8 *)gBlockRecvBuffer[tI];
+ switch (buffer[0])
+ {
+ default:
+ case CHAT_MESSAGE_CHAT: tNextState = 3; break;
+ case CHAT_MESSAGE_JOIN: tNextState = 3; break;
+ case CHAT_MESSAGE_LEAVE: tNextState = 4; break;
+ case CHAT_MESSAGE_DROP: tNextState = 5; break;
+ case CHAT_MESSAGE_DISBAND: tNextState = 6; break;
+ }
+
+ if (ProcessReceivedChatMessage(sWork->receivedMessage, (u8 *)gBlockRecvBuffer[tI]))
+ {
+ sWork->receivedPlayerIndex = tI;
+ UnionRoomChat_StartDisplaySubtask(CHATDISPLAYROUTINE_SCROLLCHAT, 2);
+ tState = 7;
+ }
+ else
+ {
+ tState = tNextState;
+ }
+
+ tI++;
+ break;
+ case 7:
+ if (!RunDisplaySubtask(2))
+ tState = tNextState;
+ break;
+ case 4:
+ // Someone is leaving
+ if (sWork->multiplayerId == 0 && tCurrLinkPlayer != 0)
+ {
+ // You're the leader, and the person who left is not you
+ if (GetLinkPlayerCount() == 2)
+ {
+ sub_80FA4A8();
+ sWork->exitType = CHATEXIT_LEADER_LAST;
+ DestroyTask(taskId);
+ return;
+ }
+
+ sub_80FBD6C(tCurrLinkPlayer);
+ }
+
+ tState = 3;
+ break;
+ case 5:
+ // Person left
+ if (sWork->multiplayerId != 0)
+ sWork->exitType = CHATEXIT_DROPPED;
+
+ DestroyTask(taskId);
+ break;
+ case 6:
+ // The leader disbanded the chat
+ sWork->exitType = CHATEXIT_DISBANDED;
+ DestroyTask(taskId);
+ break;
+ case 2:
+ if (!GetRfuUnkCE8())
+ {
+ if (sWork->multiplayerId == 0)
+ sub_80FB030(sWork->linkPlayerCount);
+
+ tState = 1;
+ }
+ break;
+ }
+}
+
+#undef tNextState
+#undef tLinkPlayerCount
+#undef tBlockReceivedStatus
+#undef tCurrLinkPlayer
+#undef tI
+#undef tState
diff --git a/src/union_room_chat_display.c b/src/union_room_chat_display.c
new file mode 100644
index 000000000..54aef8d65
--- /dev/null
+++ b/src/union_room_chat_display.c
@@ -0,0 +1,1339 @@
+#include "global.h"
+#include "gflib.h"
+#include "dynamic_placeholder_text_util.h"
+#include "graphics.h"
+#include "menu.h"
+#include "new_menu_helpers.h"
+#include "scanline_effect.h"
+#include "strings.h"
+#include "text_window.h"
+#include "union_room_chat.h"
+#include "union_room_chat_display.h"
+#include "union_room_chat_objects.h"
+
+#define STDMESSAGE_QUIT_CHATTING 0
+#define STDMESSAGE_REGISTER_WHERE 1
+#define STDMESSAGE_REGISTER_HERE 2
+#define STDMESSAGE_INPUT_TEXT 3
+#define STDMESSAGE_EXITING_CHAT 4
+#define STDMESSAGE_LEADER_LEFT 5
+#define STDMESSAGE_ASK_SAVE 6
+#define STDMESSAGE_ASK_OVERWRITE 7
+#define STDMESSAGE_SAVING_NO_OFF 8
+#define STDMESSAGE_SAVED_THE_GAME 9
+#define STDMESSAGE_WARN_LEADER_LEAVE 10
+
+struct UnionRoomChat2Subtask
+{
+ bool32 (*callback)(u8 *);
+ u8 active;
+ u8 state;
+};
+
+struct UnionRoomChat2
+{
+ struct UnionRoomChat2Subtask subtasks[3];
+ u16 yesNoMenuWinId;
+ u16 curLine;
+ u16 scrollCount;
+ u16 messageWindowId;
+ s16 bg1hofs;
+ u8 expandedPlaceholdersBuffer[0x106];
+ u8 bg0Buffer[BG_SCREEN_SIZE];
+ u8 bg1Buffer[BG_SCREEN_SIZE];
+ u8 bg3Buffer[BG_SCREEN_SIZE];
+ u8 bg2Buffer[BG_SCREEN_SIZE];
+ u8 unk2128[0x20];
+ u8 unk2148[0x20];
+};
+
+struct SubtaskInfo
+{
+ u16 idx;
+ bool32 (*callback)(u8 *);
+};
+
+struct MessageWindowInfo
+{
+ const u8 *text;
+ bool8 boxType;
+ u8 x;
+ u8 y;
+ u8 letterSpacing;
+ u8 lineSpacing;
+ bool8 expandPlaceholders;
+ bool8 widerBox;
+};
+
+static EWRAM_DATA struct UnionRoomChat2 * sWork = NULL;
+
+static void InitWork(struct UnionRoomChat2 * ptr);
+static void UnionRoomChat_ResetDisplaySubtasks(void);
+static bool32 DisplaySubtask_LoadGfx(u8 *state);
+static bool32 DisplaySubtask_PrintWin3(u8 *state);
+static bool32 DisplaySubtask_HideWin3(u8 *state);
+static bool32 DisplaySubtask_SwitchPages(u8 *state);
+static bool32 DisplaySubtask_MoveSelectorCursorObj(u8 *state);
+static bool32 DisplaySubtask_ShowQuitChattingDialog(u8 *state);
+static bool32 DisplaySubtask_HideQuitChattingDialog(u8 *state);
+static bool32 DisplaySubtask_UpdateMessageBuffer(u8 *state);
+static bool32 DisplaySubtask_PrintRegisterWhere(u8 *state);
+static bool32 DisplaySubtask_CancelRegister(u8 *state);
+static bool32 DisplaySubtask_ReturnToKeyboard(u8 *state);
+static bool32 DisplaySubtask_ScrollChat(u8 *state);
+static bool32 DisplaySubtask_AnimateSelectorCursorBlink(u8 *state);
+static bool32 DisplaySubtask_PrintInputText(u8 *state);
+static bool32 DisplaySubtask_PrintExitingChat(u8 *state);
+static bool32 DisplaySubtask_PrintLeaderLeft(u8 *state);
+static bool32 DisplaySubtask_AskSave(u8 *state);
+static bool32 DisplaySubtask_AskOverwriteSave(u8 *state);
+static bool32 DisplaySubtask_PrintSavingDontTurnOffPower(u8 *state);
+static bool32 DisplaySubtask_PrintSavedTheGame(u8 *state);
+static bool32 DisplaySubtask_ShowConfirmLeaderLeaveDialog(u8 *state);
+static bool32 DisplaySubtaskDummy(u8 *state);
+static void PlaceYesNoMenuAt(u8 a0, u8 a1, u8 a2);
+static void HideYesNoMenuWindow(void);
+static void DestroyYesNoMenuWindow(void);
+static void PlaceStdMessageWindow(int id, u16 bg0vofs);
+static void HideStdMessageWindow(void);
+static void DestroyStdMessageWindow(void);
+static void FillWin1Rect(u16 x, u16 width, u8 fillValue);
+static void PrintOnWin1Parameterized(u16 x, u8 *str, u8 bgColor, u8 fgColor, u8 shadowColor);
+static void PrintCurrentKeyboardPage(void);
+static bool32 AnimateMoveBg1Right(void);
+static bool32 AnimateMoveBg1Left(void);
+static void PrintKeyboardSwapTextsOnWin3(void);
+static void ClearWin3(void);
+static void PrintTextOnWin0Colorized(u16 row, u8 *str, u8 colorIdx);
+static void ResetGpuBgState(void);
+static void SetBgTilemapWorkBuffers(void);
+static void ClearBg0(void);
+static void LoadUnionRoomChatPanelGfx(void);
+static void LoadLinkMiscMenuGfx(void);
+static void LoadBg1Pal8(void);
+static void LoadWin0(void);
+static void LoadWin2(void);
+static void LoadWin1(void);
+static void LoadWin3(void);
+static void sub_812AD50(void);
+static void FillScanlineEffectWithValue1col(s16 a0);
+static void FillScanlineEffectWithValue2col(s16 a0);
+
+static const u16 sUnionRoomChatPanelBgPal_C[] = INCBIN_U16("graphics/union_room_chat/unk_845AA24.gbapal");
+static const u16 sBg1Pal8[] = INCBIN_U16("graphics/union_room_chat/unk_845AA44.gbapal");
+static const u16 sWin0PalF[] = INCBIN_U16("graphics/union_room_chat/unk_845AA64.gbapal");
+
+static const struct BgTemplate gUnknown_845AA84[] = {
+ {
+ .bg = 0,
+ .charBaseIndex = 0,
+ .mapBaseIndex = 7,
+ .screenSize = 0,
+ .paletteMode = 0,
+ .priority = 0,
+ .baseTile = 0x0000
+ }, {
+ .bg = 1,
+ .charBaseIndex = 3,
+ .mapBaseIndex = 31,
+ .screenSize = 0,
+ .paletteMode = 0,
+ .priority = 1,
+ .baseTile = 0x0000
+ }, {
+ .bg = 2,
+ .charBaseIndex = 2,
+ .mapBaseIndex = 23,
+ .screenSize = 0,
+ .paletteMode = 0,
+ .priority = 2,
+ .baseTile = 0x0000
+ }, {
+ .bg = 3,
+ .charBaseIndex = 1,
+ .mapBaseIndex = 15,
+ .screenSize = 0,
+ .paletteMode = 0,
+ .priority = 3,
+ .baseTile = 0x0001
+ }
+};
+
+static const struct WindowTemplate gUnknown_845AA94[] = {
+ {
+ .bg = 3,
+ .tilemapLeft = 8,
+ .tilemapTop = 1,
+ .width = 21,
+ .height = 19,
+ .paletteNum = 15,
+ .baseBlock = 0x001
+ }, {
+ .bg = 1,
+ .tilemapLeft = 9,
+ .tilemapTop = 18,
+ .width = 15,
+ .height = 2,
+ .paletteNum = 12,
+ .baseBlock = 0x07a
+ }, {
+ .bg = 1,
+ .tilemapLeft = 0,
+ .tilemapTop = 2,
+ .width = 6,
+ .height = 15,
+ .paletteNum = 7,
+ .baseBlock = 0x020
+ }, {
+ .bg = 0,
+ .tilemapLeft = 1,
+ .tilemapTop = 2,
+ .width = 7,
+ .height = 9,
+ .paletteNum = 14,
+ .baseBlock = 0x013
+ }, DUMMY_WIN_TEMPLATE
+};
+
+static const struct SubtaskInfo sSubtaskInfo[] = {
+ {CHATDISPLAYROUTINE_LOADGFX, DisplaySubtask_LoadGfx},
+ {CHATDISPLAYROUTINE_SHOWKBSWAPMENU, DisplaySubtask_PrintWin3},
+ {CHATDISPLAYROUTINE_HIDEKBSWAPMENU, DisplaySubtask_HideWin3},
+ {CHATDISPLAYROUTINE_SWITCHPAGES, DisplaySubtask_SwitchPages},
+ {CHATDISPLAYROUTINE_MOVEKBCURSOR, DisplaySubtask_MoveSelectorCursorObj},
+ {CHATDISPLAYROUTINE_SHOWQUITCHATTINGDIALOG, DisplaySubtask_ShowQuitChattingDialog},
+ {CHATDISPLAYROUTINE_DESTROYSTDMSGANDYESNO, DisplaySubtask_HideQuitChattingDialog},
+ {CHATDISPLAYROUTINE_PRINTMSG, DisplaySubtask_UpdateMessageBuffer},
+ {CHATDISPLAYROUTINE_PRINTREGISTERWHERE, DisplaySubtask_PrintRegisterWhere},
+ {CHATDISPLAYROUTINE_CANCELREGISTER, DisplaySubtask_CancelRegister},
+ {CHATDISPLAYROUTINE_RETURNTOKB, DisplaySubtask_ReturnToKeyboard},
+ {CHATDISPLAYROUTINE_SCROLLCHAT, DisplaySubtask_ScrollChat},
+ {CHATDISPLAYROUTINE_CURSORBLINK, DisplaySubtask_AnimateSelectorCursorBlink},
+ {CHATDISPLAYROUTINE_PRINTINPUTTEXT, DisplaySubtask_PrintInputText},
+ {CHATDISPLAYROUTINE_PRINTEXITINGCHAT, DisplaySubtask_PrintExitingChat},
+ {CHATDISPLAYROUTINE_PRINTLEADERLEFT, DisplaySubtask_PrintLeaderLeft},
+ {CHATDISPLAYROUTINE_ASKSAVE, DisplaySubtask_AskSave},
+ {CHATDISPLAYROUTINE_ASKOVERWRITESAVE, DisplaySubtask_AskOverwriteSave},
+ {CHATDISPLAYROUTINE_PRINTSAVING, DisplaySubtask_PrintSavingDontTurnOffPower},
+ {CHATDISPLAYROUTINE_PRINTSAVEDTHEGAME, DisplaySubtask_PrintSavedTheGame},
+ {CHATDISPLAYROUTINE_SHOWCONFIRMLEADERLEAVEDIALOG, DisplaySubtask_ShowConfirmLeaderLeaveDialog}
+};
+
+static const struct MessageWindowInfo sMessageWindowInfo[] = {
+
+ [STDMESSAGE_QUIT_CHATTING] = {
+ .text = gText_QuitChatting,
+ .boxType = 1,
+ .x = 0,
+ .y = 0,
+ .letterSpacing = 1,
+ .lineSpacing = 2,
+ .expandPlaceholders = FALSE,
+ .widerBox = FALSE
+ },
+ [STDMESSAGE_REGISTER_WHERE] = {
+ .text = gText_RegisterTextWhere,
+ .boxType = 1,
+ .x = 0,
+ .y = 0,
+ .letterSpacing = 1,
+ .lineSpacing = 2,
+ .expandPlaceholders = FALSE,
+ .widerBox = FALSE
+ },
+ [STDMESSAGE_REGISTER_HERE] = {
+ .text = gText_RegisterTextHere,
+ .boxType = 1,
+ .x = 0,
+ .y = 0,
+ .letterSpacing = 1,
+ .lineSpacing = 2,
+ .expandPlaceholders = FALSE,
+ .widerBox = FALSE
+ },
+ [STDMESSAGE_INPUT_TEXT] = {
+ .text = gText_InputText,
+ .boxType = 1,
+ .x = 0,
+ .y = 0,
+ .letterSpacing = 1,
+ .lineSpacing = 2,
+ .expandPlaceholders = FALSE,
+ .widerBox = FALSE
+ },
+ [STDMESSAGE_EXITING_CHAT] = {
+ .text = gText_ExitingTheChat,
+ .boxType = 2,
+ .x = 0,
+ .y = 0,
+ .letterSpacing = 1,
+ .lineSpacing = 2,
+ .expandPlaceholders = FALSE,
+ .widerBox = FALSE
+ },
+ [STDMESSAGE_LEADER_LEFT] = {
+ .text = gText_LeaderHasLeftEndingChat,
+ .boxType = 2,
+ .x = 0,
+ .y = 0,
+ .letterSpacing = 0,
+ .lineSpacing = 2,
+ .expandPlaceholders = TRUE,
+ .widerBox = FALSE
+ },
+ [STDMESSAGE_ASK_SAVE] = {
+ .text = gText_RegisteredTextChanged_OKtoSave,
+ .boxType = 2,
+ .x = 0,
+ .y = 0,
+ .letterSpacing = 1,
+ .lineSpacing = 2,
+ .expandPlaceholders = FALSE,
+ .widerBox = TRUE
+ },
+ [STDMESSAGE_ASK_OVERWRITE] = {
+ .text = gText_RegisteredTextChanged_AlreadySavedFile,
+ .boxType = 2,
+ .x = 0,
+ .y = 0,
+ .letterSpacing = 1,
+ .lineSpacing = 2,
+ .expandPlaceholders = FALSE,
+ .widerBox = TRUE
+ },
+ [STDMESSAGE_SAVING_NO_OFF] = {
+ .text = gText_RegisteredTextChanged_SavingDontTurnOff,
+ .boxType = 2,
+ .x = 0,
+ .y = 0,
+ .letterSpacing = 1,
+ .lineSpacing = 2,
+ .expandPlaceholders = FALSE,
+ .widerBox = TRUE
+ },
+ [STDMESSAGE_SAVED_THE_GAME] = {
+ .text = gText_RegisteredTextChanged_SavedTheGame,
+ .boxType = 2,
+ .x = 0,
+ .y = 0,
+ .letterSpacing = 1,
+ .lineSpacing = 2,
+ .expandPlaceholders = TRUE,
+ .widerBox = TRUE
+ },
+ [STDMESSAGE_WARN_LEADER_LEAVE] = {
+ .text = gText_IfLeaderLeavesChatWillEnd,
+ .boxType = 2,
+ .x = 0,
+ .y = 0,
+ .letterSpacing = 1,
+ .lineSpacing = 2,
+ .expandPlaceholders = FALSE,
+ .widerBox = TRUE
+ }
+};
+
+static const u8 gText_Ellipsis[] = _("…");
+
+static const struct MenuAction sKeyboardSwapTexts[] = {
+ {gText_Upper},
+ {gText_Lower},
+ {gText_Symbols},
+ {gText_Register2},
+ {gText_Exit}
+};
+
+bool8 UnionRoomChat_TryAllocGraphicsWork(void)
+{
+ sWork = Alloc(sizeof(*sWork));
+ if (sWork && UnionRoomChat_TryAllocSpriteWork())
+ {
+ ResetBgsAndClearDma3BusyFlags(0);
+ InitBgsFromTemplates(0, gUnknown_845AA84, NELEMS(gUnknown_845AA84));
+ InitWindows(gUnknown_845AA94);
+ ResetTempTileDataBuffers();
+ sub_812AD50();
+ InitWork(sWork);
+ UnionRoomChat_ResetDisplaySubtasks();
+ UnionRoomChat_StartDisplaySubtask(0, 0);
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+bool32 UnionRoomChat_RunDisplaySubtask0(void)
+{
+ return RunDisplaySubtask(0);
+}
+
+void UnionRoomChat_FreeGraphicsWork(void)
+{
+ UnionRoomChat_FreeSpriteWork();
+ if (sWork != NULL)
+ FREE_AND_SET_NULL(sWork);
+
+ FreeAllWindowBuffers();
+ gScanlineEffect.state = 3;
+}
+
+static void InitWork(struct UnionRoomChat2 *arg0)
+{
+ arg0->yesNoMenuWinId = 0xFF;
+ arg0->messageWindowId = 0xFF;
+ arg0->curLine = 0;
+}
+
+void UnionRoomChat_ResetDisplaySubtasks(void)
+{
+ int i;
+
+ if (sWork == NULL)
+ return;
+
+ for (i = 0; i < 3; i++)
+ {
+ sWork->subtasks[i].callback = DisplaySubtaskDummy;
+ sWork->subtasks[i].active = FALSE;
+ sWork->subtasks[i].state = 0;
+ }
+}
+
+void UnionRoomChat_RunDisplaySubtasks(void)
+{
+ int i;
+
+ if (sWork == NULL)
+ return;
+
+ for (i = 0; i < 3; i++)
+ {
+ if (sWork->subtasks[i].active)
+ sWork->subtasks[i].active = sWork->subtasks[i].callback(&sWork->subtasks[i].state);
+ }
+}
+
+void UnionRoomChat_StartDisplaySubtask(u16 arg0, u8 arg1)
+{
+ int i;
+
+ sWork->subtasks[arg1].callback = DisplaySubtaskDummy;
+ for (i = 0; i < NELEMS(sSubtaskInfo); i++)
+ {
+ if (sSubtaskInfo[i].idx == arg0)
+ {
+ sWork->subtasks[arg1].callback = sSubtaskInfo[i].callback;
+ sWork->subtasks[arg1].active = TRUE;
+ sWork->subtasks[arg1].state = 0;
+ break;
+ }
+ }
+}
+
+bool8 RunDisplaySubtask(u8 arg0)
+{
+ return sWork->subtasks[arg0].active;
+}
+
+static bool32 DisplaySubtask_LoadGfx(u8 *state)
+{
+ if (FreeTempTileDataBuffersIfPossible() == TRUE)
+ return TRUE;
+
+ switch (*state)
+ {
+ case 0:
+ ResetGpuBgState();
+ SetBgTilemapWorkBuffers();
+ break;
+ case 1:
+ ClearBg0();
+ break;
+ case 2:
+ LoadUnionRoomChatPanelGfx();
+ break;
+ case 3:
+ LoadLinkMiscMenuGfx();
+ break;
+ case 4:
+ LoadBg1Pal8();
+ break;
+ case 5:
+ LoadWin0();
+ LoadWin2();
+ LoadWin3();
+ LoadWin1();
+ break;
+ case 6:
+ if (!IsDma3ManagerBusyWithBgCopy())
+ {
+ UnionRoomChat_CreateSelectorCursorObj();
+ UnionRoomChat_SpawnTextEntryPointerSprites();
+ CreatePageSwitchUISprites();
+ }
+ break;
+ default:
+ return FALSE;
+ }
+
+ (*state)++;
+ return TRUE;
+}
+
+static bool32 DisplaySubtask_PrintWin3(u8 *state)
+{
+ switch (*state)
+ {
+ case 0:
+ PrintKeyboardSwapTextsOnWin3();
+ CopyWindowToVram(3, 3);
+ break;
+ case 1:
+ return IsDma3ManagerBusyWithBgCopy();
+ }
+
+ (*state)++;
+ return TRUE;
+}
+
+static bool32 DisplaySubtask_HideWin3(u8 *state)
+{
+ switch (*state)
+ {
+ case 0:
+ ClearWin3();
+ CopyWindowToVram(3, 3);
+ break;
+ case 1:
+ return IsDma3ManagerBusyWithBgCopy();
+ }
+
+ (*state)++;
+ return TRUE;
+}
+
+static bool32 DisplaySubtask_SwitchPages(u8 *state)
+{
+ switch (*state)
+ {
+ case 0:
+ UnionRoomChat_ToggleSelectorCursorObjVisibility(TRUE);
+ if (AnimateMoveBg1Right())
+ return TRUE;
+
+ PrintCurrentKeyboardPage();
+ CopyWindowToVram(2, 2);
+ break;
+ case 1:
+ if (IsDma3ManagerBusyWithBgCopy())
+ return TRUE;
+ break;
+ case 2:
+ if (AnimateMoveBg1Left())
+ return TRUE;
+
+ UnionRoomChat_MoveSelectorCursorObj();
+ UnionRoomChat_ToggleSelectorCursorObjVisibility(FALSE);
+ UpdateVisibleUnionRoomChatIcon();
+ return FALSE;
+ }
+
+ (*state)++;
+ return TRUE;
+}
+
+static bool32 DisplaySubtask_MoveSelectorCursorObj(u8 *state)
+{
+ UnionRoomChat_MoveSelectorCursorObj();
+ return FALSE;
+}
+
+static bool32 DisplaySubtask_ShowQuitChattingDialog(u8 *state)
+{
+ switch (*state)
+ {
+ case 0:
+ PlaceStdMessageWindow(STDMESSAGE_QUIT_CHATTING, 0);
+ PlaceYesNoMenuAt(23, 11, 1);
+ CopyWindowToVram(sWork->messageWindowId, 3);
+ break;
+ case 1:
+ return IsDma3ManagerBusyWithBgCopy();
+ }
+
+ (*state)++;
+ return TRUE;
+}
+
+static bool32 DisplaySubtask_HideQuitChattingDialog(u8 *state)
+{
+ switch (*state)
+ {
+ case 0:
+ HideStdMessageWindow();
+ HideYesNoMenuWindow();
+ CopyBgTilemapBufferToVram(0);
+ break;
+ case 1:
+ if (IsDma3ManagerBusyWithBgCopy())
+ return TRUE;
+
+ DestroyStdMessageWindow();
+ DestroyYesNoMenuWindow();
+ return FALSE;
+ }
+
+ (*state)++;
+ return TRUE;
+}
+
+static bool32 DisplaySubtask_UpdateMessageBuffer(u8 *state)
+{
+ u32 start, length;
+ u8 *str;
+
+ switch (*state)
+ {
+ case 0:
+ UnionRoomChat_GetBufferSelectionRegion(&start, &length);
+ FillWin1Rect(start, length, PIXEL_FILL(0));
+ str = UnionRoomChat_GetMessageEntryBuffer();
+ PrintOnWin1Parameterized(0, str, TEXT_COLOR_LIGHT_GREY, TEXT_COLOR_WHITE, TEXT_COLOR_DARK_GREY);
+ CopyWindowToVram(1, 2);
+ break;
+ case 1:
+ if (!IsDma3ManagerBusyWithBgCopy())
+ {
+ UpdateVisibleUnionRoomChatIcon();
+ return FALSE;
+ }
+ return TRUE;
+ }
+
+ (*state)++;
+ return TRUE;
+}
+
+static bool32 DisplaySubtask_PrintRegisterWhere(u8 *state)
+{
+ u16 var0;
+ u8 *str;
+ u16 length;
+
+ switch (*state)
+ {
+ case 0:
+ var0 = UnionRoomChat_GetNumCharsInMessageEntryBuffer();
+ str = UnionRoomChat_GetEndOfMessageEntryBuffer();
+ length = StringLength_Multibyte(str);
+ FillWin1Rect(var0, length, PIXEL_FILL(6));
+ PrintOnWin1Parameterized(var0, str, TEXT_COLOR_TRANSPARENT, TEXT_COLOR_RED, TEXT_COLOR_LIGHT_RED);
+ CopyWindowToVram(1, 2);
+ break;
+ case 1:
+ if (!IsDma3ManagerBusyWithBgCopy())
+ {
+ PlaceStdMessageWindow(STDMESSAGE_REGISTER_WHERE, 16);
+ CopyWindowToVram(sWork->messageWindowId, 3);
+ }
+ else
+ {
+ return TRUE;
+ }
+ break;
+ case 2:
+ if (!IsDma3ManagerBusyWithBgCopy())
+ UnionRoomChat_UpdateObjPalCycle(1);
+ else
+ return TRUE;
+ break;
+ case 3:
+ return FALSE;
+ }
+
+ (*state)++;
+ return TRUE;
+}
+
+static bool32 DisplaySubtask_CancelRegister(u8 *state)
+{
+ u16 x;
+ u8 *str;
+ u16 length;
+
+ switch (*state)
+ {
+ case 0:
+ x = UnionRoomChat_GetNumCharsInMessageEntryBuffer();
+ str = UnionRoomChat_GetEndOfMessageEntryBuffer();
+ length = StringLength_Multibyte(str);
+ FillWin1Rect(x, length, PIXEL_FILL(0));
+ PrintOnWin1Parameterized(x, str, TEXT_COLOR_LIGHT_GREY, TEXT_COLOR_WHITE, TEXT_COLOR_DARK_GREY);
+ CopyWindowToVram(1, 2);
+ break;
+ case 1:
+ if (!IsDma3ManagerBusyWithBgCopy())
+ {
+ HideStdMessageWindow();
+ CopyWindowToVram(sWork->messageWindowId, 3);
+ }
+ else
+ {
+ return TRUE;
+ }
+ break;
+ case 2:
+ if (!IsDma3ManagerBusyWithBgCopy())
+ {
+ UnionRoomChat_UpdateObjPalCycle(0);
+ DestroyStdMessageWindow();
+ }
+ else
+ {
+ return TRUE;
+ }
+ break;
+ case 3:
+ return FALSE;
+ }
+
+ (*state)++;
+ return TRUE;
+}
+
+static bool32 DisplaySubtask_ReturnToKeyboard(u8 *state)
+{
+ switch (*state)
+ {
+ case 0:
+ PrintCurrentKeyboardPage();
+ CopyWindowToVram(2, 2);
+ (*state)++;
+ break;
+ case 1:
+ if (IsDma3ManagerBusyWithBgCopy())
+ return TRUE;
+ else
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool32 DisplaySubtask_ScrollChat(u8 *state)
+{
+ u16 row;
+ u8 *str;
+ u8 colorIdx;
+
+ switch (*state)
+ {
+ case 0:
+ row = sWork->curLine;
+ str = UnionRoomChat_GetLastReceivedMessage();
+ colorIdx = UnionRoomChat_GetReceivedPlayerIndex();
+ PrintTextOnWin0Colorized(row, str, colorIdx);
+ CopyWindowToVram(0, 2);
+ break;
+ case 1:
+ if (IsDma3ManagerBusyWithBgCopy())
+ return TRUE;
+
+ if (sWork->curLine < 9)
+ {
+ sWork->curLine++;
+ *state = 4;
+ return FALSE;
+ }
+ else
+ {
+ sWork->scrollCount = 0;
+ (*state)++;
+ }
+ // fall through
+ case 2:
+ ScrollWindow(0, 0, 5, PIXEL_FILL(1));
+ CopyWindowToVram(0, 2);
+ sWork->scrollCount++;
+ (*state)++;
+ // fall through
+ case 3:
+ if (IsDma3ManagerBusyWithBgCopy())
+ return TRUE;
+
+ if (sWork->scrollCount < 3)
+ {
+ (*state)--;
+ return TRUE;
+ }
+ break;
+ case 4:
+ return FALSE;
+ default:
+ return TRUE;
+ }
+
+ (*state)++;
+ return TRUE;
+}
+
+static bool32 DisplaySubtask_AnimateSelectorCursorBlink(u8 *state)
+{
+ switch (*state)
+ {
+ case 0:
+ UnionRoomChat_SetSelectorCursorClosedImage();
+ (*state)++;
+ break;
+ case 1:
+ return UnionRoomChat_AnimateSelectorCursorReopen();
+ }
+
+ return TRUE;
+}
+
+static bool32 DisplaySubtask_PrintInputText(u8 *state)
+{
+ switch (*state)
+ {
+ case 0:
+ PlaceStdMessageWindow(STDMESSAGE_INPUT_TEXT, 16);
+ CopyWindowToVram(sWork->messageWindowId, 3);
+ (*state)++;
+ break;
+ case 1:
+ return IsDma3ManagerBusyWithBgCopy();
+ }
+
+ return TRUE;
+}
+
+static bool32 DisplaySubtask_PrintExitingChat(u8 *state)
+{
+ switch (*state)
+ {
+ case 0:
+ PlaceStdMessageWindow(STDMESSAGE_EXITING_CHAT, 0);
+ CopyWindowToVram(sWork->messageWindowId, 3);
+ (*state)++;
+ break;
+ case 1:
+ return IsDma3ManagerBusyWithBgCopy();
+ }
+
+ return TRUE;
+}
+
+static bool32 DisplaySubtask_PrintLeaderLeft(u8 *state)
+{
+ u8 *str;
+
+ switch (*state)
+ {
+ case 0:
+ DynamicPlaceholderTextUtil_Reset();
+ str = UnionRoomChat_GetNameOfPlayerWhoDisbandedChat();
+ DynamicPlaceholderTextUtil_SetPlaceholderPtr(0, str);
+ PlaceStdMessageWindow(STDMESSAGE_LEADER_LEFT, 0);
+ CopyWindowToVram(sWork->messageWindowId, 3);
+ (*state)++;
+ break;
+ case 1:
+ return IsDma3ManagerBusyWithBgCopy();
+ }
+
+ return TRUE;
+}
+
+static bool32 DisplaySubtask_AskSave(u8 *state)
+{
+ switch (*state)
+ {
+ case 0:
+ PlaceStdMessageWindow(STDMESSAGE_ASK_SAVE, 0);
+ PlaceYesNoMenuAt(23, 10, 1);
+ CopyWindowToVram(sWork->messageWindowId, 3);
+ (*state)++;
+ break;
+ case 1:
+ return IsDma3ManagerBusyWithBgCopy();
+ }
+
+ return TRUE;
+}
+
+static bool32 DisplaySubtask_AskOverwriteSave(u8 *state)
+{
+ switch (*state)
+ {
+ case 0:
+ PlaceStdMessageWindow(STDMESSAGE_ASK_OVERWRITE, 0);
+ PlaceYesNoMenuAt(23, 10, 1);
+ CopyWindowToVram(sWork->messageWindowId, 3);
+ (*state)++;
+ break;
+ case 1:
+ return IsDma3ManagerBusyWithBgCopy();
+ }
+
+ return TRUE;
+}
+
+static bool32 DisplaySubtask_PrintSavingDontTurnOffPower(u8 *state)
+{
+ switch (*state)
+ {
+ case 0:
+ PlaceStdMessageWindow(STDMESSAGE_SAVING_NO_OFF, 0);
+ CopyWindowToVram(sWork->messageWindowId, 3);
+ (*state)++;
+ break;
+ case 1:
+ return IsDma3ManagerBusyWithBgCopy();
+ }
+
+ return TRUE;
+}
+
+static bool32 DisplaySubtask_PrintSavedTheGame(u8 *state)
+{
+ switch (*state)
+ {
+ case 0:
+ DynamicPlaceholderTextUtil_Reset();
+ DynamicPlaceholderTextUtil_SetPlaceholderPtr(0, gSaveBlock2Ptr->playerName);
+ PlaceStdMessageWindow(STDMESSAGE_SAVED_THE_GAME, 0);
+ CopyWindowToVram(sWork->messageWindowId, 3);
+ (*state)++;
+ break;
+ case 1:
+ return IsDma3ManagerBusyWithBgCopy();
+ }
+
+ return TRUE;
+}
+
+static bool32 DisplaySubtask_ShowConfirmLeaderLeaveDialog(u8 *state)
+{
+ switch (*state)
+ {
+ case 0:
+ PlaceStdMessageWindow(STDMESSAGE_WARN_LEADER_LEAVE, 0);
+ PlaceYesNoMenuAt(23, 10, 1);
+ CopyWindowToVram(sWork->messageWindowId, 3);
+ (*state)++;
+ break;
+ case 1:
+ return IsDma3ManagerBusyWithBgCopy();
+ }
+
+ return TRUE;
+}
+
+static bool32 DisplaySubtaskDummy(u8 *arg0)
+{
+ return FALSE;
+}
+
+static void PlaceYesNoMenuAt(u8 left, u8 top, u8 initialCursorPos)
+{
+ struct WindowTemplate template;
+ template.bg = 0;
+ template.tilemapLeft = left;
+ template.tilemapTop = top;
+ template.width = 6;
+ template.height = 4;
+ template.paletteNum = 14;
+ template.baseBlock = 0x052;
+ sWork->yesNoMenuWinId = AddWindow(&template);
+ if (sWork->yesNoMenuWinId != 0xFF)
+ {
+ FillWindowPixelBuffer(sWork->yesNoMenuWinId, PIXEL_FILL(1));
+ PutWindowTilemap(sWork->yesNoMenuWinId);
+ AddTextPrinterParameterized(sWork->yesNoMenuWinId, 2, gText_Yes, 8, 2, TEXT_SPEED_FF, NULL);
+ AddTextPrinterParameterized(sWork->yesNoMenuWinId, 2, gText_No, 8, 16, TEXT_SPEED_FF, NULL);
+ DrawTextBorderOuter(sWork->yesNoMenuWinId, 1, 13);
+ Menu_InitCursor(sWork->yesNoMenuWinId, 2, 0, 2, 14, 2, initialCursorPos);
+ }
+}
+
+static void HideYesNoMenuWindow(void)
+{
+ if (sWork->yesNoMenuWinId != 0xFF)
+ {
+ ClearStdWindowAndFrameToTransparent(sWork->yesNoMenuWinId, FALSE);
+ ClearWindowTilemap(sWork->yesNoMenuWinId);
+ }
+}
+
+static void DestroyYesNoMenuWindow(void)
+{
+ if (sWork->yesNoMenuWinId != 0xFF)
+ {
+ RemoveWindow(sWork->yesNoMenuWinId);
+ sWork->yesNoMenuWinId = 0xFF;
+ }
+}
+
+s8 UnionRoomChat_ProcessInput(void)
+{
+ return Menu_ProcessInput();
+}
+
+static void PlaceStdMessageWindow(int id, u16 bg0vofs)
+{
+ const u8 *str;
+ int windowId;
+ struct WindowTemplate template;
+ template.bg = 0;
+ template.tilemapLeft = 8;
+ template.tilemapTop = 16;
+ template.width = 21;
+ template.height = 4;
+ template.paletteNum = 14;
+ template.baseBlock = 0x06A;
+ if (sMessageWindowInfo[id].widerBox)
+ {
+ template.tilemapLeft -= 7;
+ template.width += 7;
+ }
+
+ sWork->messageWindowId = AddWindow(&template);
+ windowId = sWork->messageWindowId;
+ if (sWork->messageWindowId == 0xFF)
+ return;
+
+ if (sMessageWindowInfo[id].expandPlaceholders)
+ {
+ DynamicPlaceholderTextUtil_ExpandPlaceholders(sWork->expandedPlaceholdersBuffer, sMessageWindowInfo[id].text);
+ str = sWork->expandedPlaceholdersBuffer;
+ }
+ else
+ {
+ str = sMessageWindowInfo[id].text;
+ }
+
+ ChangeBgY(0, bg0vofs * 256, 0);
+ FillWindowPixelBuffer(windowId, PIXEL_FILL(1));
+ PutWindowTilemap(windowId);
+ if (sMessageWindowInfo[id].boxType == 1)
+ {
+ DrawTextBorderInner(windowId, 0xA, 2);
+ AddTextPrinterParameterized5(
+ windowId,
+ 2,
+ str,
+ sMessageWindowInfo[id].x + 8,
+ sMessageWindowInfo[id].y + 8,
+ TEXT_SPEED_FF,
+ NULL,
+ sMessageWindowInfo[id].letterSpacing,
+ sMessageWindowInfo[id].lineSpacing);
+ }
+ else
+ {
+ DrawTextBorderOuter(windowId, 0xA, 2);
+ AddTextPrinterParameterized5(
+ windowId,
+ 2,
+ str,
+ sMessageWindowInfo[id].x,
+ sMessageWindowInfo[id].y,
+ TEXT_SPEED_FF,
+ NULL,
+ sMessageWindowInfo[id].letterSpacing,
+ sMessageWindowInfo[id].lineSpacing);
+ }
+
+ sWork->messageWindowId = windowId;
+}
+
+static void HideStdMessageWindow(void)
+{
+ if (sWork->messageWindowId != 0xFF)
+ {
+ ClearStdWindowAndFrameToTransparent(sWork->messageWindowId, FALSE);
+ ClearWindowTilemap(sWork->messageWindowId);
+ }
+
+ ChangeBgY(0, 0, 0);
+}
+
+static void DestroyStdMessageWindow(void)
+{
+ if (sWork->messageWindowId != 0xFF)
+ {
+ RemoveWindow(sWork->messageWindowId);
+ sWork->messageWindowId = 0xFF;
+ }
+}
+
+static void FillWin1Rect(u16 x, u16 width, u8 fillValue)
+{
+ FillWindowPixelRect(1, fillValue, x * 8, 1, width * 8, 14);
+}
+
+static void PrintOnWin1Parameterized(u16 x, u8 *str, u8 bgColor, u8 fgColor, u8 shadowColor)
+{
+ u8 color[3];
+ u8 strbuf[35];
+
+ if (bgColor != TEXT_COLOR_TRANSPARENT)
+ FillWin1Rect(x, UnionRoomChat_GetMessageEntryCursorPosition() - x, bgColor);
+
+ color[0] = bgColor;
+ color[1] = fgColor;
+ color[2] = shadowColor;
+ strbuf[0] = EXT_CTRL_CODE_BEGIN;
+ strbuf[1] = EXT_CTRL_CODE_MIN_LETTER_SPACING;
+ strbuf[2] = 8;
+ StringCopy(&strbuf[3], str);
+ AddTextPrinterParameterized3(1, 2, x * 8, 1, color, TEXT_SPEED_FF, strbuf);
+}
+
+static void PrintCurrentKeyboardPage(void)
+{
+ u8 page;
+ int i;
+ u16 left;
+ u16 top;
+ u8 color[3];
+ u8 str[45];
+ u8 *str2;
+
+ FillWindowPixelBuffer(2, PIXEL_FILL(15));
+ page = GetCurrentKeyboardPage();
+ color[0] = TEXT_COLOR_TRANSPARENT;
+ color[1] = TEXT_DYNAMIC_COLOR_5;
+ color[2] = TEXT_DYNAMIC_COLOR_4;
+ if (page != UNION_ROOM_KB_PAGE_COUNT)
+ {
+ str[0] = EXT_CTRL_CODE_BEGIN;
+ str[1] = EXT_CTRL_CODE_MIN_LETTER_SPACING;
+ str[2] = 8;
+
+ if (page == UNION_ROOM_KB_PAGE_EMOJI)
+ left = 6;
+ else
+ left = 8;
+ for (i = 0, top = 0; i < UNION_ROOM_KB_ROW_COUNT; i++, top += 12)
+ {
+ if (!gUnionRoomKeyboardText[page][i])
+ return;
+
+ StringCopy(&str[3], gUnionRoomKeyboardText[page][i]);
+ AddTextPrinterParameterized3(2, 0, left, top, color, TEXT_SPEED_FF, str);
+ }
+ }
+ else
+ {
+ left = 4;
+ for (i = 0, top = 0; i < 10; i++, top += 12)
+ {
+ str2 = UnionRoomChat_GetWorkRegisteredText(i);
+ if (GetStringWidth(0, str2, 0) <= 40)
+ {
+ AddTextPrinterParameterized3(2, 0, left, top, color, TEXT_SPEED_FF, str2);
+ }
+ else
+ {
+ int length = StringLength_Multibyte(str2);
+ do
+ {
+ length--;
+ StringCopyN_Multibyte(str, str2, length);
+ } while (GetStringWidth(0, str, 0) > 35);
+
+ AddTextPrinterParameterized3(2, 0, left, top, color, TEXT_SPEED_FF, str);
+ AddTextPrinterParameterized3(2, 0, left + 35, top, color, TEXT_SPEED_FF, gText_Ellipsis);
+ }
+ }
+ }
+}
+
+static bool32 AnimateMoveBg1Right(void)
+{
+ if (sWork->bg1hofs < 56)
+ {
+ sWork->bg1hofs += 12;
+ if (sWork->bg1hofs >= 56)
+ sWork->bg1hofs = 56;
+
+ if (sWork->bg1hofs < 56)
+ {
+ FillScanlineEffectWithValue1col(sWork->bg1hofs);
+ return TRUE;
+ }
+ }
+
+ FillScanlineEffectWithValue2col(sWork->bg1hofs);
+ return FALSE;
+}
+
+static bool32 AnimateMoveBg1Left(void)
+{
+ if (sWork->bg1hofs > 0)
+ {
+ sWork->bg1hofs -= 12;
+ if (sWork->bg1hofs <= 0)
+ sWork->bg1hofs = 0;
+
+ if (sWork->bg1hofs > 0)
+ {
+ FillScanlineEffectWithValue1col(sWork->bg1hofs);
+ return TRUE;
+ }
+ }
+
+ FillScanlineEffectWithValue2col(sWork->bg1hofs);
+ return FALSE;
+}
+
+static void PrintKeyboardSwapTextsOnWin3(void)
+{
+ FillWindowPixelBuffer(3, PIXEL_FILL(1));
+ DrawTextBorderOuter(3, 1, 13);
+ UnionRoomAndTradeMenuPrintOptions(3, 2, 14, 5, sKeyboardSwapTexts);
+ Menu_InitCursor(3, 2, 0, 0, 14, 5, GetCurrentKeyboardPage());
+ PutWindowTilemap(3);
+}
+
+static void ClearWin3(void)
+{
+ ClearStdWindowAndFrameToTransparent(3, FALSE);
+ ClearWindowTilemap(3);
+}
+
+static void PrintTextOnWin0Colorized(u16 row, u8 *str, u8 colorIdx)
+// colorIdx: 0 = grey, 1 = red, 2 = green, 3 = blue
+{
+ u8 color[3];
+ color[0] = TEXT_COLOR_WHITE;
+ color[1] = colorIdx * 2 + 2;
+ color[2] = colorIdx * 2 + 3;
+ FillWindowPixelRect(0, PIXEL_FILL(1), 0, row * 15, 168, 15);
+ AddTextPrinterParameterized3(0, 2, 0, row * 15, color, TEXT_SPEED_FF, str);
+}
+
+static void ResetGpuBgState(void)
+{
+ ChangeBgX(0, 0, 0);
+ ChangeBgY(0, 0, 0);
+ ChangeBgX(1, 0, 0);
+ ChangeBgY(1, 0, 0);
+ ChangeBgX(2, 0, 0);
+ ChangeBgY(2, 0, 0);
+ ChangeBgX(3, 0, 0);
+ ChangeBgY(3, 0, 0);
+ ShowBg(0);
+ ShowBg(1);
+ ShowBg(2);
+ ShowBg(3);
+ SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON | DISPCNT_OBJ_1D_MAP);
+ SetGpuReg(REG_OFFSET_BLDCNT, 0);
+ ClearGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_WIN0_ON | DISPCNT_WIN1_ON | DISPCNT_OBJWIN_ON);
+ SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_WIN0_ON);
+ SetGpuReg(REG_OFFSET_WIN0H, WIN_RANGE(64, 240));
+ SetGpuReg(REG_OFFSET_WIN0V, WIN_RANGE(0, 144));
+ SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG0 | WININ_WIN0_BG2 | WININ_WIN0_BG3
+ | WININ_WIN0_OBJ | WININ_WIN0_CLR);
+ SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG_ALL | WINOUT_WIN01_OBJ | WINOUT_WIN01_CLR);
+}
+
+static void SetBgTilemapWorkBuffers(void)
+{
+ SetBgTilemapBuffer(0, sWork->bg0Buffer);
+ SetBgTilemapBuffer(1, sWork->bg1Buffer);
+ SetBgTilemapBuffer(3, sWork->bg3Buffer);
+ SetBgTilemapBuffer(2, sWork->bg2Buffer);
+}
+
+static void ClearBg0(void)
+{
+ RequestDma3Fill(0, (void *)BG_CHAR_ADDR(0), 0x20, 1);
+ FillBgTilemapBufferRect_Palette0(0, 0, 0, 0, 32, 32);
+ CopyBgTilemapBufferToVram(0);
+}
+
+static void LoadUnionRoomChatPanelGfx(void)
+{
+ LoadPalette(gUnionRoomChatPanelBgPal_7, 0x70, 0x20);
+ LoadPalette(sUnionRoomChatPanelBgPal_C, 0xC0, 0x20);
+ DecompressAndCopyTileDataToVram(1, gUnionRoomChatPanelBgTiles, 0, 0, 0);
+ CopyToBgTilemapBuffer(1, gUnionRoomChatPanelBgMap, 0, 0);
+ CopyBgTilemapBufferToVram(1);
+}
+
+static void LoadLinkMiscMenuGfx(void)
+{
+ u8 *ptr;
+
+ LoadPalette(gLinkMiscMenu_Pal, 0, 0x20);
+ ptr = DecompressAndCopyTileDataToVram(2, gLinkMiscMenu_Gfx, 0, 0, 0);
+ CopyToBgTilemapBuffer(2, gLinkMiscMenu_Tilemap, 0, 0);
+ CopyBgTilemapBufferToVram(2);
+}
+
+static void LoadBg1Pal8(void)
+{
+ LoadPalette(sBg1Pal8, 0x80, 0x20);
+ RequestDma3Fill(0, (void *)BG_CHAR_ADDR(1) + 0x20, 0x20, 1);
+}
+
+static void LoadWin0(void)
+{
+ LoadPalette(sWin0PalF, 0xF0, 0x20);
+ PutWindowTilemap(0);
+ FillWindowPixelBuffer(0, PIXEL_FILL(1));
+ CopyWindowToVram(0, 3);
+}
+
+static void LoadWin2(void)
+{
+ PutWindowTilemap(2);
+ PrintCurrentKeyboardPage();
+ CopyWindowToVram(2, 3);
+}
+
+static void LoadWin1(void)
+{
+ FillWindowPixelBuffer(1, PIXEL_FILL(0));
+ PutWindowTilemap(1);
+ CopyWindowToVram(1, 3);
+}
+
+static void LoadWin3(void)
+{
+ FillWindowPixelBuffer(3, PIXEL_FILL(1));
+ TextWindow_SetUserSelectedFrame(3, 1, 0xD0);
+ TextWindow_SetStdFrame0_WithPal(3, 0xA, 0x20);
+ LoadPalette(gTMCaseMainWindowPalette, 0xE0, 0x20);
+}
+
+static void sub_812AD50(void)
+{
+ struct ScanlineEffectParams params;
+ params.dmaControl = SCANLINE_EFFECT_DMACNT_16BIT;
+ params.dmaDest = &REG_BG1HOFS;
+ params.initState = 1;
+ params.unused9 = 0;
+ sWork->bg1hofs = 0;
+ CpuFastFill(0, gScanlineEffectRegBuffers, sizeof(gScanlineEffectRegBuffers));
+ ScanlineEffect_SetParams(params);
+}
+
+static void FillScanlineEffectWithValue1col(s16 arg0)
+{
+ CpuFill16(arg0, gScanlineEffectRegBuffers[gScanlineEffect.srcBuffer], 0x120);
+ CpuFill16(0, gScanlineEffectRegBuffers[gScanlineEffect.srcBuffer] + 0x90, 0x20);
+}
+
+static void FillScanlineEffectWithValue2col(s16 arg0)
+{
+ CpuFill16(arg0, gScanlineEffectRegBuffers[0], 0x120);
+ CpuFill16(0, gScanlineEffectRegBuffers[0] + 0x90, 0x20);
+ CpuFill16(arg0, gScanlineEffectRegBuffers[0] + 0x3C0, 0x120);
+ CpuFill16(0, gScanlineEffectRegBuffers[0] + 0x450, 0x20);
+}
diff --git a/src/union_room_chat_objects.c b/src/union_room_chat_objects.c
new file mode 100644
index 000000000..f97136a0a
--- /dev/null
+++ b/src/union_room_chat_objects.c
@@ -0,0 +1,318 @@
+#include "global.h"
+#include "gflib.h"
+#include "decompress.h"
+#include "graphics.h"
+#include "union_room_chat.h"
+
+struct UnionRoomChat3
+{
+ struct Sprite *selectorCursorSprite;
+ struct Sprite *characterSelectCursorSprite;
+ struct Sprite *textEntryCursorSprite;
+ struct Sprite *rButtonSprite;
+ struct Sprite *chatIconsSprite;
+ u16 cursorBlinkTimer;
+};
+
+static EWRAM_DATA struct UnionRoomChat3 *sWork = NULL;
+
+static void SpriteCB_TextEntryCursor(struct Sprite * sprite);
+static void SpriteCB_CharacterSelectCursor(struct Sprite * sprite);
+
+static const u16 sUnionRoomChatInterfacePal[] = INCBIN_U16("graphics/union_room_chat/unk_845AC14.gbapal");
+static const u32 sSelectorCursorGfxTiles[] = INCBIN_U32("graphics/union_room_chat/unk_845AC34.4bpp.lz");
+static const u32 sHorizontalBarGfxTiles[] = INCBIN_U32("graphics/union_room_chat/unk_845AEB8.4bpp.lz");
+static const u32 sMenuCursorGfxTiles[] = INCBIN_U32("graphics/union_room_chat/unk_845AED8.4bpp.lz");
+static const u32 sRButtonGfxTiles[] = INCBIN_U32("graphics/union_room_chat/unk_845AF04.4bpp.lz");
+
+static const struct CompressedSpriteSheet sSpriteSheets[] = {
+ {sSelectorCursorGfxTiles, 0x1000, 0},
+ {sMenuCursorGfxTiles, 0x0040, 1},
+ {sHorizontalBarGfxTiles, 0x0040, 2},
+ {sRButtonGfxTiles, 0x0080, 3},
+ {gUnionRoomChatIcons, 0x0400, 4}
+};
+
+static const struct SpritePalette sSpritePalette = {
+ sUnionRoomChatInterfacePal, 0
+};
+
+static const struct OamData sOamData_64x32_1 = {
+ .shape = SPRITE_SHAPE(64x32),
+ .size = SPRITE_SIZE(64x32),
+ .priority = 1
+};
+
+static const union AnimCmd sAnim_CursorSmallOpen[] = {
+ ANIMCMD_FRAME(0x00, 30),
+ ANIMCMD_END
+};
+
+static const union AnimCmd sAnim_CursorSmallClosed[] = {
+ ANIMCMD_FRAME(0x20, 30),
+ ANIMCMD_END
+};
+
+static const union AnimCmd sAnim_CursorLargeOpen[] = {
+ ANIMCMD_FRAME(0x40, 30),
+ ANIMCMD_END
+};
+
+static const union AnimCmd sAnim_CursorLargeClosed[] = {
+ ANIMCMD_FRAME(0x60, 30),
+ ANIMCMD_END
+};
+
+static const union AnimCmd *const sSpriteAnims_SelectorCursor[] = {
+ sAnim_CursorSmallOpen,
+ sAnim_CursorSmallClosed,
+ sAnim_CursorLargeOpen,
+ sAnim_CursorLargeClosed
+};
+
+static const struct SpriteTemplate sSpriteTemplate_SelectorCursor = {
+ .tileTag = 0,
+ .paletteTag = 0,
+ .oam = &sOamData_64x32_1,
+ .anims = sSpriteAnims_SelectorCursor,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCallbackDummy
+};
+
+static const struct OamData sOamData_8x16_2 = {
+ .shape = SPRITE_SHAPE(8x16),
+ .size = SPRITE_SIZE(8x16),
+ .priority = 2
+};
+
+static const struct SpriteTemplate sSpriteTemplate_TextEntryCursor = {
+ .tileTag = 2,
+ .paletteTag = 0,
+ .oam = &sOamData_8x16_2,
+ .anims = gDummySpriteAnimTable,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCB_TextEntryCursor
+};
+
+static const struct SpriteTemplate sSpriteTemplate_CharacterSelectCursor = {
+ .tileTag = 1,
+ .paletteTag = 0,
+ .oam = &sOamData_8x16_2,
+ .anims = gDummySpriteAnimTable,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCB_CharacterSelectCursor
+};
+
+static const struct OamData sOamData_16x16_2 = {
+ .shape = SPRITE_SHAPE(16x16),
+ .size = SPRITE_SIZE(16x16),
+ .priority = 2
+};
+
+static const struct OamData sOamData_32x16_2 = {
+ .shape = SPRITE_SHAPE(32x16),
+ .size = SPRITE_SIZE(32x16),
+ .priority = 2
+};
+
+static const union AnimCmd sAnim_UnionRoomChatIcons_ToggleCase[] = {
+ ANIMCMD_FRAME(0x00, 2),
+ ANIMCMD_END
+};
+
+static const union AnimCmd sAnim_UnionRoomChatIcons_Dummy1[] = {
+ ANIMCMD_FRAME(0x08, 2),
+ ANIMCMD_END
+};
+
+static const union AnimCmd sAnim_UnionRoomChatIcons_Dummy2[] = {
+ ANIMCMD_FRAME(0x10, 2),
+ ANIMCMD_END
+};
+
+static const union AnimCmd sAnim_UnionRoomChatIcons_Register[] = {
+ ANIMCMD_FRAME(0x18, 2),
+ ANIMCMD_END
+};
+
+static const union AnimCmd *const sSpriteAnimTable_UnionRoomChatIcons[] = {
+ sAnim_UnionRoomChatIcons_ToggleCase,
+ sAnim_UnionRoomChatIcons_Dummy1,
+ sAnim_UnionRoomChatIcons_Dummy2,
+ sAnim_UnionRoomChatIcons_Register
+};
+
+static const struct SpriteTemplate sSpriteTemplate_RButton = {
+ .tileTag = 3,
+ .paletteTag = 0,
+ .oam = &sOamData_16x16_2,
+ .anims = gDummySpriteAnimTable,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCallbackDummy
+};
+
+static const struct SpriteTemplate sSpriteTemplate_UnionRoomChatIcons = {
+ .tileTag = 4,
+ .paletteTag = 0,
+ .oam = &sOamData_32x16_2,
+ .anims = sSpriteAnimTable_UnionRoomChatIcons,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCallbackDummy
+};
+
+bool32 UnionRoomChat_TryAllocSpriteWork(void)
+{
+ int i;
+ for (i = 0; i < NELEMS(sSpriteSheets); i++)
+ LoadCompressedSpriteSheet(&sSpriteSheets[i]);
+
+ LoadSpritePalette(&sSpritePalette);
+ sWork = Alloc(sizeof(struct UnionRoomChat3));
+ if (sWork == NULL)
+ return FALSE;
+
+ return TRUE;
+}
+
+void UnionRoomChat_FreeSpriteWork(void)
+{
+ if (sWork != NULL)
+ Free(sWork);
+}
+
+void UnionRoomChat_CreateSelectorCursorObj(void)
+{
+ u8 spriteId = CreateSprite(&sSpriteTemplate_SelectorCursor, 10, 24, 0);
+ sWork->selectorCursorSprite = &gSprites[spriteId];
+}
+
+void UnionRoomChat_ToggleSelectorCursorObjVisibility(bool32 invisible)
+{
+ sWork->selectorCursorSprite->invisible = invisible;
+}
+
+void UnionRoomChat_MoveSelectorCursorObj(void)
+{
+ u8 x, y;
+ u8 page = GetCurrentKeyboardPage();
+ UnionRoomChat_GetCursorColAndRow(&x, &y);
+ if (page != UNION_ROOM_KB_PAGE_COUNT)
+ {
+ StartSpriteAnim(sWork->selectorCursorSprite, 0);
+ sWork->selectorCursorSprite->pos1.x = x * 8 + 10;
+ sWork->selectorCursorSprite->pos1.y = y * 12 + 24;
+ }
+ else
+ {
+ StartSpriteAnim(sWork->selectorCursorSprite, 2);
+ sWork->selectorCursorSprite->pos1.x = 24;
+ sWork->selectorCursorSprite->pos1.y = y * 12 + 24;
+ }
+}
+
+void UnionRoomChat_UpdateObjPalCycle(int arg0)
+{
+ const u16 *palette = &sUnionRoomChatInterfacePal[arg0 * 2 + 1];
+ u8 index = IndexOfSpritePaletteTag(0);
+ LoadPalette(palette, index * 16 + 0x101, 4);
+}
+
+void UnionRoomChat_SetSelectorCursorClosedImage(void)
+{
+ if (GetCurrentKeyboardPage() != UNION_ROOM_KB_PAGE_COUNT)
+ StartSpriteAnim(sWork->selectorCursorSprite, 1);
+ else
+ StartSpriteAnim(sWork->selectorCursorSprite, 3);
+
+ sWork->cursorBlinkTimer = 0;
+}
+
+bool32 UnionRoomChat_AnimateSelectorCursorReopen(void)
+{
+ if (sWork->cursorBlinkTimer > 3)
+ return FALSE;
+
+ if (++sWork->cursorBlinkTimer > 3)
+ {
+ if (GetCurrentKeyboardPage() != UNION_ROOM_KB_PAGE_COUNT)
+ StartSpriteAnim(sWork->selectorCursorSprite, 0);
+ else
+ StartSpriteAnim(sWork->selectorCursorSprite, 2);
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void UnionRoomChat_SpawnTextEntryPointerSprites(void)
+{
+ u8 spriteId = CreateSprite(&sSpriteTemplate_TextEntryCursor, 76, 152, 2);
+ sWork->textEntryCursorSprite = &gSprites[spriteId];
+ spriteId = CreateSprite(&sSpriteTemplate_CharacterSelectCursor, 64, 152, 1);
+ sWork->characterSelectCursorSprite = &gSprites[spriteId];
+}
+
+static void SpriteCB_TextEntryCursor(struct Sprite *sprite)
+{
+ int var0 = UnionRoomChat_GetMessageEntryCursorPosition();
+ if (var0 == 15)
+ {
+ sprite->invisible = TRUE;
+ }
+ else
+ {
+ sprite->invisible = FALSE;
+ sprite->pos1.x = var0 * 8 + 76;
+ }
+}
+
+static void SpriteCB_CharacterSelectCursor(struct Sprite *sprite)
+{
+ if (++sprite->data[0] > 4)
+ {
+ sprite->data[0] = 0;
+ if (++sprite->pos2.x > 4)
+ sprite->pos2.x = 0;
+ }
+}
+
+void CreatePageSwitchUISprites(void)
+{
+ u8 spriteId = CreateSprite(&sSpriteTemplate_RButton, 8, 152, 3);
+ sWork->rButtonSprite = &gSprites[spriteId];
+ spriteId = CreateSprite(&sSpriteTemplate_UnionRoomChatIcons, 32, 152, 4);
+ sWork->chatIconsSprite = &gSprites[spriteId];
+ sWork->chatIconsSprite->invisible = TRUE;
+}
+
+void UpdateVisibleUnionRoomChatIcon(void)
+{
+ if (GetCurrentKeyboardPage() == UNION_ROOM_KB_PAGE_COUNT)
+ {
+ if (UnionRoomChat_LenMessageEntryBuffer() != 0)
+ {
+ // REGISTER
+ sWork->chatIconsSprite->invisible = FALSE;
+ StartSpriteAnim(sWork->chatIconsSprite, 3);
+ }
+ else
+ {
+ sWork->chatIconsSprite->invisible = TRUE;
+ }
+ }
+ else
+ {
+ int anim = UnionRoomChat_GetWhetherShouldShowCaseToggleIcon();
+ if (anim == 3)
+ {
+ sWork->chatIconsSprite->invisible = TRUE;
+ }
+ else
+ {
+ // A <--> a
+ sWork->chatIconsSprite->invisible = FALSE;
+ StartSpriteAnim(sWork->chatIconsSprite, anim);
+ }
+ }
+}