summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/clear_save_data_screen.c4
-rw-r--r--src/easy_chat_2.c1363
-rw-r--r--src/easy_chat_3.c2298
-rw-r--r--src/graphics.c12
4 files changed, 3669 insertions, 8 deletions
diff --git a/src/clear_save_data_screen.c b/src/clear_save_data_screen.c
index 5485e8da9..b6f8b83e9 100644
--- a/src/clear_save_data_screen.c
+++ b/src/clear_save_data_screen.c
@@ -131,7 +131,7 @@ static void Task_HandleYesNoMenu(u8 taskId)
{
switch (Menu_ProcessInputNoWrapClearOnChoose())
{
- case -1:
+ case MENU_B_PRESSED:
case 1:
PlaySE(SE_SELECT);
break;
@@ -142,7 +142,7 @@ static void Task_HandleYesNoMenu(u8 taskId)
CopyWindowToVram(1, 3);
ClearSaveData();
break;
- case -2:
+ case MENU_NOTHING_CHOSEN:
default:
return;
}
diff --git a/src/easy_chat_2.c b/src/easy_chat_2.c
new file mode 100644
index 000000000..4b3c70b67
--- /dev/null
+++ b/src/easy_chat_2.c
@@ -0,0 +1,1363 @@
+#include "global.h"
+#include "gflib.h"
+#include "easy_chat.h"
+#include "event_data.h"
+#include "menu.h"
+#include "mevent.h"
+#include "overworld.h"
+#include "strings.h"
+#include "task.h"
+#include "constants/songs.h"
+
+#define EZCHAT_TASK_STATE 0
+#define EZCHAT_TASK_TYPE 1
+#define EZCHAT_TASK_WORDS 2
+#define EZCHAT_TASK_MAINCALLBACK 4
+#define EZCHAT_TASK_UNK06 6
+#define EZCHAT_TASK_SIZE 7
+
+struct EasyChatScreenTemplate
+{
+ u8 type;
+ u8 numColumns;
+ u8 numRows;
+ u8 frameId;
+ const u8 *titleText;
+ const u8 *instructionsText1;
+ const u8 *instructionsText2;
+ const u8 *confirmText1;
+ const u8 *confirmText2;
+};
+
+struct EasyChatScreen
+{
+ /*0x00*/ u8 type;
+ /*0x01*/ u8 templateId;
+ /*0x02*/ u8 numColumns;
+ /*0x03*/ u8 numRows;
+ /*0x04*/ u8 state;
+ /*0x05*/ s8 mainCursorColumn;
+ /*0x06*/ s8 mainCursorRow;
+ /*0x07*/ u8 numWords;
+ /*0x08*/ u8 stateBackup;
+ /*0x09*/ bool8 isAlphaMode;
+ /*0x0A*/ s8 selectGroupCursorX;
+ /*0x0B*/ s8 selectGroupCursorY;
+ /*0x0C*/ u8 selectGroupRowsAbove;
+ /*0x0D*/ u8 selectGroupNumRows;
+ /*0x0E*/ u8 selectWordRowsAbove;
+ /*0x0F*/ u8 selectWordNumRows;
+ /*0x10*/ s8 selectWordCursorX;
+ /*0x11*/ s8 selectWordCursorY;
+ /*0x14*/ u16 *words;
+ /*0x18*/ u16 ecWordBuffer[9];
+};
+
+static EWRAM_DATA struct EasyChatScreen * sEasyChatScreen = NULL;
+
+static void CB2_EasyChatScreen(void);
+static void Task_InitEasyChat(u8 taskId);
+static void Task_RunEasyChat(u8 taskId);
+static bool8 Task_InitEasyChatInternal(u8 taskId);
+static void DismantleEasyChat(MainCallback cb);
+static void CompareProfileResponseWithPassphrase(void);
+static void CompareQuestionnaireResponseWithPassphrase(void);
+static bool8 EasyChat_AllocateResources(u8 type, u16 *words);
+static void EasyChat_FreeResources(void);
+static u16 EasyChatScreen_HandleJoypad(void);
+static u16 HandleJoypad_SelectField(void);
+static u16 HandleJoypad_SelectFooter(void);
+static u16 HandleJoypad_SelectGroup(void);
+static u16 HandleJoypad_SelectWord(void);
+static u16 Cancel_HandleYesNoMenu(void);
+static u16 Confirm_HandleYesNoMenu(void);
+static u16 DelAll_HandleYesNoMenu(void);
+static u16 Cancel_CreateYesNoMenu(void);
+static u16 DelAll_CreateYesNoMenu(void);
+static u16 Confirm_CreateYesNoMenu(void);
+static u8 GetStateBackup(void);
+static int OpenSelectedGroup(void);
+static int BackOutFromGroupToFieldSelect(void);
+static int ToggleGroupAlphaMode(void);
+static int DeleteSelectedWord(void);
+static int PlaceSelectedWord(void);
+static void CommitECWords(void);
+static void DeleteAllECFields(void);
+static void SetEasyChatWordToField(u16 word);
+static bool8 HasECMessageChanged(void);
+static u16 SelectGroupCursorAction(u32 action);
+static int UpdateSelectGroupCursorPos_OutsideBlueBox_GroupMode(u32 action);
+static int UpdateSelectGroupCursorPos_OutsideBlueBox_AlphaMode(u32 action);
+static int UpdateSelectGroupCursorPos_InsideBlueBox(u32 action);
+static void GroupCursorMoveToBlueBox(void);
+static void GroupCursorWrapAroundLeft(void);
+static u16 SelectWordCursorAction(u32 action);
+static u16 GetSelectedFieldIndex(void);
+static u16 GetSelectedGroupIndex(void);
+static int GetSelectedLetter(void);
+static u16 GetSelectWordCursorPos(void);
+static u8 GetMaxGroupCursorXinAlphaMode(u8 unkB);
+static void MoveGroupCursorXToMaxCol(void);
+static void MoveWordCursorXToMaxCol(void);
+static bool8 GroupSelectCursorXPosTooFarRight(void);
+static bool8 WordSelectCursorXPosTooFarRight(void);
+static bool8 IsPhraseDifferentThanPlayerInput(const u16 *wordsToCompare, u8 numWords);
+static u8 GetEasyChatScreenTemplateId(u8 type);
+static bool32 IsEcWordBufferUninitialized(void);
+
+void DoEasyChatScreen(u8 type, u16 *words, MainCallback callback)
+{
+ u8 taskId;
+ ResetTasks();
+ taskId = CreateTask(Task_InitEasyChat, 0);
+ gTasks[taskId].data[EZCHAT_TASK_TYPE] = type;
+ SetWordTaskArg(taskId, EZCHAT_TASK_WORDS, (uintptr_t)words);
+ SetWordTaskArg(taskId, EZCHAT_TASK_MAINCALLBACK, (uintptr_t)callback);
+ SetMainCallback2(CB2_EasyChatScreen);
+}
+
+static void CB2_EasyChatScreen(void)
+{
+ RunTasks();
+ AnimateSprites();
+ BuildOamBuffer();
+ UpdatePaletteFade();
+}
+
+static void VBlankCallback_EasyChatScreen(void)
+{
+ TransferPlttBuffer();
+ LoadOam();
+ ProcessSpriteCopyRequests();
+}
+
+static void SetEasyChatTaskFunc(u8 taskId, TaskFunc func)
+{
+ gTasks[taskId].func = func;
+ gTasks[taskId].data[EZCHAT_TASK_STATE] = 0;
+}
+
+static void Task_InitEasyChat(u8 taskId)
+{
+ if (!IsUpdateLinkStateCBActive())
+ {
+ while (Task_InitEasyChatInternal(taskId))
+ ;
+ }
+ else
+ {
+ if (Task_InitEasyChatInternal(taskId) == TRUE)
+ return;
+ }
+ SetEasyChatTaskFunc(taskId, Task_RunEasyChat);
+}
+
+static void Task_RunEasyChat(u8 taskId)
+{
+ u16 action;
+ s16 *data;
+
+ data = gTasks[taskId].data;
+ switch (data[EZCHAT_TASK_STATE])
+ {
+ case 0:
+ SetVBlankCallback(VBlankCallback_EasyChatScreen);
+ BlendPalettes(0xFFFFFFFF, 16, RGB_BLACK);
+ BeginNormalPaletteFade(0xFFFFFFFF, -1, 16, 0, RGB_BLACK);
+ data[EZCHAT_TASK_STATE]++;
+ break;
+ case 1:
+ action = EasyChatScreen_HandleJoypad();
+ if (action == 23)
+ {
+ BeginNormalPaletteFade(0xFFFFFFFF, -1, 0, 16, RGB_BLACK);
+ data[EZCHAT_TASK_STATE] = 3;
+ }
+ else if (action != 0)
+ {
+ PlaySE(SE_SELECT);
+ EasyChatInterfaceCommand_Setup(action);
+ data[EZCHAT_TASK_STATE]++;
+ }
+ break;
+ case 2:
+ if (!EasyChatInterfaceCommand_Run())
+ data[EZCHAT_TASK_STATE] = 1;
+ break;
+ case 3:
+ if (!gPaletteFade.active)
+ {
+ if (data[EZCHAT_TASK_TYPE] == EASY_CHAT_TYPE_QUESTIONNAIRE)
+ CompareQuestionnaireResponseWithPassphrase();
+ if (data[EZCHAT_TASK_TYPE] == EASY_CHAT_TYPE_PROFILE)
+ {
+ FlagSet(FLAG_SYS_SET_TRAINER_CARD_PROFILE);
+ CompareProfileResponseWithPassphrase();
+ }
+ DismantleEasyChat((MainCallback)GetWordTaskArg(taskId, EZCHAT_TASK_MAINCALLBACK));
+ }
+ break;
+ }
+}
+
+static bool8 Task_InitEasyChatInternal(u8 taskId)
+{
+ s16 *data;
+
+ data = gTasks[taskId].data;
+ switch (data[EZCHAT_TASK_STATE])
+ {
+ case 0:
+ SetVBlankCallback(NULL);
+ ResetSpriteData();
+ FreeAllSpritePalettes();
+ ResetPaletteFade();
+ break;
+ case 1:
+ if (!InitEasyChatSelection())
+ {
+ DismantleEasyChat((MainCallback)GetWordTaskArg(taskId, EZCHAT_TASK_MAINCALLBACK));
+ }
+ break;
+ case 2:
+ if (!EasyChat_AllocateResources(data[EZCHAT_TASK_TYPE], (u16 *)GetWordTaskArg(taskId, EZCHAT_TASK_WORDS)))
+ {
+ DismantleEasyChat((MainCallback)GetWordTaskArg(taskId, EZCHAT_TASK_MAINCALLBACK));
+ }
+ break;
+ case 3:
+ if (!InitEasyChatGraphicsWork())
+ {
+ DismantleEasyChat((MainCallback)GetWordTaskArg(taskId, EZCHAT_TASK_MAINCALLBACK));
+ }
+ break;
+ case 4:
+ if (LoadEasyChatGraphics())
+ {
+ return TRUE;
+ }
+ break;
+ default:
+ return FALSE;
+ }
+ data[EZCHAT_TASK_STATE]++;
+ return TRUE;
+}
+
+static void DismantleEasyChat(MainCallback callback)
+{
+ DestroyEasyChatSelectionData();
+ EasyChat_FreeResources();
+ DestroyEasyChatGraphicsResources();
+ FreeAllWindowBuffers();
+ SetMainCallback2(callback);
+}
+
+void ShowEasyChatScreen(void)
+{
+ u16 *words;
+ switch (gSpecialVar_0x8004)
+ {
+ case EASY_CHAT_TYPE_PROFILE:
+ words = gSaveBlock1Ptr->easyChatProfile;
+ break;
+ case EASY_CHAT_TYPE_BATTLE_START:
+ words = gSaveBlock1Ptr->easyChatBattleStart;
+ break;
+ case EASY_CHAT_TYPE_BATTLE_WON:
+ words = gSaveBlock1Ptr->easyChatBattleWon;
+ break;
+ case EASY_CHAT_TYPE_BATTLE_LOST:
+ words = gSaveBlock1Ptr->easyChatBattleLost;
+ break;
+ case EASY_CHAT_TYPE_QUESTIONNAIRE:
+ words = GetMEventProfileECWordsMaybe();
+ break;
+ case EASY_CHAT_TYPE_MAIL:
+ words = gSaveBlock1Ptr->mail[gSpecialVar_0x8005].words;
+ break;
+ default:
+ return;
+ }
+ DoEasyChatScreen(gSpecialVar_0x8004, words, sub_80568C4);
+}
+
+static const u16 sECPhrase_MysteryEventIsExciting[] = {
+ EC_WORD_MYSTERY,
+ EC_WORD_EVENT,
+ EC_WORD_IS,
+ EC_WORD_EXCITING
+};
+
+static void CompareProfileResponseWithPassphrase(void)
+{
+ gSpecialVar_0x8004 = IsPhraseDifferentThanPlayerInput(sECPhrase_MysteryEventIsExciting, NELEMS(sECPhrase_MysteryEventIsExciting));
+}
+
+static const u16 sECPhrase_LinkTogetherWithAll[] = {
+ EC_WORD_LINK,
+ EC_WORD_TOGETHER,
+ EC_WORD_WITH,
+ EC_WORD_ALL
+};
+
+static void CompareQuestionnaireResponseWithPassphrase(void)
+{
+ gSpecialVar_0x8004 = IsPhraseDifferentThanPlayerInput(sECPhrase_LinkTogetherWithAll, NELEMS(sECPhrase_LinkTogetherWithAll));
+}
+
+static const struct EasyChatScreenTemplate sEasyChatScreenTemplates[] = {
+ {
+ .type = EASY_CHAT_TYPE_PROFILE,
+ .numColumns = 2,
+ .numRows = 2,
+ .frameId = 0,
+ .titleText = gUnknown_8418A2B,
+ .instructionsText1 = gUnknown_84186D1,
+ .instructionsText2 = gUnknown_84186EF,
+ .confirmText1 = gUnknown_841880E,
+ .confirmText2 = gUnknown_8418902
+ }, {
+ .type = EASY_CHAT_TYPE_BATTLE_START,
+ .numColumns = 2,
+ .numRows = 3,
+ .frameId = 1,
+ .titleText = gUnknown_8418A33,
+ .instructionsText1 = gUnknown_8418706,
+ .instructionsText2 = gUnknown_8418725,
+ .confirmText1 = gUnknown_841881B,
+ .confirmText2 = gUnknown_8418902
+ }, {
+ .type = EASY_CHAT_TYPE_BATTLE_WON,
+ .numColumns = 2,
+ .numRows = 3,
+ .frameId = 1,
+ .titleText = gUnknown_8418A4A,
+ .instructionsText1 = gUnknown_8418706,
+ .instructionsText2 = gUnknown_8418725,
+ .confirmText1 = gUnknown_841883E,
+ .confirmText2 = gUnknown_8418902
+ }, {
+ .type = EASY_CHAT_TYPE_BATTLE_LOST,
+ .numColumns = 2,
+ .numRows = 3,
+ .frameId = 1,
+ .titleText = gUnknown_8418A61,
+ .instructionsText1 = gUnknown_8418706,
+ .instructionsText2 = gUnknown_8418725,
+ .confirmText1 = gUnknown_841885F,
+ .confirmText2 = gUnknown_8418902
+ }, {
+ .type = EASY_CHAT_TYPE_MAIL,
+ .numColumns = 2,
+ .numRows = 5,
+ .frameId = 2,
+ .titleText = NULL,
+ .instructionsText1 = gUnknown_8418780,
+ .instructionsText2 = gUnknown_841879E,
+ .confirmText1 = gUnknown_841888C,
+ .confirmText2 = gUnknown_8418902
+ }, {
+ .type = EASY_CHAT_TYPE_MAIL_NO_CONFIRM,
+ .numColumns = 2,
+ .numRows = 2,
+ .frameId = 0,
+ .instructionsText1 = gUnknown_8418780,
+ .instructionsText2 = gUnknown_841879E,
+ }, {
+ .type = EASY_CHAT_TYPE_BARD_SONG,
+ .numColumns = 2,
+ .numRows = 3,
+ .frameId = 1,
+ .titleText = gUnknown_8418A77,
+ .instructionsText1 = gUnknown_84187B2,
+ .instructionsText2 = gUnknown_84187D1,
+ .confirmText1 = gUnknown_84188AC,
+ .confirmText2 = gUnknown_8418902
+ }, {
+ .type = EASY_CHAT_TYPE_INTERVIEW,
+ .numColumns = 2,
+ .numRows = 3,
+ .frameId = 1,
+ .titleText = gUnknown_8418AA1,
+ .instructionsText1 = gUnknown_8418745,
+ .instructionsText2 = gUnknown_8418763,
+ .confirmText1 = gUnknown_8418881,
+ .confirmText2 = gUnknown_8418902
+ }, {
+ .type = EASY_CHAT_TYPE_TRENDY_PHRASE,
+ .numColumns = 2,
+ .numRows = 1,
+ .frameId = 3,
+ .titleText = gUnknown_8418A87,
+ .instructionsText1 = gUnknown_84188B9,
+ .instructionsText2 = gUnknown_84188D6,
+ .confirmText1 = gUnknown_84188F0,
+ .confirmText2 = gUnknown_8418902
+ }, {
+ .type = EASY_CHAT_TYPE_QUESTIONNAIRE,
+ .numColumns = 2,
+ .numRows = 2,
+ .frameId = 0,
+ .titleText = gUnknown_8418AB2,
+ .instructionsText1 = gUnknown_84186D1,
+ .instructionsText2 = gUnknown_84187EE,
+ .confirmText1 = gUnknown_8418881,
+ .confirmText2 = gUnknown_8418902
+ }
+};
+
+static bool8 EasyChat_AllocateResources(u8 type, u16 *words)
+{
+ u8 templateId;
+ int i;
+
+ sEasyChatScreen = malloc(sizeof(*sEasyChatScreen));
+ if (sEasyChatScreen == NULL)
+ return FALSE;
+
+ sEasyChatScreen->type = type;
+ sEasyChatScreen->words = words;
+ sEasyChatScreen->state = 0;
+ sEasyChatScreen->mainCursorColumn = 0;
+ sEasyChatScreen->mainCursorRow = 0;
+ sEasyChatScreen->isAlphaMode = FALSE;
+ templateId = GetEasyChatScreenTemplateId(type);
+
+ sEasyChatScreen->numColumns = sEasyChatScreenTemplates[templateId].numColumns;
+ sEasyChatScreen->numRows = sEasyChatScreenTemplates[templateId].numRows;
+ sEasyChatScreen->numWords = sEasyChatScreen->numColumns * sEasyChatScreen->numRows;
+ sEasyChatScreen->templateId = templateId;
+ if (sEasyChatScreen->numWords > 9)
+ sEasyChatScreen->numWords = 9;
+
+ CpuCopy16(words, sEasyChatScreen->ecWordBuffer, sEasyChatScreen->numWords * sizeof(u16));
+ sEasyChatScreen->selectGroupNumRows = (GetNumDisplayableGroups() - 1) / 2 + 1;
+ return TRUE;
+}
+
+static void EasyChat_FreeResources(void)
+{
+ if (sEasyChatScreen != NULL)
+ Free(sEasyChatScreen);
+}
+
+static u16 EasyChatScreen_HandleJoypad(void)
+{
+ switch (sEasyChatScreen->state)
+ {
+ case 0:
+ return HandleJoypad_SelectField();
+ case 1:
+ return HandleJoypad_SelectFooter();
+ case 2:
+ return HandleJoypad_SelectGroup();
+ case 3:
+ return HandleJoypad_SelectWord();
+ case 4:
+ return Cancel_HandleYesNoMenu();
+ case 5:
+ return DelAll_HandleYesNoMenu();
+ case 6:
+ return Confirm_HandleYesNoMenu();
+ }
+ return 0;
+}
+
+static u16 HandleJoypad_SelectField(void)
+{
+ do
+ {
+ if (JOY_NEW(A_BUTTON))
+ {
+ sEasyChatScreen->state = 2;
+ sEasyChatScreen->selectGroupCursorX = 0;
+ sEasyChatScreen->selectGroupCursorY = 0;
+ sEasyChatScreen->selectGroupRowsAbove = 0;
+ return 9;
+ }
+ else if (JOY_NEW(B_BUTTON))
+ {
+ return Cancel_CreateYesNoMenu();
+ }
+ else if (JOY_NEW(START_BUTTON))
+ {
+ return Confirm_CreateYesNoMenu();
+ }
+ else if (JOY_NEW(DPAD_UP))
+ {
+ sEasyChatScreen->mainCursorRow--;
+ break;
+ }
+ else if (JOY_NEW(DPAD_LEFT))
+ {
+ sEasyChatScreen->mainCursorColumn--;
+ break;
+ }
+ else if (JOY_NEW(DPAD_DOWN))
+ {
+ sEasyChatScreen->mainCursorRow++;
+ break;
+ }
+ else if (JOY_NEW(DPAD_RIGHT))
+ {
+ sEasyChatScreen->mainCursorColumn++;
+ break;
+ }
+
+ return 0;
+ } while (0);
+
+ if (sEasyChatScreen->mainCursorRow < 0)
+ sEasyChatScreen->mainCursorRow = sEasyChatScreenTemplates[sEasyChatScreen->templateId].numRows;
+
+ if (sEasyChatScreen->mainCursorRow > sEasyChatScreenTemplates[sEasyChatScreen->templateId].numRows)
+ sEasyChatScreen->mainCursorRow = 0;
+
+ if (sEasyChatScreen->mainCursorRow == sEasyChatScreenTemplates[sEasyChatScreen->templateId].numRows)
+ {
+ if (sEasyChatScreen->mainCursorColumn > 2)
+ sEasyChatScreen->mainCursorColumn = 2;
+
+ sEasyChatScreen->state = 1;
+ return 3;
+ }
+
+ if (sEasyChatScreen->mainCursorColumn < 0)
+ sEasyChatScreen->mainCursorColumn = sEasyChatScreenTemplates[sEasyChatScreen->templateId].numColumns - 1;
+
+ if (sEasyChatScreen->mainCursorColumn >= sEasyChatScreenTemplates[sEasyChatScreen->templateId].numColumns)
+ sEasyChatScreen->mainCursorColumn = 0;
+
+ if (GetEasyChatScreenFrameId() == 2 && sEasyChatScreen->mainCursorColumn == 1 && sEasyChatScreen->mainCursorRow == 4)
+ sEasyChatScreen->mainCursorColumn = 0;
+
+ return 2;
+}
+
+static u16 HandleJoypad_SelectFooter(void)
+{
+ do
+ {
+ if (JOY_NEW(A_BUTTON))
+ {
+ switch (sEasyChatScreen->mainCursorColumn)
+ {
+ case 0:
+ return DelAll_CreateYesNoMenu();
+ case 1:
+ return Cancel_CreateYesNoMenu();
+ case 2:
+ return Confirm_CreateYesNoMenu();
+ }
+ }
+
+ if (JOY_NEW(B_BUTTON))
+ {
+ return Cancel_CreateYesNoMenu();
+ }
+ else if (JOY_NEW(START_BUTTON))
+ {
+ return Confirm_CreateYesNoMenu();
+ }
+ else if (JOY_NEW(DPAD_UP))
+ {
+ sEasyChatScreen->mainCursorRow--;
+ break;
+ }
+ else if (JOY_NEW(DPAD_LEFT))
+ {
+ sEasyChatScreen->mainCursorColumn--;
+ break;
+ }
+ else if (JOY_NEW(DPAD_DOWN))
+ {
+ sEasyChatScreen->mainCursorRow = 0;
+ break;
+ }
+ else if (JOY_NEW(DPAD_RIGHT))
+ {
+ sEasyChatScreen->mainCursorColumn++;
+ break;
+ }
+
+ return 0;
+ } while (0);
+
+ if (sEasyChatScreen->mainCursorRow == sEasyChatScreenTemplates[sEasyChatScreen->templateId].numRows)
+ {
+ if (sEasyChatScreen->mainCursorColumn < 0)
+ sEasyChatScreen->mainCursorColumn = 2;
+
+ if (sEasyChatScreen->mainCursorColumn >= 3)
+ sEasyChatScreen->mainCursorColumn = 0;
+
+ return 3;
+ }
+
+ if (sEasyChatScreen->mainCursorColumn >= sEasyChatScreenTemplates[sEasyChatScreen->templateId].numColumns)
+ sEasyChatScreen->mainCursorColumn = sEasyChatScreenTemplates[sEasyChatScreen->templateId].numColumns - 1;
+
+ if (GetEasyChatScreenFrameId() == 2 && sEasyChatScreen->mainCursorColumn == 1 && sEasyChatScreen->mainCursorRow == 4)
+ sEasyChatScreen->mainCursorColumn = 0;
+
+ sEasyChatScreen->state = 0;
+ return 2;
+}
+
+static u16 HandleJoypad_SelectGroup(void)
+{
+ if (JOY_NEW(B_BUTTON))
+ return BackOutFromGroupToFieldSelect();
+
+ if (JOY_NEW(A_BUTTON))
+ {
+ if (sEasyChatScreen->selectGroupCursorX != -1)
+ return OpenSelectedGroup();
+
+ switch (sEasyChatScreen->selectGroupCursorY)
+ {
+ case 0:
+ return ToggleGroupAlphaMode();
+ case 1:
+ return DeleteSelectedWord();
+ case 2:
+ return BackOutFromGroupToFieldSelect();
+ }
+ }
+
+ if (JOY_NEW(SELECT_BUTTON))
+ return ToggleGroupAlphaMode();
+
+ if (JOY_REPT(DPAD_UP))
+ return SelectGroupCursorAction(2);
+
+ if (JOY_REPT(DPAD_DOWN))
+ return SelectGroupCursorAction(3);
+
+ if (JOY_REPT(DPAD_LEFT))
+ return SelectGroupCursorAction(1);
+
+ if (JOY_REPT(DPAD_RIGHT))
+ return SelectGroupCursorAction(0);
+
+ return 0;
+}
+
+static u16 HandleJoypad_SelectWord(void)
+{
+ if (JOY_NEW(B_BUTTON))
+ {
+ sEasyChatScreen->state = 2;
+ return 13;
+ }
+
+ if (JOY_NEW(A_BUTTON))
+ return PlaceSelectedWord();
+
+ if (JOY_NEW(START_BUTTON))
+ return SelectWordCursorAction(4);
+
+ if (JOY_NEW(SELECT_BUTTON))
+ return SelectWordCursorAction(5);
+
+ if (JOY_REPT(DPAD_UP))
+ return SelectWordCursorAction(2);
+
+ if (JOY_REPT(DPAD_DOWN))
+ return SelectWordCursorAction(3);
+
+ if (JOY_REPT(DPAD_LEFT))
+ return SelectWordCursorAction(1);
+
+ if (JOY_REPT(DPAD_RIGHT))
+ return SelectWordCursorAction(0);
+
+ return 0;
+}
+
+static u16 Cancel_HandleYesNoMenu(void)
+{
+ u8 var0;
+
+ switch (Menu_ProcessInputNoWrapClearOnChoose())
+ {
+ case MENU_B_PRESSED: // B Button
+ case 1: // No
+ sEasyChatScreen->state = GetStateBackup();
+ return 7;
+ case 0: // Yes
+ gSpecialVar_Result = 0;
+
+ return 23;
+ default:
+ return 0;
+ }
+}
+
+static u16 Confirm_HandleYesNoMenu(void)
+{
+ switch (Menu_ProcessInputNoWrapClearOnChoose())
+ {
+ case MENU_B_PRESSED: // B Button
+ case 1: // No
+ sEasyChatScreen->state = GetStateBackup();
+ return 7;
+ case 0: // Yes
+ gSpecialVar_Result = HasECMessageChanged();
+ CommitECWords();
+ return 23;
+ default:
+ return 0;
+ }
+}
+
+static u16 DelAll_HandleYesNoMenu(void)
+{
+ switch (Menu_ProcessInputNoWrapClearOnChoose())
+ {
+ case MENU_B_PRESSED: // B Button
+ case 1: // No
+ sEasyChatScreen->state = 1;
+ return 7;
+ case 0: // Yes
+ DeleteAllECFields();
+ sEasyChatScreen->state = 1;
+ return 8;
+ default:
+ return 0;
+ }
+}
+
+static u16 Cancel_CreateYesNoMenu(void)
+{
+ sEasyChatScreen->stateBackup = sEasyChatScreen->state;
+ sEasyChatScreen->state = 4;
+ return 5;
+}
+
+static u16 DelAll_CreateYesNoMenu(void)
+{
+ sEasyChatScreen->stateBackup = sEasyChatScreen->state;
+ sEasyChatScreen->state = 5;
+ return 4;
+}
+
+static u16 Confirm_CreateYesNoMenu(void)
+{
+ sEasyChatScreen->stateBackup = sEasyChatScreen->state;
+ if (IsEcWordBufferUninitialized())
+ {
+ sEasyChatScreen->state = 4;
+ return 5;
+ }
+ else
+ {
+ sEasyChatScreen->state = 6;
+ return 6;
+ }
+}
+
+static u8 GetStateBackup(void)
+{
+ return sEasyChatScreen->stateBackup;
+}
+
+static int OpenSelectedGroup(void)
+{
+ u16 numDisplayedWords;
+
+ if (!sEasyChatScreen->isAlphaMode)
+ {
+ u8 groupId = GetSelectedGroupByIndex(GetSelectedGroupIndex());
+ GetUnlockedECWords(FALSE, groupId);
+ }
+ else
+ {
+ GetUnlockedECWords(TRUE, GetSelectedLetter());
+ }
+
+ numDisplayedWords = GetNumDisplayedWords();
+ if (numDisplayedWords == 0)
+ return 0;
+
+ sEasyChatScreen->selectWordNumRows = (numDisplayedWords - 1) / 2;
+ sEasyChatScreen->selectWordRowsAbove = 0;
+ sEasyChatScreen->selectWordCursorX = 0;
+ sEasyChatScreen->selectWordCursorY = 0;
+ sEasyChatScreen->state = 3;
+ return 11;
+}
+
+static int BackOutFromGroupToFieldSelect(void)
+{
+ sEasyChatScreen->state = 0;
+ return 10;
+}
+
+static int ToggleGroupAlphaMode(void)
+{
+ sEasyChatScreen->selectGroupCursorX = 0;
+ sEasyChatScreen->selectGroupCursorY = 0;
+ sEasyChatScreen->selectGroupRowsAbove = 0;
+ if (!sEasyChatScreen->isAlphaMode)
+ sEasyChatScreen->isAlphaMode = TRUE;
+ else
+ sEasyChatScreen->isAlphaMode = FALSE;
+
+ return 22;
+}
+
+static int DeleteSelectedWord(void)
+{
+ SetEasyChatWordToField(0xFFFF);
+ return 1;
+}
+
+static int PlaceSelectedWord(void)
+{
+ u16 easyChatWord = GetDisplayedWordByIndex(GetSelectWordCursorPos());
+ SetEasyChatWordToField(easyChatWord);
+ sEasyChatScreen->state = 0;
+ return 12;
+}
+
+static void CommitECWords(void)
+{
+ u16 i;
+ for (i = 0; i < sEasyChatScreen->numWords; i++)
+ sEasyChatScreen->words[i] = sEasyChatScreen->ecWordBuffer[i];
+}
+
+static void DeleteAllECFields(void)
+{
+ u16 i;
+ for (i = 0; i < sEasyChatScreen->numWords; i++)
+ sEasyChatScreen->ecWordBuffer[i] = 0xFFFF;
+}
+
+static void SetEasyChatWordToField(u16 easyChatWord)
+{
+ u16 index = GetSelectedFieldIndex();
+ sEasyChatScreen->ecWordBuffer[index] = easyChatWord;
+}
+
+static bool8 HasECMessageChanged(void)
+{
+ u16 i;
+ for (i = 0; i < sEasyChatScreen->numWords; i++)
+ {
+ if (sEasyChatScreen->ecWordBuffer[i] != sEasyChatScreen->words[i])
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static u16 SelectGroupCursorAction(u32 action)
+{
+ if (sEasyChatScreen->selectGroupCursorX != -1)
+ {
+ if (!sEasyChatScreen->isAlphaMode)
+ return UpdateSelectGroupCursorPos_OutsideBlueBox_GroupMode(action);
+ else
+ return UpdateSelectGroupCursorPos_OutsideBlueBox_AlphaMode(action);
+ }
+ else
+ {
+ return UpdateSelectGroupCursorPos_InsideBlueBox(action);
+ }
+}
+
+static int UpdateSelectGroupCursorPos_OutsideBlueBox_GroupMode(u32 arg0)
+{
+ switch (arg0)
+ {
+ case 2:
+ if (sEasyChatScreen->selectGroupCursorY != -sEasyChatScreen->selectGroupRowsAbove)
+ {
+ if (sEasyChatScreen->selectGroupCursorY)
+ {
+ sEasyChatScreen->selectGroupCursorY--;
+ return 14;
+ }
+ else
+ {
+ sEasyChatScreen->selectGroupRowsAbove--;
+ return 16;
+ }
+ }
+ break;
+ case 3:
+ if (sEasyChatScreen->selectGroupCursorY + sEasyChatScreen->selectGroupRowsAbove < sEasyChatScreen->selectGroupNumRows - 1)
+ {
+ int var0;
+ if (sEasyChatScreen->selectGroupCursorY < 3)
+ {
+ sEasyChatScreen->selectGroupCursorY++;
+ var0 = 14;
+ }
+ else
+ {
+ sEasyChatScreen->selectGroupRowsAbove++;
+ var0 = 15;
+ }
+
+ MoveGroupCursorXToMaxCol();
+ return var0;
+ }
+ break;
+ case 1:
+ if (sEasyChatScreen->selectGroupCursorX)
+ sEasyChatScreen->selectGroupCursorX--;
+ else
+ GroupCursorMoveToBlueBox();
+
+ return 14;
+ case 0:
+ if (sEasyChatScreen->selectGroupCursorX < 1)
+ {
+ sEasyChatScreen->selectGroupCursorX++;
+ if (GroupSelectCursorXPosTooFarRight())
+ GroupCursorMoveToBlueBox();
+ }
+ else
+ {
+ GroupCursorMoveToBlueBox();
+ }
+ return 14;
+ }
+
+ return 0;
+}
+
+static int UpdateSelectGroupCursorPos_OutsideBlueBox_AlphaMode(u32 arg0)
+{
+ switch (arg0)
+ {
+ case 2:
+ if (sEasyChatScreen->selectGroupCursorY > 0)
+ sEasyChatScreen->selectGroupCursorY--;
+ else
+ sEasyChatScreen->selectGroupCursorY = 3;
+
+ MoveGroupCursorXToMaxCol();
+ return 14;
+ case 3:
+ if (sEasyChatScreen->selectGroupCursorY < 3)
+ sEasyChatScreen->selectGroupCursorY++;
+ else
+ sEasyChatScreen->selectGroupCursorY = 0;
+
+ MoveGroupCursorXToMaxCol();
+ return 14;
+ case 0:
+ sEasyChatScreen->selectGroupCursorX++;
+ if (GroupSelectCursorXPosTooFarRight())
+ GroupCursorMoveToBlueBox();
+
+ return 14;
+ case 1:
+ sEasyChatScreen->selectGroupCursorX--;
+ if (sEasyChatScreen->selectGroupCursorX < 0)
+ GroupCursorMoveToBlueBox();
+
+ return 14;
+ }
+
+ return 0;
+}
+
+static int UpdateSelectGroupCursorPos_InsideBlueBox(u32 arg0)
+{
+ switch (arg0)
+ {
+ case 2:
+ if (sEasyChatScreen->selectGroupCursorY)
+ sEasyChatScreen->selectGroupCursorY--;
+ else
+ sEasyChatScreen->selectGroupCursorY = 2;
+
+ return 14;
+ case 3:
+ if (sEasyChatScreen->selectGroupCursorY < 2)
+ sEasyChatScreen->selectGroupCursorY++;
+ else
+ sEasyChatScreen->selectGroupCursorY = 0;
+
+ return 14;
+ case 1:
+ sEasyChatScreen->selectGroupCursorY++;
+ GroupCursorWrapAroundLeft();
+ return 14;
+ case 0:
+ sEasyChatScreen->selectGroupCursorX = 0;
+ sEasyChatScreen->selectGroupCursorY++;
+ return 14;
+ }
+
+ return 0;
+}
+
+static void GroupCursorMoveToBlueBox(void)
+{
+ sEasyChatScreen->selectGroupCursorX = 0xFF;
+ if (sEasyChatScreen->selectGroupCursorY)
+ sEasyChatScreen->selectGroupCursorY--;
+}
+
+static void GroupCursorWrapAroundLeft(void)
+{
+ if (!sEasyChatScreen->isAlphaMode)
+ {
+ sEasyChatScreen->selectGroupCursorX = 1;
+ MoveGroupCursorXToMaxCol();
+ }
+ else
+ {
+ sEasyChatScreen->selectGroupCursorX = GetMaxGroupCursorXinAlphaMode(sEasyChatScreen->selectGroupCursorY);
+ }
+}
+
+static u16 SelectWordCursorAction(u32 arg0)
+{
+ u16 result;
+ switch (arg0)
+ {
+ case 2: // up
+ if (sEasyChatScreen->selectWordCursorY + sEasyChatScreen->selectWordRowsAbove > 0)
+ {
+ if (sEasyChatScreen->selectWordCursorY > 0)
+ {
+ sEasyChatScreen->selectWordCursorY--;
+ result = 17;
+ }
+ else
+ {
+ sEasyChatScreen->selectWordRowsAbove--;
+ result = 18;
+ }
+
+ MoveWordCursorXToMaxCol();
+ return result;
+ }
+ break;
+ case 3: // down
+ if (sEasyChatScreen->selectWordCursorY + sEasyChatScreen->selectWordRowsAbove < sEasyChatScreen->selectWordNumRows)
+ {
+ if (sEasyChatScreen->selectWordCursorY < 3)
+ {
+ sEasyChatScreen->selectWordCursorY++;
+ result = 17;
+ }
+ else
+ {
+ sEasyChatScreen->selectWordRowsAbove++;
+ result = 19;
+ }
+
+ MoveWordCursorXToMaxCol();
+ return result;
+ }
+ break;
+ case 1: // left
+ if (sEasyChatScreen->selectWordCursorX > 0)
+ sEasyChatScreen->selectWordCursorX--;
+ else
+ sEasyChatScreen->selectWordCursorX = 1;
+
+ MoveWordCursorXToMaxCol();
+ return 17;
+ case 0: // right
+ if (sEasyChatScreen->selectWordCursorX < 1)
+ {
+ sEasyChatScreen->selectWordCursorX++;
+ if (WordSelectCursorXPosTooFarRight())
+ sEasyChatScreen->selectWordCursorX = 0;
+ }
+ else
+ {
+ sEasyChatScreen->selectWordCursorX = 0;
+ }
+ return 17;
+ case 4: // pg up
+ if (sEasyChatScreen->selectWordRowsAbove)
+ {
+ if (sEasyChatScreen->selectWordRowsAbove > 3)
+ sEasyChatScreen->selectWordRowsAbove -= 4;
+ else
+ sEasyChatScreen->selectWordRowsAbove = 0;
+
+ return 20;
+ }
+ break;
+ case 5: // pg dn
+ if (sEasyChatScreen->selectWordRowsAbove <= sEasyChatScreen->selectWordNumRows - 4)
+ {
+ sEasyChatScreen->selectWordRowsAbove += 4;
+ if (sEasyChatScreen->selectWordRowsAbove > sEasyChatScreen->selectWordNumRows - 3)
+ sEasyChatScreen->selectWordRowsAbove = sEasyChatScreen->selectWordNumRows + -3u;
+
+ MoveWordCursorXToMaxCol();
+ return 21;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static u16 GetSelectedFieldIndex(void)
+{
+ return (sEasyChatScreen->mainCursorRow * sEasyChatScreen->numColumns) + sEasyChatScreen->mainCursorColumn;
+}
+
+static u16 GetSelectedGroupIndex(void)
+{
+ return 2 * (sEasyChatScreen->selectGroupCursorY + sEasyChatScreen->selectGroupRowsAbove) + sEasyChatScreen->selectGroupCursorX;
+}
+
+static const u8 sAlphabetLayout[][7] = {
+ { 1, 2, 3, 4, 5, 6},
+ { 7, 8, 9, 10, 11, 12},
+ {13, 14, 15, 16, 17, 18, 19},
+ {20, 21, 22, 23, 24, 25, 26}
+};
+
+static int GetSelectedLetter(void)
+{
+ int col = sEasyChatScreen->selectGroupCursorX < NELEMS(*sAlphabetLayout) ? sEasyChatScreen->selectGroupCursorX : 0;
+ int row = sEasyChatScreen->selectGroupCursorY < NELEMS(sAlphabetLayout) ? sEasyChatScreen->selectGroupCursorY : 0;
+ return sAlphabetLayout[row][col];
+}
+
+static u16 GetSelectWordCursorPos(void)
+{
+ return 2 * (sEasyChatScreen->selectWordCursorY + sEasyChatScreen->selectWordRowsAbove) + sEasyChatScreen->selectWordCursorX;
+}
+
+static u8 GetMaxGroupCursorXinAlphaMode(u8 arg0)
+{
+ switch (arg0)
+ {
+ case 0:
+ default:
+ return 6;
+ case 1:
+ return 5;
+ }
+}
+
+static void MoveGroupCursorXToMaxCol(void)
+{
+ while (GroupSelectCursorXPosTooFarRight())
+ {
+ if (sEasyChatScreen->selectGroupCursorX)
+ sEasyChatScreen->selectGroupCursorX--;
+ else
+ break;
+ }
+}
+
+static void MoveWordCursorXToMaxCol(void)
+{
+ while (WordSelectCursorXPosTooFarRight())
+ {
+ if (sEasyChatScreen->selectWordCursorX)
+ sEasyChatScreen->selectWordCursorX--;
+ else
+ break;
+ }
+}
+
+static bool8 GroupSelectCursorXPosTooFarRight(void)
+{
+ if (!sEasyChatScreen->isAlphaMode)
+ return GetSelectedGroupIndex() >= GetNumDisplayableGroups() ? TRUE : FALSE;
+ else
+ return sEasyChatScreen->selectGroupCursorX > GetMaxGroupCursorXinAlphaMode(sEasyChatScreen->selectGroupCursorY) ? TRUE : FALSE;
+}
+
+static bool8 WordSelectCursorXPosTooFarRight(void)
+{
+ return GetSelectWordCursorPos() >= GetNumDisplayedWords() ? TRUE : FALSE;
+}
+
+u8 GetEasyChatScreenFrameId(void)
+{
+ return sEasyChatScreenTemplates[sEasyChatScreen->templateId].frameId;
+}
+
+const u8 *GetTitleText(void)
+{
+ return sEasyChatScreenTemplates[sEasyChatScreen->templateId].titleText;
+}
+
+u16 *GetEasyChatWordBuffer(void)
+{
+ return sEasyChatScreen->ecWordBuffer;
+}
+
+u8 GetNumRows(void)
+{
+ return sEasyChatScreen->numRows;
+}
+
+u8 GetNumColumns(void)
+{
+ return sEasyChatScreen->numColumns;
+}
+
+u8 GetMainCursorColumn(void)
+{
+ return sEasyChatScreen->mainCursorColumn;
+}
+
+u8 GetMainCursorRow(void)
+{
+ return sEasyChatScreen->mainCursorRow;
+}
+
+void GetEasyChatInstructionsText(const u8 **str1, const u8 **str2)
+{
+ *str1 = sEasyChatScreenTemplates[sEasyChatScreen->templateId].instructionsText1;
+ *str2 = sEasyChatScreenTemplates[sEasyChatScreen->templateId].instructionsText2;
+}
+
+void GetEasyChatConfirmText(const u8 **str1, const u8 **str2)
+{
+ *str1 = sEasyChatScreenTemplates[sEasyChatScreen->templateId].confirmText1;
+ *str2 = sEasyChatScreenTemplates[sEasyChatScreen->templateId].confirmText2;
+}
+
+void GetEasyChatConfirmCancelText(const u8 **str1, const u8 **str2)
+{
+ switch (sEasyChatScreen->type)
+ {
+ case EASY_CHAT_TYPE_MAIL:
+ *str1 = gUnknown_84189EE;
+ *str2 = NULL;
+ break;
+ default:
+ *str1 = gUnknown_84189E0;
+ *str2 = NULL;
+ break;
+ }
+
+}
+
+void GetEasyChatConfirmDeletionText(const u8 **str1, const u8 **str2)
+{
+ *str1 = gUnknown_8418937;
+ *str2 = gUnknown_8418956;
+}
+
+void GetECSelectGroupCursorCoords(u8 *Xp, u8 *Yp)
+{
+ *Xp = sEasyChatScreen->selectGroupCursorX;
+ *Yp = sEasyChatScreen->selectGroupCursorY;
+}
+
+bool8 IsEasyChatAlphaMode(void)
+{
+ return sEasyChatScreen->isAlphaMode;
+}
+
+u8 GetECSelectGroupRowsAbove(void)
+{
+ return sEasyChatScreen->selectGroupRowsAbove;
+}
+
+void GetECSelectWordCursorCoords(s8 *Xp, s8 *Yp)
+{
+ *Xp = sEasyChatScreen->selectWordCursorX;
+ *Yp = sEasyChatScreen->selectWordCursorY;
+}
+
+u8 GetECSelectWordRowsAbove(void)
+{
+ return sEasyChatScreen->selectWordRowsAbove;
+}
+
+u8 GetECSelectWordNumRows(void)
+{
+ return sEasyChatScreen->selectWordNumRows;
+}
+
+u8 unref_sub_80FFE60(void)
+{
+ return 0;
+}
+
+bool32 ShouldDrawECUpArrow(void)
+{
+ switch (sEasyChatScreen->state)
+ {
+ case 2:
+ if (!sEasyChatScreen->isAlphaMode && sEasyChatScreen->selectGroupRowsAbove != 0)
+ return TRUE;
+ break;
+ case 3:
+ if (sEasyChatScreen->selectWordRowsAbove != 0)
+ return TRUE;
+ break;
+ }
+
+ return FALSE;
+}
+
+bool32 ShouldDrawECDownArrow(void)
+{
+ switch (sEasyChatScreen->state)
+ {
+ case 2:
+ if (!sEasyChatScreen->isAlphaMode && sEasyChatScreen->selectGroupRowsAbove + 4 <= sEasyChatScreen->selectGroupNumRows - 1)
+ return TRUE;
+ break;
+ case 3:
+ if (sEasyChatScreen->selectWordRowsAbove + 4 <= sEasyChatScreen->selectWordNumRows)
+ return TRUE;
+ break;
+ }
+
+ return FALSE;
+}
+
+static bool8 IsPhraseDifferentThanPlayerInput(const u16 *phrase, u8 phraseLength)
+{
+ u8 i;
+
+ for (i = 0; i < phraseLength; i++)
+ {
+ if (phrase[i] != sEasyChatScreen->ecWordBuffer[i])
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static u8 GetEasyChatScreenTemplateId(u8 type)
+{
+ u32 i;
+
+ for (i = 0; i < NELEMS(sEasyChatScreenTemplates); i++)
+ {
+ if (sEasyChatScreenTemplates[i].type == type)
+ return i;
+ }
+
+ return 0;
+}
+
+static bool32 IsEcWordBufferUninitialized(void)
+{
+ int i;
+
+ for (i = 0; i < sEasyChatScreen->numWords; i++)
+ {
+ if (sEasyChatScreen->ecWordBuffer[i] != 0xFFFF)
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/src/easy_chat_3.c b/src/easy_chat_3.c
new file mode 100644
index 000000000..3d9d6c9f7
--- /dev/null
+++ b/src/easy_chat_3.c
@@ -0,0 +1,2298 @@
+#include "global.h"
+#include "gflib.h"
+#include "data_8479668.h"
+#include "decompress.h"
+#include "easy_chat.h"
+#include "graphics.h"
+#include "menu.h"
+#include "new_menu_helpers.h"
+#include "strings.h"
+#include "text_window.h"
+
+struct ECWork
+{
+ u16 state;
+ u16 windowId;
+ u16 id;
+ u8 frameAnimIdx;
+ u8 frameAnimTarget;
+ s8 frameAnimDelta;
+ u8 modeIconState;
+ u8 ecPrintBuffer[0xC1];
+ u8 ecPaddedWordBuffer[0x200];
+ u16 bg2ScrollRow;
+ int tgtBgY;
+ int deltaBgY;
+ struct Sprite * selectDestFieldCursorSprite;
+ struct Sprite * rectCursorSpriteRight;
+ struct Sprite * rectCursorSpriteLeft;
+ struct Sprite * selectWordCursorSprite;
+ struct Sprite * selectGroupHelpSprite;
+ struct Sprite * modeIconsSprite;
+ struct Sprite * upTriangleCursorSprite;
+ struct Sprite * downTriangleCursorSprite;
+ struct Sprite * startPgUpButtonSprite;
+ struct Sprite * selectPgDnButtonSprite;
+ u16 bg1TilemapBuffer[BG_SCREEN_SIZE / 2];
+ u16 bg3TilemapBuffer[BG_SCREEN_SIZE / 2];
+};
+
+struct EasyChatPhraseFrameDimensions
+{
+ u8 left;
+ u8 top;
+ u8 width;
+ u8 height;
+};
+
+static EWRAM_DATA struct ECWork * sEasyChatGraphicsResources = NULL;
+
+static bool8 ECInterfaceCmd_01(void);
+static bool8 ECInterfaceCmd_02(void);
+static bool8 ECInterfaceCmd_03(void);
+static bool8 ECInterfaceCmd_05(void);
+static bool8 ECInterfaceCmd_06(void);
+static bool8 ECInterfaceCmd_04(void);
+static bool8 ECInterfaceCmd_07(void);
+static bool8 ECInterfaceCmd_08(void);
+static bool8 ECInterfaceCmd_09(void);
+static bool8 ECInterfaceCmd_10(void);
+static bool8 ECInterfaceCmd_22(void);
+static bool8 ECInterfaceCmd_14(void);
+static bool8 ECInterfaceCmd_15(void);
+static bool8 ECInterfaceCmd_16(void);
+static bool8 ECInterfaceCmd_11(void);
+static bool8 ECInterfaceCmd_12(void);
+static bool8 ECInterfaceCmd_13(void);
+static bool8 ECInterfaceCmd_17(void);
+static bool8 ECInterfaceCmd_19(void);
+static bool8 ECInterfaceCmd_18(void);
+static bool8 ECInterfaceCmd_21(void);
+static bool8 ECInterfaceCmd_20(void);
+static bool8 InitEasyChatGraphicsWork_Internal(void);
+static void SetGpuRegsForEasyChatInit(void);
+static void LoadEasyChatPals(void);
+static void PrintTitleText(void);
+static void EC_AddTextPrinterParameterized2(u8 windowId, u8 fontId, const u8 *str, u8 left, u8 top, u8 speed, u8 bg, u8 fg, u8 shadow);
+static void PrintECInstructionsText(void);
+static void PrintECInterfaceTextById(u8 a0);
+static void EC_CreateYesNoMenuWithInitialCursorPos(u8 initialCursorPos);
+static void CreatePhraseFrameWindow(void);
+static void PrintECFields(void);
+static void DrawECFrameInTilemapBuffer(u16 *buffer);
+static void PutWin2TilemapAndCopyToVram(void);
+static void PrintECMenuById(u32 a0);
+static void PrintECGroupOrAlphaMenu(void);
+static void PrintECGroupsMenu(void);
+static void PrintEasyChatKeyboardText(void);
+static void PrintECWordsMenu(void);
+static void UpdateWin2PrintWordsScrollDown(void);
+static void UpdateWin2PrintWordsScrollUp(void);
+static void UpdateWin2PrintWordsScrollPageDown(void);
+static void UpdateWin2PrintWordsScrollPageUp(void);
+static void PrintECRowsWin2(u8 row, u8 remrow);
+static void ClearECRowsWin2(u8 row, u8 remrow);
+static void ClearWin2AndCopyToVram(void);
+static void StartWin2FrameAnim(int a0);
+static bool8 AnimateFrameResize(void);
+static void RedrawFrameByIndex(u8 a0);
+static void RedrawFrameByRect(int left, int top, int width, int height);
+static void InitBg2Scroll(void);
+static void ScheduleBg2VerticalScroll(s16 direction, u8 speed);
+static bool8 AnimateBg2VerticalScroll(void);
+static int GetBg2ScrollRow(void);
+static void SetRegWin0Coords(u8 left, u8 top, u8 right, u8 bottom);
+static void LoadSpriteGfx(void);
+static void CreateSelectDestFieldCursorSprite(void);
+static void SpriteCB_BounceCursor(struct Sprite * sprite);
+static void SetSelectDestFieldCursorSpritePosAndResetAnim(u8 x, u8 y);
+static void FreezeSelectDestFieldCursorSprite(void);
+static void UnfreezeSelectDestFieldCursorSprite(void);
+static void CreateRedRectangularCursorSpritePair(void);
+static void DestroyRedRectangularCursor(void);
+static void EC_MoveCursor(void);
+static void MoveCursor_Group(s8 a0, s8 a1);
+static void MoveCursor_Alpha(s8 a0, s8 a1);
+static void CreateSelectWordCursorSprite(void);
+static void SpriteCB_SelectWordCursorSprite(struct Sprite * sprite);
+static void SetSelectWordCursorSpritePos(void);
+static void SetSelectWordCursorSpritePosExplicit(u8 x, u8 y);
+static void DestroySelectWordCursorSprite(void);
+static void CreateSelectGroupHelpSprite(void);
+static bool8 AnimateSeletGroupModeAndHelpSpriteEnter(void);
+static void StartModeIconHidingAnimation(void);
+static bool8 RunModeIconHidingAnimation(void);
+static void ShrinkModeIconsSprite(void);
+static void ShowModeIconsSprite(void);
+static bool8 ModeIconsSpriteAnimIsEnded(void);
+static void CreateVerticalScrollArrowSprites(void);
+static void UpdateVerticalScrollArrowVisibility(void);
+static void HideVerticalScrollArrowSprites(void);
+static void UpdateVerticalScrollArrowSpriteXPos(int a0);
+static void CreateStartSelectButtonsSprites(void);
+static void UpdateStartSelectButtonSpriteVisibility(void);
+static void HideStartSelectButtonSprites(void);
+static void CreateFooterWindow(void);
+
+static const u16 gUnknown_843F3B8[] = INCBIN_U16("graphics/link_rfu/unk_843F3F8.gbapal");
+static const u16 gUnknown_843F3D8[] = INCBIN_U16("graphics/link_rfu/unk_8E9BD28.gbapal");
+static const u16 sRightTriangleCursor_Tiles[] = INCBIN_U16("graphics/link_rfu/unk_843F3F8.4bpp");
+static const u16 sUpTriangleCursor_Tiles[] = INCBIN_U16("graphics/link_rfu/unk_843F418.4bpp");
+static const u16 sStartSelectButtons_Tiles[] = INCBIN_U16("graphics/link_rfu/unk_843F518.4bpp");
+static const u16 gUnknown_843F618[] = INCBIN_U16("graphics/link_rfu/unk_843F638.gbapal");
+static const u32 gUnknown_843F638[] = INCBIN_U32("graphics/link_rfu/unk_843F638.4bpp.lz");
+static const u16 gUnknown_843F76C[] = INCBIN_U16("graphics/link_rfu/unk_843F76C.gbapal");
+static const u16 gUnknown_843F78C[] = INCBIN_U16("graphics/link_rfu/unk_843F78C.gbapal");
+static const u32 gUnknown_843F7AC[] = INCBIN_U32("graphics/link_rfu/unk_843F7AC.4bpp.lz");
+
+static const u16 gUnknown_843F874[] = {
+ RGB( 0, 0, 0),
+ RGB( 0, 0, 0),
+ RGB( 7, 25, 31),
+ RGB(21, 21, 29)
+};
+
+static const u16 gUnknown_843F87C[] = {
+ RGB( 0, 0, 0),
+ RGB(31, 31, 31),
+ RGB(12, 12, 12),
+ RGB(27, 26, 27),
+ RGB( 8, 17, 9)
+};
+
+static const struct EasyChatPhraseFrameDimensions sPhraseFrameDimensions[] = {
+ {
+ .left = 0x03,
+ .top = 0x04,
+ .width = 0x18,
+ .height = 0x04
+ }, {
+ .left = 0x01,
+ .top = 0x04,
+ .width = 0x1b,
+ .height = 0x04
+ }, {
+ .left = 0x03,
+ .top = 0x00,
+ .width = 0x18,
+ .height = 0x0a
+ }, {
+ .left = 0x06,
+ .top = 0x06,
+ .width = 0x12,
+ .height = 0x04
+ }, {
+ .left = 0x10,
+ .top = 0x04,
+ .width = 0x09,
+ .height = 0x02
+ }, {
+ .left = 0x0e,
+ .top = 0x04,
+ .width = 0x12,
+ .height = 0x04
+ }
+};
+
+static const struct BgTemplate sEasyChatBgTemplates[] = {
+ {
+ .bg = 0,
+ .charBaseIndex = 0,
+ .mapBaseIndex = 28,
+ .screenSize = 0,
+ .paletteMode = 0,
+ .priority = 0,
+ .baseTile = 0,
+ }, {
+ .bg = 1,
+ .charBaseIndex = 3,
+ .mapBaseIndex = 29,
+ .screenSize = 0,
+ .paletteMode = 0,
+ .priority = 1,
+ .baseTile = 0,
+ }, {
+ .bg = 2,
+ .charBaseIndex = 0,
+ .mapBaseIndex = 30,
+ .screenSize = 0,
+ .paletteMode = 0,
+ .priority = 2,
+ .baseTile = 0x80,
+ }, {
+ .bg = 3,
+ .charBaseIndex = 2,
+ .mapBaseIndex = 31,
+ .screenSize = 0,
+ .paletteMode = 0,
+ .priority = 3,
+ .baseTile = 0,
+ }
+};
+
+static const struct WindowTemplate sEasyChatWindowTemplates[] = {
+ {
+ .bg = 1,
+ .tilemapLeft = 7,
+ .tilemapTop = 0,
+ .width = 16,
+ .height = 2,
+ .paletteNum = 10,
+ .baseBlock = 0x10,
+ },
+ {
+ .bg = 0,
+ .tilemapLeft = 4,
+ .tilemapTop = 15,
+ .width = 22,
+ .height = 4,
+ .paletteNum = 15,
+ .baseBlock = 0xA,
+ },
+ {
+ .bg = 2,
+ .tilemapLeft = 1,
+ .tilemapTop = 0,
+ .width = 28,
+ .height = 32,
+ .paletteNum = 3,
+ .baseBlock = 0,
+ },
+ DUMMY_WIN_TEMPLATE,
+};
+
+static const struct WindowTemplate sEasyChatYesNoWindowTemplate = {
+ .bg = 0,
+ .tilemapLeft = 22,
+ .tilemapTop = 9,
+ .width = 5,
+ .height = 4,
+ .paletteNum = 15,
+ .baseBlock = 0x062
+};
+
+static const u8 gUnknown_843F8D8[] = _("{UNDERSCORE}");
+static const u8 sText_Clear17[] = _("{CLEAR 17}");
+
+static const u8 *const sEasyChatKeyboardText[] = {
+ gUnknown_847A8D8,
+ gUnknown_847A8FA,
+ gUnknown_847A913,
+ gUnknown_847A934
+};
+
+static const struct SpriteSheet sEasyChatSpriteSheets[] = {
+ {sRightTriangleCursor_Tiles, 0x0020, 0},
+ {sUpTriangleCursor_Tiles, 0x0100, 2},
+ {sStartSelectButtons_Tiles, 0x0100, 3},
+ {}
+};
+
+static const struct SpritePalette sEasyChatSpritePalettes[] = {
+ {gUnknown_843F3B8, 0},
+ {gUnknown_843F3D8, 1},
+ {gUnknown_8E99F24, 2},
+ {gUnknown_843F618, 3},
+ {}
+};
+
+static const struct CompressedSpriteSheet sEasyChatCompressedSpriteSheets[] = {
+ {gUnknown_843F638, 0x0800, 5},
+ {gEasyChatRedRectangularCursor_Tiles, 0x1000, 1},
+ {gEasyChatSelectGroupHelp_Tiles, 0x0800, 6},
+ {gEasyChatModeIcons_Tiles, 0x1000, 4}
+};
+
+static const u8 sECDisplay_AlphaModeXCoords[] = {
+ 0,
+ 12,
+ 24,
+ 56,
+ 68,
+ 80,
+ 92
+};
+
+static const struct OamData sOamData_RightTriangleCursor = {
+ .y = 0,
+ .affineMode = ST_OAM_AFFINE_OFF,
+ .objMode = ST_OAM_OBJ_NORMAL,
+ .bpp = ST_OAM_4BPP,
+ .mosaic = FALSE,
+ .shape = SPRITE_SHAPE(8x8),
+ .x = 0,
+ .matrixNum = 0,
+ .size = SPRITE_SIZE(8x8),
+ .tileNum = 0x000,
+ .priority = 3,
+ .paletteNum = 0
+};
+
+static const struct SpriteTemplate sSpriteTemplate_RightTriangleCursor = {
+ .tileTag = 0,
+ .paletteTag = 0,
+ .oam = &sOamData_RightTriangleCursor,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCB_BounceCursor
+};
+
+static const struct OamData sOamData_RedRectangularCursor = {
+ .y = 0,
+ .affineMode = ST_OAM_AFFINE_OFF,
+ .objMode = ST_OAM_OBJ_NORMAL,
+ .bpp = ST_OAM_4BPP,
+ .mosaic = FALSE,
+ .shape = SPRITE_SHAPE(64x32),
+ .x = 0,
+ .matrixNum = 0,
+ .size = SPRITE_SIZE(64x32),
+ .tileNum = 0x000,
+ .priority = 1,
+ .paletteNum = 0
+};
+
+static const union AnimCmd sAnimCmd_RectCursor_Wide[] = {
+ ANIMCMD_FRAME(0x00, 0),
+ ANIMCMD_END
+};
+
+static const union AnimCmd sAnimCmd_RectCursor_Norm[] = {
+ ANIMCMD_FRAME(0x20, 0),
+ ANIMCMD_END
+};
+
+static const union AnimCmd sAnimCmd_RectCursor_NormTaller[] = {
+ ANIMCMD_FRAME(0x40, 0),
+ ANIMCMD_END
+};
+
+static const union AnimCmd sAnimCmd_RectCursor_Narrow[] = {
+ ANIMCMD_FRAME(0x60, 0),
+ ANIMCMD_END
+};
+
+static const union AnimCmd *const sAnimTable_RedRectangularCursor[] = {
+ sAnimCmd_RectCursor_Wide,
+ sAnimCmd_RectCursor_Norm,
+ sAnimCmd_RectCursor_NormTaller,
+ sAnimCmd_RectCursor_Narrow
+};
+
+static const struct SpriteTemplate sSpriteTemplate_RedRectangularCursor = {
+ .tileTag = 1,
+ .paletteTag = 1,
+ .oam = &sOamData_RedRectangularCursor,
+ .anims = sAnimTable_RedRectangularCursor,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCB_BounceCursor
+};
+
+static const struct OamData sOamData_EasyChatModeIcons = {
+ .y = 0,
+ .affineMode = ST_OAM_AFFINE_OFF,
+ .objMode = ST_OAM_OBJ_NORMAL,
+ .bpp = ST_OAM_4BPP,
+ .mosaic = FALSE,
+ .shape = SPRITE_SHAPE(64x32),
+ .x = 0,
+ .matrixNum = 0,
+ .size = SPRITE_SIZE(64x32),
+ .tileNum = 0x000,
+ .priority = 1,
+ .paletteNum = 0
+};
+
+static const union AnimCmd sAnim_EasyChatModeIcon_Hidden[] = {
+ ANIMCMD_FRAME(0x60, 0),
+ ANIMCMD_END
+};
+
+static const union AnimCmd sAnim_EasyChatModeIcon_ToGroupMode[] = {
+ ANIMCMD_FRAME(0x40, 4),
+ ANIMCMD_FRAME(0x20, 4),
+ ANIMCMD_END
+};
+
+static const union AnimCmd sAnim_EasyChatModeIcon_ToAlphaMode[] = {
+ ANIMCMD_FRAME(0x40, 4),
+ ANIMCMD_FRAME(0x00, 4),
+ ANIMCMD_END
+};
+
+static const union AnimCmd sAnim_EasyChatModeIcon_ToHidden[] = {
+ ANIMCMD_FRAME(0x40, 4),
+ ANIMCMD_FRAME(0x60, 0),
+ ANIMCMD_END
+};
+
+static const union AnimCmd sAnim_EasyChatModeIcon_HoldSmall[] = {
+ ANIMCMD_FRAME(0x40, 4),
+ ANIMCMD_END
+};
+
+static const union AnimCmd *const sAnimTable_EasyChatModeIcons[] = {
+ sAnim_EasyChatModeIcon_Hidden,
+ sAnim_EasyChatModeIcon_ToGroupMode,
+ sAnim_EasyChatModeIcon_ToAlphaMode,
+ sAnim_EasyChatModeIcon_ToHidden,
+ sAnim_EasyChatModeIcon_HoldSmall
+};
+
+static const struct SpriteTemplate sSpriteTemplate_EasyChatModeIcons = {
+ .tileTag = 4,
+ .paletteTag = 2,
+ .oam = &sOamData_EasyChatModeIcons,
+ .anims = sAnimTable_EasyChatModeIcons,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCallbackDummy
+};
+
+static const struct OamData sOamData_SelectGroupHelp = {
+ .y = 0,
+ .affineMode = ST_OAM_AFFINE_OFF,
+ .objMode = ST_OAM_OBJ_NORMAL,
+ .mosaic = FALSE,
+ .bpp = ST_OAM_4BPP,
+ .shape = SPRITE_SHAPE(64x64),
+ .x = 0,
+ .matrixNum = 0,
+ .size = SPRITE_SIZE(64x64),
+ .tileNum = 0x000,
+ .priority = 3,
+ .paletteNum = 0
+};
+
+static const struct SpriteTemplate sSpriteTemplate_SelectGroupHelp = {
+ .tileTag = 6,
+ .paletteTag = 2,
+ .oam = &sOamData_SelectGroupHelp,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCallbackDummy
+};
+
+static const struct OamData gUnknown_843FA58 = {
+ .y = 0,
+ .affineMode = ST_OAM_AFFINE_OFF,
+ .objMode = ST_OAM_OBJ_NORMAL,
+ .mosaic = FALSE,
+ .bpp = ST_OAM_4BPP,
+ .shape = SPRITE_SHAPE(32x8),
+ .x = 0,
+ .matrixNum = 0,
+ .size = SPRITE_SIZE(32x8),
+ .tileNum = 0x000,
+ .priority = 1,
+ .paletteNum = 0
+};
+
+static const struct OamData sOamData_UpTriangleCursor = {
+ .y = 0,
+ .affineMode = ST_OAM_AFFINE_OFF,
+ .objMode = ST_OAM_OBJ_NORMAL,
+ .mosaic = FALSE,
+ .bpp = ST_OAM_4BPP,
+ .shape = SPRITE_SHAPE(16x16),
+ .x = 0,
+ .matrixNum = 0,
+ .size = SPRITE_SIZE(16x16),
+ .tileNum = 0x000,
+ .priority = 1,
+ .paletteNum = 0
+};
+
+static const union AnimCmd gUnknown_843FA68[] = {
+ ANIMCMD_FRAME(0, 0),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd gUnknown_843FA70[] = {
+ ANIMCMD_FRAME(4, 0),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd *const gUnknown_843FA78[] = {
+ gUnknown_843FA68,
+ gUnknown_843FA70,
+};
+
+static const struct SpriteTemplate sSpriteTemplate_StartSelectButtons = {
+ .tileTag = 3,
+ .paletteTag = 2,
+ .oam = &gUnknown_843FA58,
+ .anims = gUnknown_843FA78,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCallbackDummy,
+};
+
+static const struct SpriteTemplate sSpriteTemplate_UpTriangleCursor = {
+ .tileTag = 2,
+ .paletteTag = 2,
+ .oam = &sOamData_UpTriangleCursor,
+ .anims = gUnknown_843FA78,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCallbackDummy,
+};
+
+bool8 InitEasyChatGraphicsWork(void)
+{
+ if (!InitEasyChatGraphicsWork_Internal())
+ return FALSE;
+ else
+ return TRUE;
+}
+
+bool8 LoadEasyChatGraphics(void)
+{
+ switch (sEasyChatGraphicsResources->state)
+ {
+ case 0:
+ ResetBgsAndClearDma3BusyFlags(0);
+ InitBgsFromTemplates(0, sEasyChatBgTemplates, NELEMS(sEasyChatBgTemplates));
+ SetBgTilemapBuffer(3, sEasyChatGraphicsResources->bg3TilemapBuffer);
+ SetBgTilemapBuffer(1, sEasyChatGraphicsResources->bg1TilemapBuffer);
+ InitWindows(sEasyChatWindowTemplates);
+ DeactivateAllTextPrinters();
+ LoadEasyChatPals();
+ SetGpuRegsForEasyChatInit();
+ CpuFastFill(0, (void *)VRAM + 0x1000000, 0x400);
+ break;
+ case 1:
+ DecompressAndLoadBgGfxUsingHeap(3, gEasyChatWindow_Gfx, 0, 0, 0);
+ CopyToBgTilemapBuffer(3, gEasyChatWindow_Tilemap, 0, 0);
+ CreatePhraseFrameWindow();
+ CreateFooterWindow();
+ CopyBgTilemapBufferToVram(3);
+ break;
+ case 2:
+ DrawECFrameInTilemapBuffer(sEasyChatGraphicsResources->bg1TilemapBuffer);
+ DecompressAndLoadBgGfxUsingHeap(1, gUnknown_843F7AC, 0, 0, 0);
+ CopyBgTilemapBufferToVram(1);
+ break;
+ case 3:
+ PrintTitleText();
+ PrintECInstructionsText();
+ PrintECFields();
+ PutWin2TilemapAndCopyToVram();
+ break;
+ case 4:
+ LoadSpriteGfx();
+ CreateSelectDestFieldCursorSprite();
+ break;
+ case 5:
+ if (IsDma3ManagerBusyWithBgCopy())
+ {
+ return TRUE;
+ }
+ else
+ {
+ SetRegWin0Coords(0, 0, 0, 0);
+ SetGpuReg(REG_OFFSET_WININ, WIN_RANGE(0, 63));
+ SetGpuReg(REG_OFFSET_WINOUT, WIN_RANGE(0, 59));
+ ShowBg(3);
+ ShowBg(1);
+ ShowBg(2);
+ ShowBg(0);
+ CreateVerticalScrollArrowSprites();
+ CreateStartSelectButtonsSprites();
+ }
+ break;
+ default:
+ return FALSE;
+ }
+
+ sEasyChatGraphicsResources->state++;
+ return TRUE;
+}
+
+void DestroyEasyChatGraphicsResources(void)
+{
+ if (sEasyChatGraphicsResources)
+ Free(sEasyChatGraphicsResources);
+}
+
+void EasyChatInterfaceCommand_Setup(u16 id)
+{
+ sEasyChatGraphicsResources->id = id;
+ sEasyChatGraphicsResources->state = 0;
+ EasyChatInterfaceCommand_Run();
+}
+
+bool8 EasyChatInterfaceCommand_Run(void)
+{
+ switch (sEasyChatGraphicsResources->id)
+ {
+ case 0: return FALSE;
+ case 1: return ECInterfaceCmd_01();
+ case 2: return ECInterfaceCmd_02();
+ case 3: return ECInterfaceCmd_03();
+ case 4: return ECInterfaceCmd_04();
+ case 5: return ECInterfaceCmd_05();
+ case 6: return ECInterfaceCmd_06();
+ case 7: return ECInterfaceCmd_07();
+ case 8: return ECInterfaceCmd_08();
+ case 9: return ECInterfaceCmd_09();
+ case 10: return ECInterfaceCmd_10();
+ case 11: return ECInterfaceCmd_11();
+ case 12: return ECInterfaceCmd_12();
+ case 13: return ECInterfaceCmd_13();
+ case 14: return ECInterfaceCmd_14();
+ case 15: return ECInterfaceCmd_15();
+ case 16: return ECInterfaceCmd_16();
+ case 17: return ECInterfaceCmd_17();
+ case 18: return ECInterfaceCmd_18();
+ case 19: return ECInterfaceCmd_19();
+ case 20: return ECInterfaceCmd_20();
+ case 21: return ECInterfaceCmd_21();
+ case 22: return ECInterfaceCmd_22();
+ default: return FALSE;
+ }
+}
+
+static bool8 ECInterfaceCmd_01(void)
+{
+ switch (sEasyChatGraphicsResources->state)
+ {
+ case 0:
+ PrintECFields();
+ sEasyChatGraphicsResources->state++;
+ break;
+ case 1:
+ return IsDma3ManagerBusyWithBgCopy();
+ }
+
+ return TRUE;
+}
+
+static bool8 ECInterfaceCmd_02(void)
+{
+ u8 i;
+ u16 *ecWordBuffer;
+ u16 *ecWord;
+ u8 frameId;
+ u8 cursorColumn, cursorRow, numColumns;
+ s16 var1;
+ int stringWidth;
+ int trueStringWidth;
+ int var2;
+ u8 str[64];
+
+ ecWordBuffer = GetEasyChatWordBuffer();
+ frameId = GetEasyChatScreenFrameId();
+ cursorColumn = GetMainCursorColumn();
+ cursorRow = GetMainCursorRow();
+ numColumns = GetNumColumns();
+ ecWord = &ecWordBuffer[cursorRow * numColumns];
+ var1 = 8 * sPhraseFrameDimensions[frameId].left + 13;
+ for (i = 0; i < cursorColumn; i++)
+ {
+ if (*ecWord == 0xFFFF)
+ {
+ stringWidth = GetStringWidth(1, gUnknown_843F8D8, 0) * 7;
+ }
+ else
+ {
+ CopyEasyChatWord(str, *ecWord);
+ stringWidth = GetStringWidth(1, str, 0);
+ }
+
+ trueStringWidth = stringWidth + 17;
+ var1 += trueStringWidth;
+ ecWord++;
+ }
+
+ var2 = 8 * (sPhraseFrameDimensions[frameId].top + cursorRow * 2 + 1) + 1;
+ SetSelectDestFieldCursorSpritePosAndResetAnim(var1, var2);
+ return FALSE;
+}
+
+static bool8 ECInterfaceCmd_03(void)
+{
+ u8 xOffset;
+ switch (GetMainCursorColumn())
+ {
+ case 0:
+ xOffset = 28;
+ break;
+ case 1:
+ xOffset = 115;
+ break;
+ case 2:
+ xOffset = 191;
+ break;
+ default:
+ return FALSE;
+ }
+ SetSelectDestFieldCursorSpritePosAndResetAnim(xOffset, 97);
+ return FALSE;
+}
+
+static bool8 ECInterfaceCmd_05(void)
+{
+ switch (sEasyChatGraphicsResources->state)
+ {
+ case 0:
+ FreezeSelectDestFieldCursorSprite();
+ PrintECInterfaceTextById(2);
+ EC_CreateYesNoMenuWithInitialCursorPos(1);
+ sEasyChatGraphicsResources->state++;
+ break;
+ case 1:
+ return IsDma3ManagerBusyWithBgCopy();
+ }
+
+ return TRUE;
+}
+
+static bool8 ECInterfaceCmd_06(void)
+{
+ switch (sEasyChatGraphicsResources->state)
+ {
+ case 0:
+ FreezeSelectDestFieldCursorSprite();
+ PrintECInterfaceTextById(3);
+ EC_CreateYesNoMenuWithInitialCursorPos(0);
+ sEasyChatGraphicsResources->state++;
+ break;
+ case 1:
+ return IsDma3ManagerBusyWithBgCopy();
+ }
+
+ return TRUE;
+}
+
+static bool8 ECInterfaceCmd_04(void)
+{
+ switch (sEasyChatGraphicsResources->state)
+ {
+ case 0:
+ FreezeSelectDestFieldCursorSprite();
+ PrintECInterfaceTextById(1);
+ EC_CreateYesNoMenuWithInitialCursorPos(1);
+ sEasyChatGraphicsResources->state++;
+ break;
+ case 1:
+ return IsDma3ManagerBusyWithBgCopy();
+ }
+
+ return TRUE;
+}
+
+static bool8 ECInterfaceCmd_07(void)
+{
+ switch (sEasyChatGraphicsResources->state)
+ {
+ case 0:
+ UnfreezeSelectDestFieldCursorSprite();
+ PrintECInterfaceTextById(0);
+ ShowBg(0);
+ sEasyChatGraphicsResources->state++;
+ break;
+ case 1:
+ return IsDma3ManagerBusyWithBgCopy();
+ }
+
+ return TRUE;
+}
+
+static bool8 ECInterfaceCmd_08(void)
+{
+ switch (sEasyChatGraphicsResources->state)
+ {
+ case 0:
+ UnfreezeSelectDestFieldCursorSprite();
+ PrintECInterfaceTextById(0);
+ PrintECFields();
+ sEasyChatGraphicsResources->state++;
+ // Fall through
+ case 1:
+ return IsDma3ManagerBusyWithBgCopy();
+ }
+
+ return TRUE;
+}
+
+static bool8 ECInterfaceCmd_09(void)
+{
+ switch (sEasyChatGraphicsResources->state)
+ {
+ case 0:
+ FreezeSelectDestFieldCursorSprite();
+ HideBg(0);
+ SetRegWin0Coords(0, 0, 0, 0);
+ PrintECGroupOrAlphaMenu();
+ sEasyChatGraphicsResources->state++;
+ break;
+ case 1:
+ if (!IsDma3ManagerBusyWithBgCopy())
+ {
+ StartWin2FrameAnim(0);
+ sEasyChatGraphicsResources->state++;
+ }
+ break;
+ case 2:
+ if (!IsDma3ManagerBusyWithBgCopy() && !AnimateFrameResize())
+ sEasyChatGraphicsResources->state++;
+ break;
+ case 3:
+ if (!IsDma3ManagerBusyWithBgCopy())
+ {
+ CreateSelectGroupHelpSprite();
+ sEasyChatGraphicsResources->state++;
+ }
+ break;
+ case 4:
+ if (!AnimateSeletGroupModeAndHelpSpriteEnter())
+ {
+ CreateRedRectangularCursorSpritePair();
+ UpdateVerticalScrollArrowSpriteXPos(0);
+ UpdateVerticalScrollArrowVisibility();
+ sEasyChatGraphicsResources->state++;
+ return FALSE;
+ }
+ break;
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool8 ECInterfaceCmd_10(void)
+{
+ switch (sEasyChatGraphicsResources->state)
+ {
+ case 0:
+ DestroyRedRectangularCursor();
+ StartModeIconHidingAnimation();
+ HideVerticalScrollArrowSprites();
+ sEasyChatGraphicsResources->state++;
+ break;
+ case 1:
+ if (RunModeIconHidingAnimation() == TRUE)
+ break;
+
+ StartWin2FrameAnim(1);
+ sEasyChatGraphicsResources->state++;
+ // Fall through
+ case 2:
+ if (!AnimateFrameResize())
+ sEasyChatGraphicsResources->state++;
+ break;
+ case 3:
+ if (!IsDma3ManagerBusyWithBgCopy())
+ {
+ UnfreezeSelectDestFieldCursorSprite();
+ ShowBg(0);
+ sEasyChatGraphicsResources->state++;
+ }
+ break;
+ case 4:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool8 ECInterfaceCmd_22(void)
+{
+ switch (sEasyChatGraphicsResources->state)
+ {
+ case 0:
+ DestroyRedRectangularCursor();
+ HideVerticalScrollArrowSprites();
+ ShrinkModeIconsSprite();
+ StartWin2FrameAnim(5);
+ sEasyChatGraphicsResources->state++;
+ break;
+ case 1:
+ if (!AnimateFrameResize() && !ModeIconsSpriteAnimIsEnded())
+ {
+ PrintECGroupOrAlphaMenu();
+ sEasyChatGraphicsResources->state++;
+ }
+ break;
+ case 2:
+ if (!IsDma3ManagerBusyWithBgCopy())
+ {
+ StartWin2FrameAnim(6);
+ ShowModeIconsSprite();
+ sEasyChatGraphicsResources->state++;
+ }
+ break;
+ case 3:
+ if (!AnimateFrameResize() && !ModeIconsSpriteAnimIsEnded())
+ {
+ UpdateVerticalScrollArrowVisibility();
+ CreateRedRectangularCursorSpritePair();
+ sEasyChatGraphicsResources->state++;
+ return FALSE;
+ }
+ break;
+ case 4:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool8 ECInterfaceCmd_14(void)
+{
+ EC_MoveCursor();
+ return FALSE;
+}
+
+static bool8 ECInterfaceCmd_15(void)
+{
+ switch (sEasyChatGraphicsResources->state)
+ {
+ case 0:
+ ScheduleBg2VerticalScroll(1, 2);
+ sEasyChatGraphicsResources->state++;
+ // Fall through
+ case 1:
+ if (!AnimateBg2VerticalScroll())
+ {
+ EC_MoveCursor();
+ UpdateVerticalScrollArrowVisibility();
+ return FALSE;
+ }
+ break;
+ }
+
+ return TRUE;
+}
+
+static bool8 ECInterfaceCmd_16(void)
+{
+ switch (sEasyChatGraphicsResources->state)
+ {
+ case 0:
+ ScheduleBg2VerticalScroll(-1, 2);
+ sEasyChatGraphicsResources->state++;
+ // Fall through
+ case 1:
+ if (!AnimateBg2VerticalScroll())
+ {
+ UpdateVerticalScrollArrowVisibility();
+ sEasyChatGraphicsResources->state++;
+ return FALSE;
+ }
+ break;
+ case 2:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool8 ECInterfaceCmd_11(void)
+{
+ switch (sEasyChatGraphicsResources->state)
+ {
+ case 0:
+ DestroyRedRectangularCursor();
+ StartModeIconHidingAnimation();
+ HideVerticalScrollArrowSprites();
+ sEasyChatGraphicsResources->state++;
+ break;
+ case 1:
+ if (!RunModeIconHidingAnimation())
+ {
+ ClearWin2AndCopyToVram();
+ sEasyChatGraphicsResources->state++;
+ }
+ break;
+ case 2:
+ if (!IsDma3ManagerBusyWithBgCopy())
+ {
+ StartWin2FrameAnim(2);
+ sEasyChatGraphicsResources->state++;
+ }
+ break;
+ case 3:
+ if (!AnimateFrameResize())
+ {
+ PrintECMenuById(2);
+ sEasyChatGraphicsResources->state++;
+ }
+ break;
+ case 4:
+ if (!IsDma3ManagerBusyWithBgCopy())
+ {
+ CreateSelectWordCursorSprite();
+ UpdateVerticalScrollArrowSpriteXPos(1);
+ UpdateVerticalScrollArrowVisibility();
+ UpdateStartSelectButtonSpriteVisibility();
+ sEasyChatGraphicsResources->state++;
+ return FALSE;
+ }
+ break;
+ case 5:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool8 ECInterfaceCmd_12(void)
+{
+ switch (sEasyChatGraphicsResources->state)
+ {
+ case 0:
+ PrintECFields();
+ sEasyChatGraphicsResources->state++;
+ break;
+ case 1:
+ DestroySelectWordCursorSprite();
+ HideVerticalScrollArrowSprites();
+ HideStartSelectButtonSprites();
+ ClearWin2AndCopyToVram();
+ sEasyChatGraphicsResources->state++;
+ break;
+ case 2:
+ if (!IsDma3ManagerBusyWithBgCopy())
+ {
+ StartWin2FrameAnim(3);
+ sEasyChatGraphicsResources->state++;
+ }
+ break;
+ case 3:
+ if (!AnimateFrameResize())
+ {
+ ShowBg(0);
+ sEasyChatGraphicsResources->state++;
+ }
+ break;
+ case 4:
+ if (!IsDma3ManagerBusyWithBgCopy())
+ {
+ UnfreezeSelectDestFieldCursorSprite();
+ sEasyChatGraphicsResources->state++;
+ return FALSE;
+ }
+ break;
+ case 5:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool8 ECInterfaceCmd_13(void)
+{
+ switch (sEasyChatGraphicsResources->state)
+ {
+ case 0:
+ DestroySelectWordCursorSprite();
+ HideVerticalScrollArrowSprites();
+ HideStartSelectButtonSprites();
+ ClearWin2AndCopyToVram();
+ sEasyChatGraphicsResources->state++;
+ break;
+ case 1:
+ if (!IsDma3ManagerBusyWithBgCopy())
+ {
+ StartWin2FrameAnim(4);
+ sEasyChatGraphicsResources->state++;
+ }
+ break;
+ case 2:
+ if (!AnimateFrameResize())
+ {
+ PrintECGroupOrAlphaMenu();
+ sEasyChatGraphicsResources->state++;
+ }
+ break;
+ case 3:
+ if (!IsDma3ManagerBusyWithBgCopy())
+ {
+ CreateSelectGroupHelpSprite();
+ sEasyChatGraphicsResources->state++;
+ }
+ break;
+ case 4:
+ if (!AnimateSeletGroupModeAndHelpSpriteEnter())
+ {
+ CreateRedRectangularCursorSpritePair();
+ UpdateVerticalScrollArrowSpriteXPos(0);
+ UpdateVerticalScrollArrowVisibility();
+ sEasyChatGraphicsResources->state++;
+ return FALSE;
+ }
+ break;
+ }
+
+ return TRUE;
+}
+
+static bool8 ECInterfaceCmd_17(void)
+{
+ SetSelectWordCursorSpritePos();
+ return FALSE;
+}
+
+static bool8 ECInterfaceCmd_19(void)
+{
+ switch (sEasyChatGraphicsResources->state)
+ {
+ case 0:
+ UpdateWin2PrintWordsScrollDown();
+ sEasyChatGraphicsResources->state++;
+ break;
+ case 1:
+ if (!IsDma3ManagerBusyWithBgCopy())
+ {
+ ScheduleBg2VerticalScroll(1, 2);
+ sEasyChatGraphicsResources->state++;
+ }
+ break;
+ case 2:
+ if (!AnimateBg2VerticalScroll())
+ {
+ SetSelectWordCursorSpritePos();
+ UpdateVerticalScrollArrowVisibility();
+ UpdateStartSelectButtonSpriteVisibility();
+ sEasyChatGraphicsResources->state++;
+ return FALSE;
+ }
+ break;
+ case 3:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool8 ECInterfaceCmd_18(void)
+{
+ switch (sEasyChatGraphicsResources->state)
+ {
+ case 0:
+ UpdateWin2PrintWordsScrollUp();
+ sEasyChatGraphicsResources->state++;
+ break;
+ case 1:
+ if (!IsDma3ManagerBusyWithBgCopy())
+ {
+ ScheduleBg2VerticalScroll(-1, 2);
+ sEasyChatGraphicsResources->state++;
+ }
+ break;
+ case 2:
+ if (!AnimateBg2VerticalScroll())
+ {
+ UpdateVerticalScrollArrowVisibility();
+ UpdateStartSelectButtonSpriteVisibility();
+ sEasyChatGraphicsResources->state++;
+ return FALSE;
+ }
+ break;
+ case 3:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool8 ECInterfaceCmd_21(void)
+{
+ switch (sEasyChatGraphicsResources->state)
+ {
+ case 0:
+ UpdateWin2PrintWordsScrollPageDown();
+ sEasyChatGraphicsResources->state++;
+ break;
+ case 1:
+ if (!IsDma3ManagerBusyWithBgCopy())
+ {
+ s16 direction = GetECSelectWordRowsAbove() - GetBg2ScrollRow();
+ ScheduleBg2VerticalScroll(direction, 4);
+ sEasyChatGraphicsResources->state++;
+ }
+ break;
+ case 2:
+ if (!AnimateBg2VerticalScroll())
+ {
+ SetSelectWordCursorSpritePos();
+ UpdateVerticalScrollArrowVisibility();
+ UpdateStartSelectButtonSpriteVisibility();
+ sEasyChatGraphicsResources->state++;
+ return FALSE;
+ }
+ break;
+ case 3:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool8 ECInterfaceCmd_20(void)
+{
+ switch (sEasyChatGraphicsResources->state)
+ {
+ case 0:
+ UpdateWin2PrintWordsScrollPageUp();
+ sEasyChatGraphicsResources->state++;
+ break;
+ case 1:
+ if (!IsDma3ManagerBusyWithBgCopy())
+ {
+ s16 direction = GetECSelectWordRowsAbove() - GetBg2ScrollRow();
+ ScheduleBg2VerticalScroll(direction, 4);
+ sEasyChatGraphicsResources->state++;
+ }
+ break;
+ case 2:
+ if (!AnimateBg2VerticalScroll())
+ {
+ UpdateVerticalScrollArrowVisibility();
+ UpdateStartSelectButtonSpriteVisibility();
+ sEasyChatGraphicsResources->state++;
+ return FALSE;
+ }
+ break;
+ case 3:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool8 InitEasyChatGraphicsWork_Internal(void)
+{
+ sEasyChatGraphicsResources = Alloc(sizeof(*sEasyChatGraphicsResources));
+ if (sEasyChatGraphicsResources == NULL)
+ return FALSE;
+
+ sEasyChatGraphicsResources->state = 0;
+ sEasyChatGraphicsResources->selectDestFieldCursorSprite = NULL;
+ sEasyChatGraphicsResources->rectCursorSpriteRight = NULL;
+ sEasyChatGraphicsResources->rectCursorSpriteLeft = NULL;
+ sEasyChatGraphicsResources->selectWordCursorSprite = NULL;
+ sEasyChatGraphicsResources->selectGroupHelpSprite = NULL;
+ sEasyChatGraphicsResources->modeIconsSprite = NULL;
+ sEasyChatGraphicsResources->upTriangleCursorSprite = NULL;
+ sEasyChatGraphicsResources->downTriangleCursorSprite = NULL;
+ sEasyChatGraphicsResources->startPgUpButtonSprite = NULL;
+ sEasyChatGraphicsResources->selectPgDnButtonSprite = NULL;
+ return TRUE;
+}
+
+static void SetGpuRegsForEasyChatInit(void)
+{
+ ChangeBgX(3, 0, 0);
+ ChangeBgY(3, 0, 0);
+ ChangeBgX(1, 0, 0);
+ ChangeBgY(1, 0, 0);
+ ChangeBgX(2, 0, 0);
+ ChangeBgY(2, 0, 0);
+ ChangeBgX(0, 0, 0);
+ ChangeBgY(0, 0, 0);
+ SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_0 | DISPCNT_OBJ_1D_MAP | DISPCNT_OBJ_ON | DISPCNT_WIN0_ON);
+}
+
+static void LoadEasyChatPals(void)
+{
+ ResetPaletteFade();
+ LoadPalette(gEasyChatMode_Pal, 0, 32);
+ LoadPalette(gUnknown_843F76C, 1 * 16, 32);
+ LoadPalette(gUnknown_843F78C, 4 * 16, 32);
+ LoadPalette(gUnknown_843F874, 10 * 16, 8);
+ LoadPalette(gUnknown_843F87C, 11 * 16, 10);
+ LoadPalette(gUnknown_843F87C, 15 * 16, 10);
+ LoadPalette(gUnknown_843F87C, 3 * 16, 10);
+}
+
+static void PrintTitleText(void)
+{
+ int xOffset;
+ const u8 *titleText = GetTitleText();
+ if (titleText == NULL)
+ return;
+
+ xOffset = (128 - GetStringWidth(1, titleText, 0)) / 2u;
+ FillWindowPixelBuffer(0, PIXEL_FILL(0));
+ EC_AddTextPrinterParameterized2(0, 1, titleText, xOffset, 0, TEXT_SPEED_FF, TEXT_COLOR_TRANSPARENT, TEXT_COLOR_DARK_GREY, TEXT_COLOR_LIGHT_GREY);
+ PutWindowTilemap(0);
+ CopyWindowToVram(0, 3);
+}
+
+static void EC_AddTextPrinterParameterized(u8 windowId, u8 fontId, const u8 *str, u8 x, u8 y, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16))
+{
+ if (fontId == 1) y += 2;
+ AddTextPrinterParameterized(windowId, fontId, str, x, y, speed, callback);
+}
+
+static void EC_AddTextPrinterParameterized2(u8 windowId, u8 fontId, const u8 *str, u8 x, u8 y, u8 speed, u8 bg, u8 fg, u8 shadow)
+{
+ u8 color[3];
+ if (fontId == 1) y += 2;
+ color[0] = bg;
+ color[1] = fg;
+ color[2] = shadow;
+ AddTextPrinterParameterized3(windowId, fontId, x, y, color, speed, str);
+}
+
+static void PrintECInstructionsText(void)
+{
+ FillBgTilemapBufferRect(0, 0, 0, 0, 32, 20, 17);
+ TextWindow_SetUserSelectedFrame(1, 1, 0xE0);
+ DrawTextBorderOuter(1, 1, 14);
+ PrintECInterfaceTextById(0);
+ PutWindowTilemap(1);
+ CopyBgTilemapBufferToVram(0);
+}
+
+static void PrintECInterfaceTextById(u8 direction)
+{
+ const u8 *text2 = NULL;
+ const u8 *text1 = NULL;
+ switch (direction)
+ {
+ case 0:
+ GetEasyChatInstructionsText(&text1, &text2);
+ break;
+ case 2:
+ GetEasyChatConfirmCancelText(&text1, &text2);
+ break;
+ case 3:
+ GetEasyChatConfirmText(&text1, &text2);
+ break;
+ case 1:
+ GetEasyChatConfirmDeletionText(&text1, &text2);
+ break;
+ }
+
+ FillWindowPixelBuffer(1, PIXEL_FILL(1));
+ if (text1)
+ EC_AddTextPrinterParameterized(1, 1, text1, 0, 0, TEXT_SPEED_FF, NULL);
+
+ if (text2)
+ EC_AddTextPrinterParameterized(1, 1, text2, 0, 16, TEXT_SPEED_FF, NULL);
+
+ CopyWindowToVram(1, 3);
+}
+
+static void EC_CreateYesNoMenuWithInitialCursorPos(u8 initialCursorPos)
+{
+ CreateYesNoMenu(&sEasyChatYesNoWindowTemplate, 1, 0, 2, 0x001, 14, initialCursorPos);
+}
+
+static void CreatePhraseFrameWindow(void)
+{
+ u8 frameId;
+ struct WindowTemplate template;
+
+ frameId = GetEasyChatScreenFrameId();
+ template.bg = 3;
+ template.tilemapLeft = sPhraseFrameDimensions[frameId].left;
+ template.tilemapTop = sPhraseFrameDimensions[frameId].top;
+ template.width = sPhraseFrameDimensions[frameId].width;
+ template.height = sPhraseFrameDimensions[frameId].height;
+ template.paletteNum = 11;
+ template.baseBlock = 0x060;
+ sEasyChatGraphicsResources->windowId = AddWindow(&template);
+ PutWindowTilemap(sEasyChatGraphicsResources->windowId);
+}
+
+static void PrintECFields(void)
+{
+ u16 *ecWord;
+ u8 numColumns, numRows;
+ u8 *str;
+ u8 frameId;
+ int i, j, k;
+
+ ecWord = GetEasyChatWordBuffer();
+ numColumns = GetNumColumns();
+ numRows = GetNumRows();
+ frameId = GetEasyChatScreenFrameId();
+ FillWindowPixelBuffer(sEasyChatGraphicsResources->windowId, PIXEL_FILL(1));
+ for (i = 0; i < numRows; i++)
+ {
+ str = sEasyChatGraphicsResources->ecPrintBuffer;
+ str[0] = EOS;
+ str = StringAppend(str, sText_Clear17);
+ for (j = 0; j < numColumns; j++)
+ {
+ if (*ecWord != 0xFFFF)
+ {
+ str = CopyEasyChatWord(str, *ecWord);
+ ecWord++;
+ }
+ else
+ {
+ str = WriteColorChangeControlCode(str, 0, TEXT_COLOR_RED);
+ ecWord++;
+ for (k = 0; k < 7; k++)
+ {
+ *str++ = CHAR_EXTRA_EMOJI;
+ *str++ = 9;
+ }
+
+ str = WriteColorChangeControlCode(str, 0, TEXT_COLOR_DARK_GREY);
+ }
+
+ str = StringAppend(str, sText_Clear17);
+ if (frameId == 2)
+ {
+ if (j == 0 && i == 4)
+ break;
+ }
+ }
+
+ *str = EOS;
+ EC_AddTextPrinterParameterized(sEasyChatGraphicsResources->windowId, 1, sEasyChatGraphicsResources->ecPrintBuffer, 0, i * 16, TEXT_SPEED_FF, NULL);
+ }
+
+ CopyWindowToVram(sEasyChatGraphicsResources->windowId, 3);
+}
+
+static void DrawECFrameInTilemapBuffer(u16 *tilemap)
+{
+ u8 frameId;
+ int right, bottom;
+ int x, y;
+
+ frameId = GetEasyChatScreenFrameId();
+ CpuFastFill(0, tilemap, BG_SCREEN_SIZE);
+ if (frameId == 2)
+ {
+ right = sPhraseFrameDimensions[frameId].left + sPhraseFrameDimensions[frameId].width;
+ bottom = sPhraseFrameDimensions[frameId].top + sPhraseFrameDimensions[frameId].height;
+ for (y = sPhraseFrameDimensions[frameId].top; y < bottom; y++)
+ {
+ x = sPhraseFrameDimensions[frameId].left - 1;
+ tilemap[y * 32 + x] = 0x1005;
+ x++;
+ for (; x < right; x++)
+ tilemap[y * 32 + x] = 0x1000;
+
+ tilemap[y* 32 + x] = 0x1007;
+ }
+ }
+ else
+ {
+ y = sPhraseFrameDimensions[frameId].top - 1;
+ x = sPhraseFrameDimensions[frameId].left - 1;
+ right = sPhraseFrameDimensions[frameId].left + sPhraseFrameDimensions[frameId].width;
+ bottom = sPhraseFrameDimensions[frameId].top + sPhraseFrameDimensions[frameId].height;
+ tilemap[y * 32 + x] = 0x1001;
+ x++;
+ for (; x < right; x++)
+ tilemap[y * 32 + x] = 0x1002;
+
+ tilemap[y * 32 + x] = 0x1003;
+ y++;
+ for (; y < bottom; y++)
+ {
+ x = sPhraseFrameDimensions[frameId].left - 1;
+ tilemap[y * 32 + x] = 0x1005;
+ x++;
+ for (; x < right; x++)
+ tilemap[y * 32 + x] = 0x1000;
+
+ tilemap[y* 32 + x] = 0x1007;
+ }
+
+ x = sPhraseFrameDimensions[frameId].left - 1;
+ tilemap[y * 32 + x] = 0x1009;
+ x++;
+ for (; x < right; x++)
+ tilemap[y * 32 + x] = 0x100A;
+
+ tilemap[y * 32 + x] = 0x100B;
+ }
+}
+
+static void PutWin2TilemapAndCopyToVram(void)
+{
+ PutWindowTilemap(2);
+ CopyBgTilemapBufferToVram(2);
+}
+
+static void PrintECMenuById(u32 id)
+{
+ InitBg2Scroll();
+ FillWindowPixelBuffer(2, PIXEL_FILL(1));
+ switch (id)
+ {
+ case 0:
+ PrintECGroupsMenu();
+ break;
+ case 1:
+ PrintEasyChatKeyboardText();
+ break;
+ case 2:
+ PrintECWordsMenu();
+ break;
+ }
+
+ CopyWindowToVram(2, 2);
+}
+
+static void PrintECGroupOrAlphaMenu(void)
+{
+ if (!IsEasyChatAlphaMode())
+ PrintECMenuById(0);
+ else
+ PrintECMenuById(1);
+}
+
+static void PrintECGroupsMenu(void)
+{
+ int i;
+ int x, y;
+
+ i = 0;
+ y = 96;
+ while (1)
+ {
+ for (x = 0; x < 2; x++)
+ {
+ u8 groupId = GetSelectedGroupByIndex(i++);
+ if (groupId == EC_NUM_GROUPS)
+ {
+ ScheduleBg2VerticalScroll(GetECSelectGroupRowsAbove(), 0);
+ return;
+ }
+
+ EC_AddTextPrinterParameterized(2, 1, GetEasyChatWordGroupName(groupId), x * 84 + 10, y, TEXT_SPEED_FF, NULL);
+ }
+
+ y += 16;
+ }
+}
+
+static void PrintEasyChatKeyboardText(void)
+{
+ u32 i;
+
+ for (i = 0; i < NELEMS(sEasyChatKeyboardText); i++)
+ EC_AddTextPrinterParameterized(2, 1, sEasyChatKeyboardText[i], 10, 96 + i * 16, TEXT_SPEED_FF, NULL);
+}
+
+static void PrintECWordsMenu(void)
+{
+ PrintECRowsWin2(0, 4);
+}
+
+static void UpdateWin2PrintWordsScrollDown(void)
+{
+ u8 rowsAbove = GetECSelectWordRowsAbove() + 3;
+ ClearECRowsWin2(rowsAbove, 1);
+ PrintECRowsWin2(rowsAbove, 1);
+}
+
+static void UpdateWin2PrintWordsScrollUp(void)
+{
+ u8 rowsAbove = GetECSelectWordRowsAbove();
+ ClearECRowsWin2(rowsAbove, 1);
+ PrintECRowsWin2(rowsAbove, 1);
+}
+
+static void UpdateWin2PrintWordsScrollPageDown(void)
+{
+ u8 row = GetECSelectWordRowsAbove();
+ u8 maxrow = row + 4;
+ u8 numrowsplus1 = GetECSelectWordNumRows() + 1;
+ if (maxrow > numrowsplus1)
+ maxrow = numrowsplus1;
+
+ if (row < maxrow)
+ {
+ u8 remrow = maxrow - row;
+ ClearECRowsWin2(row, remrow);
+ PrintECRowsWin2(row, remrow);
+ }
+}
+
+static void UpdateWin2PrintWordsScrollPageUp(void)
+{
+ u8 row = GetECSelectWordRowsAbove();
+ u8 maxrow = GetBg2ScrollRow();
+ if (row < maxrow)
+ {
+ u8 remrow = maxrow - row;
+ ClearECRowsWin2(row, remrow);
+ PrintECRowsWin2(row, remrow);
+ }
+}
+
+static void PrintECRowsWin2(u8 row, u8 remrow)
+{
+ int i, j;
+ u16 easyChatWord;
+ u8 *str;
+ int y;
+ u8 y_;
+ int ecWordIdx;
+
+ ecWordIdx = row * 2;
+ y = (row * 16 + 96) & 0xFF;
+
+ for (i = 0; i < remrow; i++)
+ {
+ for (j = 0; j < 2; j++)
+ {
+ // FIXME: Dumb trick needed to match
+ y_ = y << 18 >> 18;
+ easyChatWord = GetDisplayedWordByIndex(ecWordIdx++);
+ if (easyChatWord != 0xFFFF)
+ {
+
+ CopyEasyChatWordPadded(sEasyChatGraphicsResources->ecPaddedWordBuffer, easyChatWord, 0);
+
+ EC_AddTextPrinterParameterized(2, 1, sEasyChatGraphicsResources->ecPaddedWordBuffer, (j * 13 + 3) * 8, y_, TEXT_SPEED_FF, NULL);
+ }
+ }
+ y += 16;
+
+ }
+
+ CopyWindowToVram(2, 2);
+}
+
+static void ClearECRowsWin2(u8 row, u8 remrow)
+{
+ int y;
+ int totalHeight;
+ int heightWrappedAround;
+ int heightToBottom;
+
+ y = (row * 16 + 96) & 0xFF;
+ heightToBottom = remrow * 16;
+ totalHeight = y + heightToBottom;
+ if (totalHeight > 255)
+ {
+ heightWrappedAround = totalHeight - 256;
+ heightToBottom = 256 - y;
+ }
+ else
+ {
+ heightWrappedAround = 0;
+ }
+
+ FillWindowPixelRect(2, PIXEL_FILL(1), 0, y, 224, heightToBottom);
+ if (heightWrappedAround)
+ FillWindowPixelRect(2, PIXEL_FILL(1), 0, 0, 224, heightWrappedAround);
+}
+
+static void ClearWin2AndCopyToVram(void)
+{
+ FillWindowPixelBuffer(2, PIXEL_FILL(1));
+ CopyWindowToVram(2, 2);
+}
+
+static void StartWin2FrameAnim(int animNo)
+{
+ switch (animNo)
+ {
+ case 0:
+ sEasyChatGraphicsResources->frameAnimIdx = 0;
+ sEasyChatGraphicsResources->frameAnimTarget = 10;
+ break;
+ case 1:
+ sEasyChatGraphicsResources->frameAnimIdx = 9;
+ sEasyChatGraphicsResources->frameAnimTarget = 0;
+ break;
+ case 2:
+ sEasyChatGraphicsResources->frameAnimIdx = 11;
+ sEasyChatGraphicsResources->frameAnimTarget = 17;
+ break;
+ case 3:
+ sEasyChatGraphicsResources->frameAnimIdx = 17;
+ sEasyChatGraphicsResources->frameAnimTarget = 0;
+ break;
+ case 4:
+ sEasyChatGraphicsResources->frameAnimIdx = 17;
+ sEasyChatGraphicsResources->frameAnimTarget = 10;
+ break;
+ case 5:
+ sEasyChatGraphicsResources->frameAnimIdx = 18;
+ sEasyChatGraphicsResources->frameAnimTarget = 22;
+ break;
+ case 6:
+ sEasyChatGraphicsResources->frameAnimIdx = 22;
+ sEasyChatGraphicsResources->frameAnimTarget = 18;
+ break;
+ }
+
+ sEasyChatGraphicsResources->frameAnimDelta = sEasyChatGraphicsResources->frameAnimIdx < sEasyChatGraphicsResources->frameAnimTarget ? 1 : -1;
+}
+
+static bool8 AnimateFrameResize(void)
+{
+ if (sEasyChatGraphicsResources->frameAnimIdx == sEasyChatGraphicsResources->frameAnimTarget)
+ return FALSE;
+
+ sEasyChatGraphicsResources->frameAnimIdx += sEasyChatGraphicsResources->frameAnimDelta;
+ RedrawFrameByIndex(sEasyChatGraphicsResources->frameAnimIdx);
+ return sEasyChatGraphicsResources->frameAnimIdx != sEasyChatGraphicsResources->frameAnimTarget;
+}
+
+static void RedrawFrameByIndex(u8 direction)
+{
+ FillBgTilemapBufferRect_Palette0(1, 0, 0, 10, 30, 10);
+ switch (direction)
+ {
+ case 0:
+ break;
+ case 1:
+ RedrawFrameByRect(11, 14, 3, 2);
+ break;
+ case 2:
+ RedrawFrameByRect(9, 14, 7, 2);
+ break;
+ case 3:
+ RedrawFrameByRect(7, 14, 11, 2);
+ break;
+ case 4:
+ RedrawFrameByRect(5, 14, 15, 2);
+ break;
+ case 5:
+ RedrawFrameByRect(3, 14, 19, 2);
+ break;
+ case 6:
+ RedrawFrameByRect(1, 14, 23, 2);
+ break;
+ case 7:
+ RedrawFrameByRect(1, 13, 23, 4);
+ break;
+ case 8:
+ RedrawFrameByRect(1, 12, 23, 6);
+ break;
+ case 9:
+ RedrawFrameByRect(1, 11, 23, 8);
+ break;
+ case 10:
+ RedrawFrameByRect(1, 10, 23, 10);
+ break;
+ case 11:
+ RedrawFrameByRect(1, 10, 24, 10);
+ break;
+ case 12:
+ RedrawFrameByRect(1, 10, 25, 10);
+ break;
+ case 13:
+ RedrawFrameByRect(1, 10, 26, 10);
+ break;
+ case 14:
+ RedrawFrameByRect(1, 10, 27, 10);
+ break;
+ case 15:
+ RedrawFrameByRect(1, 10, 28, 10);
+ break;
+ case 16:
+ RedrawFrameByRect(1, 10, 29, 10);
+ break;
+ case 17:
+ RedrawFrameByRect(0, 10, 30, 10);
+ break;
+ case 18:
+ RedrawFrameByRect(1, 10, 23, 10);
+ break;
+ case 19:
+ RedrawFrameByRect(1, 11, 23, 8);
+ break;
+ case 20:
+ RedrawFrameByRect(1, 12, 23, 6);
+ break;
+ case 21:
+ RedrawFrameByRect(1, 13, 23, 4);
+ break;
+ case 22:
+ RedrawFrameByRect(1, 14, 23, 2);
+ break;
+ }
+
+ CopyBgTilemapBufferToVram(1);
+}
+
+static void RedrawFrameByRect(int left, int top, int width, int height)
+{
+ u16 *tilemap;
+ int right;
+ int bottom;
+ int x, y;
+
+ tilemap = sEasyChatGraphicsResources->bg1TilemapBuffer;
+ right = left + width - 1;
+ bottom = top + height - 1;
+ x = left;
+ y = top;
+ tilemap[y * 32 + x] = 0x4001;
+ x++;
+ for (; x < right; x++)
+ tilemap[y * 32 + x] = 0x4002;
+
+ tilemap[y * 32 + x] = 0x4003;
+ y++;
+ for (; y < bottom; y++)
+ {
+ tilemap[y * 32 + left] = 0x4005;
+ x = left + 1;
+ for (; x < right; x++)
+ tilemap[y * 32 + x] = 0x4000;
+
+ tilemap[y * 32 + x] = 0x4007;
+ }
+
+ tilemap[y * 32 + left] = 0x4009;
+ x = left + 1;
+ for (; x < right; x++)
+ tilemap[y * 32 + x] = 0x400A;
+
+ tilemap[y * 32 + x] = 0x400B;
+ SetRegWin0Coords((left + 1) * 8, (top + 1) * 8, (width - 2) * 8, (height - 2) * 8);
+}
+
+static void InitBg2Scroll(void)
+{
+ ChangeBgY(2, 0x800, 0);
+ sEasyChatGraphicsResources->bg2ScrollRow = 0;
+}
+
+static void ScheduleBg2VerticalScroll(s16 direction, u8 speed)
+{
+ int bgY;
+ s16 totalDelta;
+
+ bgY = GetBgY(2);
+ sEasyChatGraphicsResources->bg2ScrollRow += direction;
+ totalDelta = direction * 16;
+ bgY += totalDelta << 8;
+ if (speed)
+ {
+ sEasyChatGraphicsResources->tgtBgY = bgY;
+ sEasyChatGraphicsResources->deltaBgY = speed * 256;
+ if (totalDelta < 0)
+ sEasyChatGraphicsResources->deltaBgY = -sEasyChatGraphicsResources->deltaBgY;
+ }
+ else
+ {
+ ChangeBgY(2, bgY, 0);
+ }
+}
+
+static bool8 AnimateBg2VerticalScroll(void)
+{
+ int bgY;
+
+ bgY = GetBgY(2);
+ if (bgY == sEasyChatGraphicsResources->tgtBgY)
+ {
+ return FALSE;
+ }
+ else
+ {
+ ChangeBgY(2, sEasyChatGraphicsResources->deltaBgY, 1);
+ return TRUE;
+ }
+}
+
+static int GetBg2ScrollRow(void)
+{
+ return sEasyChatGraphicsResources->bg2ScrollRow;
+}
+
+static void SetRegWin0Coords(u8 left, u8 top, u8 width, u8 height)
+{
+ u16 horizontalDimensions = WIN_RANGE(left, left + width);
+ u16 verticalDimensions = WIN_RANGE(top, top + height);
+ SetGpuReg(REG_OFFSET_WIN0H, horizontalDimensions);
+ SetGpuReg(REG_OFFSET_WIN0V, verticalDimensions);
+}
+
+static void LoadSpriteGfx(void)
+{
+ u32 i;
+
+ LoadSpriteSheets(sEasyChatSpriteSheets);
+ LoadSpritePalettes(sEasyChatSpritePalettes);
+ for (i = 0; i < NELEMS(sEasyChatCompressedSpriteSheets); i++)
+ LoadCompressedSpriteSheet(&sEasyChatCompressedSpriteSheets[i]);
+}
+
+static void CreateSelectDestFieldCursorSprite(void)
+{
+ u8 frameId = GetEasyChatScreenFrameId();
+ s16 x = sPhraseFrameDimensions[frameId].left * 8 + 13;
+ s16 y = (sPhraseFrameDimensions[frameId].top + 1) * 8 + 1;
+ u8 spriteId = CreateSprite(&sSpriteTemplate_RightTriangleCursor, x, y, 2);
+ sEasyChatGraphicsResources->selectDestFieldCursorSprite = &gSprites[spriteId];
+ gSprites[spriteId].data[1] = 1;
+}
+
+static void SpriteCB_BounceCursor(struct Sprite * sprite)
+{
+ if (sprite->data[1])
+ {
+ if (++sprite->data[0] > 2)
+ {
+ sprite->data[0] = 0;
+ if (++sprite->pos2.x > 0)
+ sprite->pos2.x = -6;
+ }
+ }
+}
+
+static void SetSelectDestFieldCursorSpritePosAndResetAnim(u8 x, u8 y)
+{
+ sEasyChatGraphicsResources->selectDestFieldCursorSprite->pos1.x = x;
+ sEasyChatGraphicsResources->selectDestFieldCursorSprite->pos1.y = y;
+ sEasyChatGraphicsResources->selectDestFieldCursorSprite->pos2.x = 0;
+ sEasyChatGraphicsResources->selectDestFieldCursorSprite->data[0] = 0;
+}
+
+static void FreezeSelectDestFieldCursorSprite(void)
+{
+ sEasyChatGraphicsResources->selectDestFieldCursorSprite->data[0] = 0;
+ sEasyChatGraphicsResources->selectDestFieldCursorSprite->data[1] = 0;
+ sEasyChatGraphicsResources->selectDestFieldCursorSprite->pos2.x = 0;
+}
+
+static void UnfreezeSelectDestFieldCursorSprite(void)
+{
+ sEasyChatGraphicsResources->selectDestFieldCursorSprite->data[1] = 1;
+}
+
+static void CreateRedRectangularCursorSpritePair(void)
+{
+ u8 spriteId = CreateSprite(&sSpriteTemplate_RedRectangularCursor, 0, 0, 3);
+ sEasyChatGraphicsResources->rectCursorSpriteRight = &gSprites[spriteId];
+ sEasyChatGraphicsResources->rectCursorSpriteRight->pos2.x = 32;
+
+ spriteId = CreateSprite(&sSpriteTemplate_RedRectangularCursor, 0, 0, 3);
+ sEasyChatGraphicsResources->rectCursorSpriteLeft = &gSprites[spriteId];
+ sEasyChatGraphicsResources->rectCursorSpriteLeft->pos2.x = -32;
+
+ sEasyChatGraphicsResources->rectCursorSpriteRight->hFlip = TRUE;
+ EC_MoveCursor();
+}
+
+static void DestroyRedRectangularCursor(void)
+{
+ DestroySprite(sEasyChatGraphicsResources->rectCursorSpriteRight);
+ sEasyChatGraphicsResources->rectCursorSpriteRight = NULL;
+ DestroySprite(sEasyChatGraphicsResources->rectCursorSpriteLeft);
+ sEasyChatGraphicsResources->rectCursorSpriteLeft = NULL;
+}
+
+static void EC_MoveCursor(void)
+{
+ u8 x;
+ u8 y;
+
+ if (sEasyChatGraphicsResources->rectCursorSpriteRight && sEasyChatGraphicsResources->rectCursorSpriteLeft)
+ {
+ GetECSelectGroupCursorCoords(&x, &y);
+ if (!IsEasyChatAlphaMode())
+ MoveCursor_Group(x, y);
+ else
+ MoveCursor_Alpha(x, y);
+ }
+}
+
+static void MoveCursor_Group(s8 x, s8 y)
+{
+ if (x != -1)
+ {
+ StartSpriteAnim(sEasyChatGraphicsResources->rectCursorSpriteRight, 0);
+ sEasyChatGraphicsResources->rectCursorSpriteRight->pos1.x = x * 84 + 58;
+ sEasyChatGraphicsResources->rectCursorSpriteRight->pos1.y = y * 16 + 96;
+
+ StartSpriteAnim(sEasyChatGraphicsResources->rectCursorSpriteLeft, 0);
+ sEasyChatGraphicsResources->rectCursorSpriteLeft->pos1.x = x * 84 + 58;
+ sEasyChatGraphicsResources->rectCursorSpriteLeft->pos1.y = y * 16 + 96;
+ }
+ else
+ {
+ StartSpriteAnim(sEasyChatGraphicsResources->rectCursorSpriteRight, 1);
+ sEasyChatGraphicsResources->rectCursorSpriteRight->pos1.x = 216;
+ sEasyChatGraphicsResources->rectCursorSpriteRight->pos1.y = y * 16 + 112;
+
+ StartSpriteAnim(sEasyChatGraphicsResources->rectCursorSpriteLeft, 1);
+ sEasyChatGraphicsResources->rectCursorSpriteLeft->pos1.x = 216;
+ sEasyChatGraphicsResources->rectCursorSpriteLeft->pos1.y = y * 16 + 112;
+ }
+}
+
+static void MoveCursor_Alpha(s8 cursorX, s8 cursorY)
+{
+ int anim;
+ int x, y;
+
+ if (cursorX != -1)
+ {
+ y = cursorY * 16 + 96;
+ x = 32;
+ if (cursorX == 6 && cursorY == 0)
+ {
+ x = 157;
+ anim = 2;
+ }
+ else
+ {
+ x += sECDisplay_AlphaModeXCoords[cursorX < NELEMS(sECDisplay_AlphaModeXCoords) ? cursorX : 0];
+ anim = 3;
+ }
+
+ StartSpriteAnim(sEasyChatGraphicsResources->rectCursorSpriteRight, anim);
+ sEasyChatGraphicsResources->rectCursorSpriteRight->pos1.x = x;
+ sEasyChatGraphicsResources->rectCursorSpriteRight->pos1.y = y;
+
+ StartSpriteAnim(sEasyChatGraphicsResources->rectCursorSpriteLeft, anim);
+ sEasyChatGraphicsResources->rectCursorSpriteLeft->pos1.x = x;
+ sEasyChatGraphicsResources->rectCursorSpriteLeft->pos1.y = y;
+ }
+ else
+ {
+ StartSpriteAnim(sEasyChatGraphicsResources->rectCursorSpriteRight, 1);
+ sEasyChatGraphicsResources->rectCursorSpriteRight->pos1.x = 216;
+ sEasyChatGraphicsResources->rectCursorSpriteRight->pos1.y = cursorY * 16 + 112;
+
+ StartSpriteAnim(sEasyChatGraphicsResources->rectCursorSpriteLeft, 1);
+ sEasyChatGraphicsResources->rectCursorSpriteLeft->pos1.x = 216;
+ sEasyChatGraphicsResources->rectCursorSpriteLeft->pos1.y = cursorY * 16 + 112;
+ }
+}
+
+static void CreateSelectWordCursorSprite(void)
+{
+ u8 spriteId = CreateSprite(&sSpriteTemplate_RightTriangleCursor, 0, 0, 4);
+ sEasyChatGraphicsResources->selectWordCursorSprite = &gSprites[spriteId];
+ sEasyChatGraphicsResources->selectWordCursorSprite->callback = SpriteCB_SelectWordCursorSprite;
+ sEasyChatGraphicsResources->selectWordCursorSprite->oam.priority = 2;
+ SetSelectWordCursorSpritePos();
+}
+
+static void SpriteCB_SelectWordCursorSprite(struct Sprite * sprite)
+{
+ if (++sprite->data[0] > 2)
+ {
+ sprite->data[0] = 0;
+ if (++sprite->pos2.x > 0)
+ sprite->pos2.x = -6;
+ }
+}
+
+static void SetSelectWordCursorSpritePos(void)
+{
+ s8 cursorX, cursorY;
+ u8 x, y;
+
+ GetECSelectWordCursorCoords(&cursorX, &cursorY);
+ x = cursorX * 13 + 3;
+ y = cursorY * 2 + 11;
+ SetSelectWordCursorSpritePosExplicit(x, y);
+}
+
+static void SetSelectWordCursorSpritePosExplicit(u8 x, u8 y)
+{
+ if (sEasyChatGraphicsResources->selectWordCursorSprite)
+ {
+ sEasyChatGraphicsResources->selectWordCursorSprite->pos1.x = x * 8 + 4;
+ sEasyChatGraphicsResources->selectWordCursorSprite->pos1.y = (y + 1) * 8 + 1;
+ sEasyChatGraphicsResources->selectWordCursorSprite->pos2.x = 0;
+ sEasyChatGraphicsResources->selectWordCursorSprite->data[0] = 0;
+ }
+}
+
+static void DestroySelectWordCursorSprite(void)
+{
+ if (sEasyChatGraphicsResources->selectWordCursorSprite)
+ {
+ DestroySprite(sEasyChatGraphicsResources->selectWordCursorSprite);
+ sEasyChatGraphicsResources->selectWordCursorSprite = NULL;
+ }
+}
+
+static void CreateSelectGroupHelpSprite(void)
+{
+ u8 spriteId = CreateSprite(&sSpriteTemplate_SelectGroupHelp, 208, 128, 6);
+ sEasyChatGraphicsResources->selectGroupHelpSprite = &gSprites[spriteId];
+ sEasyChatGraphicsResources->selectGroupHelpSprite->pos2.x = -64;
+
+ spriteId = CreateSprite(&sSpriteTemplate_EasyChatModeIcons, 208, 80, 5);
+ sEasyChatGraphicsResources->modeIconsSprite = &gSprites[spriteId];
+ sEasyChatGraphicsResources->modeIconState = 0;
+}
+
+static bool8 AnimateSeletGroupModeAndHelpSpriteEnter(void)
+{
+ switch (sEasyChatGraphicsResources->modeIconState)
+ {
+ default:
+ return FALSE;
+ case 0:
+ sEasyChatGraphicsResources->selectGroupHelpSprite->pos2.x += 8;
+ if (sEasyChatGraphicsResources->selectGroupHelpSprite->pos2.x >= 0)
+ {
+ sEasyChatGraphicsResources->selectGroupHelpSprite->pos2.x = 0;
+ if (!IsEasyChatAlphaMode())
+ StartSpriteAnim(sEasyChatGraphicsResources->modeIconsSprite, 1);
+ else
+ StartSpriteAnim(sEasyChatGraphicsResources->modeIconsSprite, 2);
+
+ sEasyChatGraphicsResources->modeIconState++;
+ }
+ break;
+ case 1:
+ if (sEasyChatGraphicsResources->modeIconsSprite->animEnded)
+ {
+ sEasyChatGraphicsResources->modeIconState = 2;
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static void StartModeIconHidingAnimation(void)
+{
+ sEasyChatGraphicsResources->modeIconState = 0;
+ StartSpriteAnim(sEasyChatGraphicsResources->modeIconsSprite, 3);
+}
+
+static bool8 RunModeIconHidingAnimation(void)
+{
+ switch (sEasyChatGraphicsResources->modeIconState)
+ {
+ default:
+ return FALSE;
+ case 0:
+ if (sEasyChatGraphicsResources->modeIconsSprite->animEnded)
+ sEasyChatGraphicsResources->modeIconState = 1;
+ break;
+ case 1:
+ sEasyChatGraphicsResources->selectGroupHelpSprite->pos2.x -= 8;
+ if (sEasyChatGraphicsResources->selectGroupHelpSprite->pos2.x <= -64)
+ {
+ DestroySprite(sEasyChatGraphicsResources->modeIconsSprite);
+ DestroySprite(sEasyChatGraphicsResources->selectGroupHelpSprite);
+ sEasyChatGraphicsResources->modeIconsSprite = NULL;
+ sEasyChatGraphicsResources->selectGroupHelpSprite = NULL;
+ sEasyChatGraphicsResources->modeIconState++;
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static void ShrinkModeIconsSprite(void)
+{
+ StartSpriteAnim(sEasyChatGraphicsResources->modeIconsSprite, 4);
+}
+
+static void ShowModeIconsSprite(void)
+{
+ if (!IsEasyChatAlphaMode())
+ StartSpriteAnim(sEasyChatGraphicsResources->modeIconsSprite, 1);
+ else
+ StartSpriteAnim(sEasyChatGraphicsResources->modeIconsSprite, 2);
+}
+
+static bool8 ModeIconsSpriteAnimIsEnded(void)
+{
+ return !sEasyChatGraphicsResources->modeIconsSprite->animEnded;
+}
+
+static void CreateVerticalScrollArrowSprites(void)
+{
+ u8 spriteId = CreateSprite(&sSpriteTemplate_UpTriangleCursor, 96, 80, 0);
+ if (spriteId != MAX_SPRITES)
+ sEasyChatGraphicsResources->upTriangleCursorSprite = &gSprites[spriteId];
+
+ spriteId = CreateSprite(&sSpriteTemplate_UpTriangleCursor, 96, 156, 0);
+ if (spriteId != MAX_SPRITES)
+ {
+ sEasyChatGraphicsResources->downTriangleCursorSprite = &gSprites[spriteId];
+ sEasyChatGraphicsResources->downTriangleCursorSprite->vFlip = TRUE;
+ }
+
+ HideVerticalScrollArrowSprites();
+}
+
+static void UpdateVerticalScrollArrowVisibility(void)
+{
+ sEasyChatGraphicsResources->upTriangleCursorSprite->invisible = !ShouldDrawECUpArrow();
+ sEasyChatGraphicsResources->downTriangleCursorSprite->invisible = !ShouldDrawECDownArrow();
+}
+
+static void HideVerticalScrollArrowSprites(void)
+{
+ sEasyChatGraphicsResources->upTriangleCursorSprite->invisible = TRUE;
+ sEasyChatGraphicsResources->downTriangleCursorSprite->invisible = TRUE;
+}
+
+static void UpdateVerticalScrollArrowSpriteXPos(int direction)
+{
+ if (!direction)
+ {
+ // Group select
+ sEasyChatGraphicsResources->upTriangleCursorSprite->pos1.x = 96;
+ sEasyChatGraphicsResources->downTriangleCursorSprite->pos1.x = 96;
+ }
+ else
+ {
+ // Word select
+ sEasyChatGraphicsResources->upTriangleCursorSprite->pos1.x = 120;
+ sEasyChatGraphicsResources->downTriangleCursorSprite->pos1.x = 120;
+ }
+}
+
+static void CreateStartSelectButtonsSprites(void)
+{
+ u8 spriteId = CreateSprite(&sSpriteTemplate_StartSelectButtons, 220, 84, 1);
+ if (spriteId != MAX_SPRITES)
+ sEasyChatGraphicsResources->startPgUpButtonSprite = &gSprites[spriteId];
+
+ spriteId = CreateSprite(&sSpriteTemplate_StartSelectButtons, 220, 156, 1);
+ if (spriteId != MAX_SPRITES)
+ {
+ sEasyChatGraphicsResources->selectPgDnButtonSprite = &gSprites[spriteId];
+ StartSpriteAnim(sEasyChatGraphicsResources->selectPgDnButtonSprite, 1);
+ }
+
+ HideStartSelectButtonSprites();
+}
+
+static void UpdateStartSelectButtonSpriteVisibility(void)
+{
+ sEasyChatGraphicsResources->startPgUpButtonSprite->invisible = !ShouldDrawECUpArrow();
+ sEasyChatGraphicsResources->selectPgDnButtonSprite->invisible = !ShouldDrawECDownArrow();
+}
+
+static void HideStartSelectButtonSprites(void)
+{
+ sEasyChatGraphicsResources->startPgUpButtonSprite->invisible = TRUE;
+ sEasyChatGraphicsResources->selectPgDnButtonSprite->invisible = TRUE;
+}
+
+static void CreateFooterWindow(void)
+{
+ u16 windowId;
+ struct WindowTemplate template;
+ template.bg = 3;
+ template.tilemapLeft = 4;
+ template.tilemapTop = 11;
+ template.width = 24;
+ template.height = 2;
+ template.paletteNum = 11;
+ template.baseBlock = 0x030;
+ windowId = AddWindow(&template);
+ FillWindowPixelBuffer(windowId, PIXEL_FILL(1));
+ EC_AddTextPrinterParameterized(windowId, 1, gUnknown_841EE2B, 0, 0, 0, NULL);
+ PutWindowTilemap(windowId);
+}
diff --git a/src/graphics.c b/src/graphics.c
index eaa49247c..cb35568fa 100644
--- a/src/graphics.c
+++ b/src/graphics.c
@@ -1215,13 +1215,13 @@ const u32 gKantoTrainerCard_Gfx[] = INCBIN_U32("graphics/trainer_card/card.4bpp.
const u16 gHoennTrainerCard_Pal[] = INCBIN_U16("graphics/trainer_card/0star_em.gbapal");
const u32 gHoennTrainerCard_Gfx[] = INCBIN_U32("graphics/trainer_card/card_em.4bpp.lz");
-const u16 gUnknown_8E99D8C[] = INCBIN_U16("graphics/link_rfu/unk_8E99DAC.gbapal");
-const u32 gUnknown_8E99DAC[] = INCBIN_U32("graphics/link_rfu/unk_8E99DAC.4bpp.lz");
-const u32 gUnknown_8E99E74[] = INCBIN_U32("graphics/link_rfu/unk_8E99E74.bin.lz");
+const u16 gEasyChatMode_Pal[] = INCBIN_U16("graphics/link_rfu/unk_8E99DAC.gbapal");
+const u32 gEasyChatWindow_Gfx[] = INCBIN_U32("graphics/link_rfu/unk_8E99DAC.4bpp.lz");
+const u32 gEasyChatWindow_Tilemap[] = INCBIN_U32("graphics/link_rfu/unk_8E99E74.bin.lz");
const u16 gUnknown_8E99F24[] = INCBIN_U16("graphics/link_rfu/unk_8E9A168.gbapal");
-const u32 gUnknown_8E99F44[] = INCBIN_U32("graphics/link_rfu/unk_8E99F44.4bpp.lz");
-const u32 gUnknown_8E9A168[] = INCBIN_U32("graphics/link_rfu/unk_8E9A168.4bpp.lz");
+const u32 gEasyChatSelectGroupHelp_Tiles[] = INCBIN_U32("graphics/link_rfu/unk_8E99F44.4bpp.lz");
+const u32 gEasyChatModeIcons_Tiles[] = INCBIN_U32("graphics/link_rfu/unk_8E9A168.4bpp.lz");
const u32 gUnknown_8E9A460[] = INCBIN_U32("graphics/interface/trainer_memo.4bpp.lz");
const u32 gUnknown_8E9B310[] = INCBIN_U32("graphics/interface/trainer_memo_pal1.gbapal");
@@ -1240,7 +1240,7 @@ const u32 gUnknown_8E9BBCC[] = INCBIN_U32("graphics/interface/trainer_memo_5.bin
const u16 gUnknown_8E9BD08[] = INCBIN_U16("graphics/unknown/unknown_E9BD08.gbapal"); // might be an alternate unused palette of the link_rfu gfx below.
-const u32 gUnknown_8E9BD28[] = INCBIN_U32("graphics/interface/link_rfu_frame.4bpp.lz");
+const u32 gEasyChatRedRectangularCursor_Tiles[] = INCBIN_U32("graphics/interface/link_rfu_frame.4bpp.lz");
const u16 gUnknown_8E9BF28[] = INCBIN_U16("graphics/interface/link_rfu_frame.gbapal");
const u32 gUnknown_8E9BF48[] = INCBIN_U32("graphics/interface/link_rfu_status.4bpp.lz");