diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/battle_main.c | 9 | ||||
-rw-r--r-- | src/battle_setup.c | 27 | ||||
-rw-r--r-- | src/daycare.c | 30 | ||||
-rw-r--r-- | src/fame_checker.c | 2 | ||||
-rw-r--r-- | src/link_rfu_2.c | 31 | ||||
-rw-r--r-- | src/link_rfu_3.c | 4 | ||||
-rw-r--r-- | src/mail_data.c | 4 | ||||
-rw-r--r-- | src/new_game.c | 4 | ||||
-rw-r--r-- | src/oak_speech.c | 4 | ||||
-rw-r--r-- | src/pokemon.c | 4 | ||||
-rw-r--r-- | src/quest_log.c | 44 | ||||
-rw-r--r-- | src/seagallop.c | 28 | ||||
-rw-r--r-- | src/trade.c | 25 | ||||
-rw-r--r-- | src/union_room.c | 4 | ||||
-rw-r--r-- | src/union_room_chat.c | 1452 | ||||
-rw-r--r-- | src/union_room_chat_display.c | 1339 | ||||
-rw-r--r-- | src/union_room_chat_objects.c | 318 |
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 = ®_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); + } + } +} |