#include "global.h" #include "naming_screen.h" #include "malloc.h" #include "palette.h" #include "task.h" #include "sprite.h" #include "string_util.h" #include "window.h" #include "bg.h" #include "gpu_regs.h" #include "pokemon.h" #include "field_specials.h" #include "field_player_avatar.h" #include "event_object_movement.h" #include "event_data.h" #include "constants/songs.h" #include "pokemon_storage_system.h" #include "graphics.h" #include "sound.h" #include "trig.h" #include "field_effect.h" #include "pokemon_icon.h" #include "data.h" #include "strings.h" #include "menu.h" #include "text_window.h" #include "overworld.h" #include "walda_phrase.h" #include "constants/event_objects.h" #include "constants/rgb.h" enum { INPUT_NONE, INPUT_DPAD_UP, INPUT_DPAD_DOWN, INPUT_DPAD_LEFT, INPUT_DPAD_RIGHT, INPUT_A_BUTTON, INPUT_B_BUTTON, INPUT_LR_BUTTON, INPUT_SELECT, INPUT_START, }; #define KBROW_COUNT 4 #define KBCOL_COUNT 8 enum { GFXTAG_BACK_BUTTON, GFXTAG_OK_BUTTON, GFXTAG_PAGE_SWAP_FRAME, GFXTAG_PAGE_SWAP_BUTTON, GFXTAG_PAGE_SWAP_UPPER, GFXTAG_PAGE_SWAP_LOWER, GFXTAG_PAGE_SWAP_OTHERS, GFXTAG_CURSOR, GFXTAG_CURSOR_SQUISHED, GFXTAG_CURSOR_FILLED, GFXTAG_INPUT_ARROW, GFXTAG_UNDERSCORE, }; enum { PALTAG_PC_ICON, PALTAG_PAGE_SWAP_UPPER, PALTAG_PAGE_SWAP_LOWER, PALTAG_PAGE_SWAP_OTHERS, PALTAG_PAGE_SWAP, PALTAG_CURSOR, PALTAG_BACK_BUTTON, PALTAG_OK_BUTTON, }; enum { WIN_KB_PAGE_1, // Which of these two windows is in front is cycled as the player swaps WIN_KB_PAGE_2, // Initially WIN_KB_PAGE_1 is in front, with WIN_KB_PAGE_2 on deck WIN_TEXT_ENTRY, WIN_TEXT_ENTRY_BOX, WIN_BANNER, WIN_COUNT, }; // The constants for the pages are needlessly complicated because GF didn't keep the indexing order consistent // This set is used for sNamingScreen->currentPage. It uses the order that the pages are cycled in enum { KBPAGE_SYMBOLS, KBPAGE_LETTERS_UPPER, KBPAGE_LETTERS_LOWER, KBPAGE_COUNT, }; // This set is used for initializing a page's keyboard text and getting its number of columns enum { KEYBOARD_LETTERS_LOWER, KEYBOARD_LETTERS_UPPER, KEYBOARD_SYMBOLS, }; // This set is used for getting the gfx/pal tags of the page's swap button enum { PAGE_SWAP_UPPER, PAGE_SWAP_OTHERS, PAGE_SWAP_LOWER, }; enum { KEY_ROLE_CHAR, KEY_ROLE_PAGE, KEY_ROLE_BACKSPACE, KEY_ROLE_OK, }; enum { BUTTON_PAGE, BUTTON_BACK, BUTTON_OK, BUTTON_COUNT, }; // states for Task_NamingScreen enum { STATE_FADE_IN, STATE_WAIT_FADE_IN, STATE_HANDLE_INPUT, STATE_MOVE_TO_OK_BUTTON, STATE_START_PAGE_SWAP, STATE_WAIT_PAGE_SWAP, STATE_PRESSED_OK, STATE_WAIT_SENT_TO_PC_MESSAGE, STATE_FADE_OUT, STATE_EXIT, }; // sates for Task_HandleInput enum { INPUT_STATE_DISABLED, INPUT_STATE_ENABLED, INPUT_STATE_OVERRIDE, }; struct NamingScreenTemplate { u8 copyExistingString; u8 maxChars; u8 iconFunction; u8 addGenderIcon; u8 initialPage; u8 unused; const u8 *title; }; struct NamingScreenData { u8 tilemapBuffer1[0x800]; u8 tilemapBuffer2[0x800]; u8 tilemapBuffer3[0x800]; u8 textBuffer[16]; u8 tileBuffer[0x600]; u8 state; u8 windows[WIN_COUNT]; u16 inputCharBaseXPos; u16 bg1vOffset; u16 bg2vOffset; u16 bg1Priority; u16 bg2Priority; u8 bgToReveal; u8 bgToHide; u8 currentPage; u8 cursorSpriteId; u8 swapBtnFrameSpriteId; u8 keyRepeatStartDelayCopy; const struct NamingScreenTemplate *template; u8 templateNum; u8 *destBuffer; u16 monSpecies; u16 monGender; u32 monPersonality; MainCallback returnCallback; }; EWRAM_DATA static struct NamingScreenData *sNamingScreen = NULL; extern u16 gKeyRepeatStartDelay; // extern text extern const u8 gText_MoveOkBack[]; extern const u8 gText_YourName[]; extern const u8 gText_BoxName[]; extern const u8 gText_PkmnsNickname[]; extern const u8 gText_TellHimTheWords[]; // start of .rodata static const u8 sPCIconOff_Gfx[] = INCBIN_U8("graphics/naming_screen/pc_icon/off.4bpp"); static const u8 sPCIconOn_Gfx[] = INCBIN_U8("graphics/naming_screen/pc_icon/on.4bpp"); static const u16 sKeyboard_Pal[] = INCBIN_U16("graphics/naming_screen/keyboard.gbapal"); static const u16 sUnused_Pal[] = INCBIN_U16("graphics/naming_screen/unused.gbapal"); static const u8 *const sTransferredToPCMessages[] = { gText_PkmnTransferredSomeonesPC, gText_PkmnTransferredLanettesPC, gText_PkmnTransferredSomeonesPCBoxFull, gText_PkmnTransferredLanettesPCBoxFull }; static const u8 sText_AlphabetUpperLower[] = _("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!"); static const struct BgTemplate sBgTemplates[] = { { .bg = 0, .charBaseIndex = 0, .mapBaseIndex = 30, .priority = 0 }, { .bg = 1, .charBaseIndex = 2, .mapBaseIndex = 29, .priority = 1 }, { .bg = 2, .charBaseIndex = 2, .mapBaseIndex = 28, .priority = 2 }, { .bg = 3, .charBaseIndex = 3, .mapBaseIndex = 31, .priority = 3 } }; static const struct WindowTemplate sWindowTemplates[WIN_COUNT + 1] = { [WIN_KB_PAGE_1] = { .bg = 1, .tilemapLeft = 3, .tilemapTop = 10, .width = 19, .height = 8, .paletteNum = 10, .baseBlock = 0x030 }, [WIN_KB_PAGE_2] = { .bg = 2, .tilemapLeft = 3, .tilemapTop = 10, .width = 19, .height = 8, .paletteNum = 10, .baseBlock = 0x0C8 }, [WIN_TEXT_ENTRY] = { .bg = 3, .tilemapLeft = 8, .tilemapTop = 6, .width = 17, .height = 2, .paletteNum = 10, .baseBlock = 0x030 }, [WIN_TEXT_ENTRY_BOX] = { .bg = 3, .tilemapLeft = 8, .tilemapTop = 4, .width = 17, .height = 2, .paletteNum = 10, .baseBlock = 0x052 }, [WIN_BANNER] = { .bg = 0, .tilemapLeft = 0, .tilemapTop = 0, .width = 30, .height = 2, .paletteNum = 11, .baseBlock = 0x074 }, DUMMY_WIN_TEMPLATE }; // This handles what characters get inserted when a key is pressed // The keys shown on the keyboard are handled separately by sNamingScreenKeyboardText static const u8 sKeyboardChars[KBPAGE_COUNT][KBROW_COUNT][KBCOL_COUNT] = { [KEYBOARD_LETTERS_LOWER] = { __("abcdef ."), __("ghijkl ,"), __("mnopqrs "), __("tuvwxyz "), }, [KEYBOARD_LETTERS_UPPER] = { __("ABCDEF ."), __("GHIJKL ,"), __("MNOPQRS "), __("TUVWXYZ "), }, [KEYBOARD_SYMBOLS] = { __("01234 "), __("56789 "), __("!?♂♀/- "), __("…“”‘' "), } }; static const u8 sPageColumnCounts[KBPAGE_COUNT] = { [KEYBOARD_LETTERS_LOWER] = KBCOL_COUNT, [KEYBOARD_LETTERS_UPPER] = KBCOL_COUNT, [KEYBOARD_SYMBOLS] = 6 }; static const u8 sPageColumnXPos[KBPAGE_COUNT * KBCOL_COUNT] = { 0, 12, 24, 56, 68, 80, 92, 123, // KEYBOARD_LETTERS_LOWER 0, 12, 24, 56, 68, 80, 92, 123, // KEYBOARD_LETTERS_UPPER 0, 22, 44, 66, 88, 110 // KEYBOARD_SYMBOLS }; // forward declarations static const struct NamingScreenTemplate *const sNamingScreenTemplates[]; static const struct SubspriteTable sSubspriteTable_PageSwapFrame[]; static const struct SubspriteTable sSubspriteTable_PageSwapText[]; static const struct SubspriteTable sSubspriteTable_Button[]; static const struct SubspriteTable sSubspriteTable_PCIcon[]; static const struct SpriteTemplate sSpriteTemplate_PageSwapFrame; static const struct SpriteTemplate sSpriteTemplate_PageSwapButton; static const struct SpriteTemplate sSpriteTemplate_PageSwapText; static const struct SpriteTemplate sSpriteTemplate_BackButton; static const struct SpriteTemplate sSpriteTemplate_OkButton; static const struct SpriteTemplate sSpriteTemplate_Cursor; static const struct SpriteTemplate sSpriteTemplate_InputArrow; static const struct SpriteTemplate sSpriteTemplate_Underscore; static const struct SpriteTemplate sSpriteTemplate_PCIcon; static const u8* const sNamingScreenKeyboardText[KBPAGE_COUNT][KBROW_COUNT]; static const struct SpriteSheet sSpriteSheets[]; static const struct SpritePalette sSpritePalettes[]; static void CB2_LoadNamingScreen(void); static void NamingScreen_Init(void); static void NamingScreen_InitBGs(void); static void CreateNamingScreenTask(void); static void Task_NamingScreen(u8 taskId); static bool8 MainState_FadeIn(void); static bool8 MainState_WaitFadeIn(void); static bool8 MainState_HandleInput(void); static bool8 MainState_MoveToOKButton(void); static bool8 MainState_PressedOKButton(void); static bool8 MainState_FadeOut(void); static bool8 MainState_Exit(void); static void DisplaySentToPCMessage(void); static bool8 MainState_WaitSentToPCMessage(void); static bool8 MainState_StartPageSwap(void); static bool8 MainState_WaitPageSwap(void); static void StartPageSwapAnim(void); static void Task_HandlePageSwapAnim(u8); static bool8 IsPageSwapAnimNotInProgress(void); static void TryStartButtonFlash(u8, bool8, bool8); static void Task_UpdateButtonFlash(u8); static u16 GetButtonPalOffset(u8); static void RestoreButtonColor(u8); static void StartButtonFlash(struct Task *, u8, bool8); static void CreateSprites(void); static void CreateCursorSprite(void); static void SetCursorPos(s16, s16); static void GetCursorPos(s16 *x, s16 *y); static void MoveCursorToOKButton(void); static void SetCursorInvisibility(u8); static void SetCursorFlashing(bool8); static u8 IsCursorAnimFinished(void); static u8 GetCurrentPageColumnCount(void); static void CreatePageSwapButtonSprites(void); static void StartPageSwapButtonAnim(void); static void SetPageSwapButtonGfx(u8, struct Sprite *, struct Sprite *); static void CreateBackOkSprites(void); static void CreateTextEntrySprites(void); static void CreateInputTargetIcon(void); static u8 HandleKeyboardEvent(void); static u8 SwapKeyboardPage(void); static u8 GetInputEvent(void); static void SetInputState(u8); static void DrawTextEntryBox(void); static u8 GetTextEntryPosition(void); static void DeleteTextCharacter(void); static bool8 AddTextCharacter(void); static void BufferCharacter(u8); static void SaveInputText(void); static void LoadGfx(void); static void CreateHelperTasks(void); static void LoadPalettes(void); static void DrawBgTilemap(u8, const void *); static void NamingScreen_Dummy(u8, u8); static void DrawTextEntry(void); static void PrintKeyboardKeys(u8, u8); static void DrawKeyboardPageOnDeck(void); static void PrintControls(void); static void CB2_NamingScreen(void); static void ResetVHBlank(void); static void SetVBlank(void); static void VBlankCB_NamingScreen(void); static void NamingScreen_ShowBgs(void); static bool8 IsWideLetter(u8); void DoNamingScreen(u8 templateNum, u8 *destBuffer, u16 monSpecies, u16 monGender, u32 monPersonality, MainCallback returnCallback) { sNamingScreen = Alloc(sizeof(struct NamingScreenData)); if (!sNamingScreen) { SetMainCallback2(returnCallback); } else { sNamingScreen->templateNum = templateNum; sNamingScreen->monSpecies = monSpecies; sNamingScreen->monGender = monGender; sNamingScreen->monPersonality = monPersonality; sNamingScreen->destBuffer = destBuffer; sNamingScreen->returnCallback = returnCallback; if (templateNum == NAMING_SCREEN_PLAYER) StartTimer1(); SetMainCallback2(CB2_LoadNamingScreen); } } static void CB2_LoadNamingScreen(void) { switch (gMain.state) { case 0: ResetVHBlank(); NamingScreen_Init(); gMain.state++; break; case 1: NamingScreen_InitBGs(); gMain.state++; break; case 2: ResetPaletteFade(); gMain.state++; break; case 3: ResetSpriteData(); FreeAllSpritePalettes(); gMain.state++; break; case 4: ResetTasks(); gMain.state++; break; case 5: LoadPalettes(); gMain.state++; break; case 6: LoadGfx(); gMain.state++; break; case 7: CreateSprites(); UpdatePaletteFade(); NamingScreen_ShowBgs(); gMain.state++; break; default: CreateHelperTasks(); CreateNamingScreenTask(); break; } } static void NamingScreen_Init(void) { sNamingScreen->state = STATE_FADE_IN; sNamingScreen->bg1vOffset = 0; sNamingScreen->bg2vOffset = 0; sNamingScreen->bg1Priority = BGCNT_PRIORITY(1); sNamingScreen->bg2Priority = BGCNT_PRIORITY(2); sNamingScreen->bgToReveal = 0; sNamingScreen->bgToHide = 1; sNamingScreen->template = sNamingScreenTemplates[sNamingScreen->templateNum]; sNamingScreen->currentPage = sNamingScreen->template->initialPage; sNamingScreen->inputCharBaseXPos = (DISPLAY_WIDTH - sNamingScreen->template->maxChars * 8) / 2 + 6; if (sNamingScreen->templateNum == NAMING_SCREEN_WALDA) sNamingScreen->inputCharBaseXPos += 11; sNamingScreen->keyRepeatStartDelayCopy = gKeyRepeatStartDelay; memset(sNamingScreen->textBuffer, EOS, sizeof(sNamingScreen->textBuffer)); if (sNamingScreen->template->copyExistingString) StringCopy(sNamingScreen->textBuffer, sNamingScreen->destBuffer); gKeyRepeatStartDelay = 16; } static void SetSpritesVisible(void) { u8 i; for (i = 0; i < MAX_SPRITES; i++) { if (gSprites[i].inUse) gSprites[i].invisible = FALSE; } SetCursorInvisibility(FALSE); } static void NamingScreen_InitBGs(void) { u8 i; DmaClearLarge16(3, (void *)VRAM, VRAM_SIZE, 0x1000); DmaClear32(3, (void *)OAM, OAM_SIZE); DmaClear16(3, (void *)PLTT, PLTT_SIZE); SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_0); ResetBgsAndClearDma3BusyFlags(0); InitBgsFromTemplates(0, sBgTemplates, ARRAY_COUNT(sBgTemplates)); ChangeBgX(0, 0, BG_COORD_SET); ChangeBgY(0, 0, BG_COORD_SET); ChangeBgX(1, 0, BG_COORD_SET); ChangeBgY(1, 0, BG_COORD_SET); ChangeBgX(2, 0, BG_COORD_SET); ChangeBgY(2, 0, BG_COORD_SET); ChangeBgX(3, 0, BG_COORD_SET); ChangeBgY(3, 0, BG_COORD_SET); InitStandardTextBoxWindows(); InitTextBoxGfxAndPrinters(); for (i = 0; i < WIN_COUNT; i++) sNamingScreen->windows[i] = AddWindow(&sWindowTemplates[i]); SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_1D_MAP | DISPCNT_OBJ_ON); SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_BG1 | BLDCNT_TGT2_BG2); SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(12, 8)); SetBgTilemapBuffer(1, sNamingScreen->tilemapBuffer1); SetBgTilemapBuffer(2, sNamingScreen->tilemapBuffer2); SetBgTilemapBuffer(3, sNamingScreen->tilemapBuffer3); FillBgTilemapBufferRect_Palette0(1, 0, 0, 0, 0x20, 0x20); FillBgTilemapBufferRect_Palette0(2, 0, 0, 0, 0x20, 0x20); FillBgTilemapBufferRect_Palette0(3, 0, 0, 0, 0x20, 0x20); } static void CreateNamingScreenTask(void) { CreateTask(Task_NamingScreen, 2); SetMainCallback2(CB2_NamingScreen); } static void Task_NamingScreen(u8 taskId) { switch (sNamingScreen->state) { case STATE_FADE_IN: MainState_FadeIn(); SetSpritesVisible(); SetVBlank(); break; case STATE_WAIT_FADE_IN: MainState_WaitFadeIn(); break; case STATE_HANDLE_INPUT: MainState_HandleInput(); break; case STATE_MOVE_TO_OK_BUTTON: MainState_MoveToOKButton(); MainState_HandleInput(); break; case STATE_START_PAGE_SWAP: MainState_StartPageSwap(); break; case STATE_WAIT_PAGE_SWAP: MainState_WaitPageSwap(); break; case STATE_PRESSED_OK: MainState_PressedOKButton(); break; case STATE_WAIT_SENT_TO_PC_MESSAGE: MainState_WaitSentToPCMessage(); break; case STATE_FADE_OUT: MainState_FadeOut(); break; case STATE_EXIT: MainState_Exit(); break; } } // Which gfx/pal to load for the swap page button static const u8 sPageToNextGfxId[KBPAGE_COUNT] = { [KBPAGE_SYMBOLS] = PAGE_SWAP_UPPER, [KBPAGE_LETTERS_UPPER] = PAGE_SWAP_LOWER, [KBPAGE_LETTERS_LOWER] = PAGE_SWAP_OTHERS }; static const u8 sPageToNextKeyboardId[KBPAGE_COUNT] = { [KBPAGE_SYMBOLS] = KEYBOARD_LETTERS_UPPER, [KBPAGE_LETTERS_UPPER] = KEYBOARD_LETTERS_LOWER, [KBPAGE_LETTERS_LOWER] = KEYBOARD_SYMBOLS }; static const u8 sPageToKeyboardId[KBPAGE_COUNT] = { [KBPAGE_SYMBOLS] = KEYBOARD_SYMBOLS, [KBPAGE_LETTERS_UPPER] = KEYBOARD_LETTERS_UPPER, [KBPAGE_LETTERS_LOWER] = KEYBOARD_LETTERS_LOWER }; static u8 PageToNextGfxId(u8 page) { return sPageToNextGfxId[page]; } static u8 CurrentPageToNextKeyboardId(void) { return sPageToNextKeyboardId[sNamingScreen->currentPage]; } static u8 CurrentPageToKeyboardId(void) { return sPageToKeyboardId[sNamingScreen->currentPage]; } static bool8 MainState_FadeIn(void) { DrawBgTilemap(3, gNamingScreenBackground_Tilemap); sNamingScreen->currentPage = KBPAGE_LETTERS_UPPER; DrawBgTilemap(2, gNamingScreenKeyboardLower_Tilemap); DrawBgTilemap(1, gNamingScreenKeyboardUpper_Tilemap); PrintKeyboardKeys(sNamingScreen->windows[WIN_KB_PAGE_2], KEYBOARD_LETTERS_LOWER); PrintKeyboardKeys(sNamingScreen->windows[WIN_KB_PAGE_1], KEYBOARD_LETTERS_UPPER); NamingScreen_Dummy(2, KEYBOARD_LETTERS_LOWER); NamingScreen_Dummy(1, KEYBOARD_LETTERS_UPPER); DrawTextEntry(); DrawTextEntryBox(); PrintControls(); CopyBgTilemapBufferToVram(1); CopyBgTilemapBufferToVram(2); CopyBgTilemapBufferToVram(3); BlendPalettes(PALETTES_ALL, 16, 0); BeginNormalPaletteFade(PALETTES_ALL, 0, 16, 0, RGB_BLACK); sNamingScreen->state++; return FALSE; } static bool8 MainState_WaitFadeIn(void) { if (!gPaletteFade.active) { SetInputState(INPUT_STATE_ENABLED); SetCursorFlashing(TRUE); sNamingScreen->state++; } return FALSE; } static bool8 MainState_HandleInput(void) { return HandleKeyboardEvent(); } static bool8 MainState_MoveToOKButton(void) { if (IsCursorAnimFinished()) { SetInputState(INPUT_STATE_ENABLED); MoveCursorToOKButton(); sNamingScreen->state = STATE_HANDLE_INPUT; } return FALSE; } static bool8 MainState_PressedOKButton(void) { SaveInputText(); SetInputState(INPUT_STATE_DISABLED); SetCursorFlashing(FALSE); TryStartButtonFlash(BUTTON_COUNT, FALSE, TRUE); if (sNamingScreen->templateNum == NAMING_SCREEN_CAUGHT_MON && CalculatePlayerPartyCount() >= PARTY_SIZE) { DisplaySentToPCMessage(); sNamingScreen->state = STATE_WAIT_SENT_TO_PC_MESSAGE; return FALSE; } else { sNamingScreen->state = STATE_FADE_OUT; return TRUE; } } static bool8 MainState_FadeOut(void) { BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); sNamingScreen->state++; return FALSE; } static bool8 MainState_Exit(void) { if (!gPaletteFade.active) { if (sNamingScreen->templateNum == NAMING_SCREEN_PLAYER) SeedRngAndSetTrainerId(); SetMainCallback2(sNamingScreen->returnCallback); DestroyTask(FindTaskIdByFunc(Task_NamingScreen)); FreeAllWindowBuffers(); FREE_AND_SET_NULL(sNamingScreen); } return FALSE; } static void DisplaySentToPCMessage(void) { u8 stringToDisplay = 0; if (!IsDestinationBoxFull()) { StringCopy(gStringVar1, GetBoxNamePtr(VarGet(VAR_PC_BOX_TO_SEND_MON))); StringCopy(gStringVar2, sNamingScreen->destBuffer); } else { StringCopy(gStringVar1, GetBoxNamePtr(VarGet(VAR_PC_BOX_TO_SEND_MON))); StringCopy(gStringVar2, sNamingScreen->destBuffer); StringCopy(gStringVar3, GetBoxNamePtr(GetPCBoxToSendMon())); stringToDisplay = 2; } if (FlagGet(FLAG_SYS_PC_LANETTE)) stringToDisplay++; StringExpandPlaceholders(gStringVar4, sTransferredToPCMessages[stringToDisplay]); DrawDialogueFrame(0, 0); gTextFlags.canABSpeedUpPrint = TRUE; AddTextPrinterParameterized2(0, FONT_NORMAL, gStringVar4, GetPlayerTextSpeedDelay(), 0, 2, 1, 3); CopyWindowToVram(0, COPYWIN_FULL); } static bool8 MainState_WaitSentToPCMessage(void) { RunTextPrinters(); if (!IsTextPrinterActive(0) && JOY_NEW(A_BUTTON)) sNamingScreen->state = STATE_FADE_OUT; return FALSE; } static bool8 MainState_StartPageSwap(void) { SetInputState(INPUT_STATE_DISABLED); StartPageSwapButtonAnim(); StartPageSwapAnim(); SetCursorInvisibility(TRUE); TryStartButtonFlash(BUTTON_PAGE, FALSE, TRUE); PlaySE(SE_WIN_OPEN); sNamingScreen->state = STATE_WAIT_PAGE_SWAP; return FALSE; } static bool8 MainState_WaitPageSwap(void) { s16 cursorX; s16 cursorY; bool32 onLastColumn; if (IsPageSwapAnimNotInProgress()) { GetCursorPos(&cursorX, &cursorY); onLastColumn = (cursorX == GetCurrentPageColumnCount()); sNamingScreen->state = STATE_HANDLE_INPUT; sNamingScreen->currentPage++; sNamingScreen->currentPage %= KBPAGE_COUNT; if (onLastColumn) { cursorX = GetCurrentPageColumnCount(); } else { if (cursorX >= GetCurrentPageColumnCount()) cursorX = GetCurrentPageColumnCount() - 1; } SetCursorPos(cursorX, cursorY); DrawKeyboardPageOnDeck(); SetInputState(INPUT_STATE_ENABLED); SetCursorInvisibility(FALSE); } return FALSE; } //-------------------------------------------------- // Page Swap //-------------------------------------------------- #define tState data[0] #define tFrameCount data[1] static bool8 PageSwapAnimState_Init(struct Task *); static bool8 PageSwapAnimState_1(struct Task *); static bool8 PageSwapAnimState_2(struct Task *); static bool8 PageSwapAnimState_Done(struct Task *); static bool8 (*const sPageSwapAnimStateFuncs[])(struct Task *) = { PageSwapAnimState_Init, PageSwapAnimState_1, PageSwapAnimState_2, PageSwapAnimState_Done, }; static void StartPageSwapAnim(void) { u8 taskId; taskId = CreateTask(Task_HandlePageSwapAnim, 0); Task_HandlePageSwapAnim(taskId); } static void Task_HandlePageSwapAnim(u8 taskId) { while (sPageSwapAnimStateFuncs[gTasks[taskId].tState](&gTasks[taskId]) != 0); } static bool8 IsPageSwapAnimNotInProgress(void) { if (FindTaskIdByFunc(Task_HandlePageSwapAnim) == TASK_NONE) return TRUE; else return FALSE; } static bool8 PageSwapAnimState_Init(struct Task *task) { sNamingScreen->bg1vOffset = 0; sNamingScreen->bg2vOffset = 0; task->tState++; return 0; } static bool8 PageSwapAnimState_1(struct Task *task) { u16 *const vOffsets[] = { &sNamingScreen->bg2vOffset, &sNamingScreen->bg1vOffset }; task->tFrameCount += 4; *vOffsets[sNamingScreen->bgToReveal] = Sin(task->tFrameCount, 40); *vOffsets[sNamingScreen->bgToHide] = Sin((task->tFrameCount + 128) & 0xFF, 40); if (task->tFrameCount >= 64) { u8 temp = sNamingScreen->bg1Priority; //Why u8 and not u16? sNamingScreen->bg1Priority = sNamingScreen->bg2Priority; sNamingScreen->bg2Priority = temp; task->tState++; } return 0; } static bool8 PageSwapAnimState_2(struct Task *task) { u16 *const vOffsets[] = { &sNamingScreen->bg2vOffset, &sNamingScreen->bg1vOffset }; task->tFrameCount += 4; *vOffsets[sNamingScreen->bgToReveal] = Sin(task->tFrameCount, 40); *vOffsets[sNamingScreen->bgToHide] = Sin((task->tFrameCount + 128) & 0xFF, 40); if (task->tFrameCount >= 128) { u8 temp = sNamingScreen->bgToReveal; sNamingScreen->bgToReveal = sNamingScreen->bgToHide; sNamingScreen->bgToHide = temp; task->tState++; } return 0; } static bool8 PageSwapAnimState_Done(struct Task *task) { DestroyTask(FindTaskIdByFunc(Task_HandlePageSwapAnim)); return 0; } #undef tState #undef tFrameCount //-------------------------------------------------- // //-------------------------------------------------- #define tButtonId data[0] #define tKeepFlashing data[1] #define tAllowFlash data[2] #define tColor data[3] #define tColorIncr data[4] #define tColorDelay data[5] #define tColorDelta data[6] static void CreateButtonFlashTask(void) { u8 taskId; taskId = CreateTask(Task_UpdateButtonFlash, 3); gTasks[taskId].tButtonId = BUTTON_COUNT; } static void TryStartButtonFlash(u8 button, bool8 keepFlashing, bool8 interruptCurFlash) { struct Task *task = &gTasks[FindTaskIdByFunc(Task_UpdateButtonFlash)]; if (button == task->tButtonId && !interruptCurFlash) { task->tKeepFlashing = keepFlashing; task->tAllowFlash = TRUE; return; } if (button == BUTTON_COUNT && !task->tKeepFlashing && !interruptCurFlash) return; if (task->tButtonId != BUTTON_COUNT) RestoreButtonColor(task->tButtonId); StartButtonFlash(task, button, keepFlashing); } static void Task_UpdateButtonFlash(u8 taskId) { struct Task *task = &gTasks[taskId]; if (task->tButtonId == BUTTON_COUNT || !task->tAllowFlash) return; MultiplyInvertedPaletteRGBComponents(GetButtonPalOffset(task->tButtonId), task->tColor, task->tColor, task->tColor); if (task->tColorDelay && --task->tColorDelay) return; task->tColorDelay = 2; if (task->tColorIncr >= 0) { if (task->tColor < 14) { task->tColor += task->tColorIncr; task->tColorDelta += task->tColorIncr; } else { task->tColor = 16; task->tColorDelta++; } } else { task->tColor += task->tColorIncr; task->tColorDelta += task->tColorIncr; } if (task->tColor == 16 && task->tColorDelta == 22) { task->tColorIncr = -4; } else if (task->tColor == 0) { task->tAllowFlash = task->tKeepFlashing; task->tColorIncr = 2; task->tColorDelta = 0; } } static u16 GetButtonPalOffset(u8 button) { const u16 palOffsets[BUTTON_COUNT + 1] = { [BUTTON_PAGE] = IndexOfSpritePaletteTag(PALTAG_PAGE_SWAP) * 16 + 0x10E, [BUTTON_BACK] = IndexOfSpritePaletteTag(PALTAG_BACK_BUTTON) * 16 + 0x10E, [BUTTON_OK] = IndexOfSpritePaletteTag(PALTAG_OK_BUTTON) * 16 + 0x10E, [BUTTON_COUNT] = IndexOfSpritePaletteTag(PALTAG_OK_BUTTON) * 16 + 0x101, }; return palOffsets[button]; } static void RestoreButtonColor(u8 button) { u16 index = GetButtonPalOffset(button); gPlttBufferFaded[index] = gPlttBufferUnfaded[index]; } static void StartButtonFlash(struct Task *task, u8 button, bool8 keepFlashing) { task->tButtonId = button; task->tKeepFlashing = keepFlashing; task->tAllowFlash = TRUE; task->tColor = 4; task->tColorIncr = 2; task->tColorDelay = 0; task->tColorDelta = 4; } #undef tButtonId #undef tColor // Sprite data for the the cursor #define sX data[0] #define sY data[1] #define sPrevX data[2] #define sPrevY data[3] #define sInvisible data[4] & 0x00FF #define sFlashing data[4] & 0xFF00 #define sColor data[5] #define sColorIncr data[6] #define sColorDelay data[7] static void SpriteCB_Cursor(struct Sprite *sprite) { if (sprite->animEnded) StartSpriteAnim(sprite, 0); // Hide cursor when on button column sprite->invisible = sprite->sInvisible; if (sprite->sX == GetCurrentPageColumnCount()) sprite->invisible = TRUE; if (sprite->invisible || !(sprite->sFlashing) || sprite->sX != sprite->sPrevX || sprite->sY != sprite->sPrevY) { sprite->sColor = 0; sprite->sColorIncr = 2; sprite->sColorDelay = 2; } sprite->sColorDelay--; if (sprite->sColorDelay == 0) { sprite->sColor += sprite->sColorIncr; if (sprite->sColor == 16 || sprite->sColor == 0) sprite->sColorIncr = -sprite->sColorIncr; sprite->sColorDelay = 2; } if (sprite->sFlashing) { s8 gb = sprite->sColor; s8 r = sprite->sColor >> 1; u16 index = IndexOfSpritePaletteTag(PALTAG_CURSOR) * 16 + 0x0101; MultiplyInvertedPaletteRGBComponents(index, r, gb, gb); } } #define sDelay data[0] #define sXPosId data[1] static void SpriteCB_InputArrow(struct Sprite *sprite) { const s16 x[] = {0, -4, -2, -1}; if (sprite->sDelay == 0 || --sprite->sDelay == 0) { sprite->sDelay = 8; sprite->sXPosId = (sprite->sXPosId + 1) & (ARRAY_COUNT(x) - 1); } sprite->x2 = x[sprite->sXPosId]; } #undef sDelay #undef sXPosId #define sId data[0] // set in CreateTextEntrySprites #define sYPosId data[1] #define sDelay data[2] static void SpriteCB_Underscore(struct Sprite *sprite) { const s16 y[] = {2, 3, 2, 1}; u8 pos; pos = GetTextEntryPosition(); if (pos != (u8)sprite->sId) { sprite->y2 = 0; sprite->sYPosId = 0; sprite->sDelay = 0; } else { sprite->y2 = y[sprite->sYPosId]; sprite->sDelay++; if (sprite->sDelay > 8) { sprite->sYPosId = (sprite->sYPosId + 1) & (ARRAY_COUNT(y) - 1); sprite->sDelay = 0; } } } #undef sId #undef sYPosId #undef sDelay static void CreateSprites(void) { CreateCursorSprite(); CreatePageSwapButtonSprites(); CreateBackOkSprites(); CreateTextEntrySprites(); CreateInputTargetIcon(); } static void CreateCursorSprite(void) { sNamingScreen->cursorSpriteId = CreateSprite(&sSpriteTemplate_Cursor, 38, 88, 1); SetCursorInvisibility(TRUE); gSprites[sNamingScreen->cursorSpriteId].oam.priority = 1; gSprites[sNamingScreen->cursorSpriteId].oam.objMode = ST_OAM_OBJ_BLEND; gSprites[sNamingScreen->cursorSpriteId].sColorIncr = 1; // ? immediately overwritten gSprites[sNamingScreen->cursorSpriteId].sColorIncr = 2; SetCursorPos(0, 0); } static void SetCursorPos(s16 x, s16 y) { struct Sprite *cursorSprite = &gSprites[sNamingScreen->cursorSpriteId]; if (x < sPageColumnCounts[CurrentPageToKeyboardId()]) cursorSprite->x = sPageColumnXPos[x + CurrentPageToKeyboardId() * KBCOL_COUNT] + 38; else cursorSprite->x = 0; cursorSprite->y = y * 16 + 88; cursorSprite->sPrevX = cursorSprite->sX; cursorSprite->sPrevY = cursorSprite->sY; cursorSprite->sX = x; cursorSprite->sY = y; } static void GetCursorPos(s16 *x, s16 *y) { struct Sprite *cursorSprite = &gSprites[sNamingScreen->cursorSpriteId]; *x = cursorSprite->sX; *y = cursorSprite->sY; } static void MoveCursorToOKButton(void) { SetCursorPos(GetCurrentPageColumnCount(), 2); } static void SetCursorInvisibility(bool8 invisible) { gSprites[sNamingScreen->cursorSpriteId].data[4] &= 0xFF00; gSprites[sNamingScreen->cursorSpriteId].data[4] |= invisible; // sInvisible StartSpriteAnim(&gSprites[sNamingScreen->cursorSpriteId], 0); } static void SetCursorFlashing(bool8 flashing) { gSprites[sNamingScreen->cursorSpriteId].data[4] &= 0xFF; gSprites[sNamingScreen->cursorSpriteId].data[4] |= flashing << 8; // sFlashing } static void SquishCursor(void) { StartSpriteAnim(&gSprites[sNamingScreen->cursorSpriteId], 1); } static bool8 IsCursorAnimFinished(void) { return gSprites[sNamingScreen->cursorSpriteId].animEnded; } static const u8 sButtonKeyRoles[] = {KEY_ROLE_PAGE, KEY_ROLE_BACKSPACE, KEY_ROLE_OK}; static u8 GetKeyRoleAtCursorPos(void) { s16 cursorX; s16 cursorY; GetCursorPos(&cursorX, &cursorY); if (cursorX < GetCurrentPageColumnCount()) return KEY_ROLE_CHAR; else return sButtonKeyRoles[cursorY]; } // If the cursor's x is equal to the column count, cursor is in the button column static u8 GetCurrentPageColumnCount(void) { return sPageColumnCounts[CurrentPageToKeyboardId()]; } #undef sX #undef sY #undef sPrevX #undef sPrevY #undef sInvisible #undef sFlashing #undef sColor #undef sColorIncr #undef sColorDelay static bool8 PageSwapSprite_Init(struct Sprite *); static bool8 PageSwapSprite_Idle(struct Sprite *); static bool8 PageSwapSprite_SlideOff(struct Sprite *); static bool8 PageSwapSprite_SlideOn(struct Sprite *); #define sState data[0] #define sPage data[1] #define sTextSpriteId data[6] #define sButtonSpriteId data[7] static void CreatePageSwapButtonSprites(void) { u8 frameSpriteId; u8 textSpriteId; u8 buttonSpriteId; frameSpriteId = CreateSprite(&sSpriteTemplate_PageSwapFrame, 204, 88, 0); sNamingScreen->swapBtnFrameSpriteId = frameSpriteId; SetSubspriteTables(&gSprites[frameSpriteId], sSubspriteTable_PageSwapFrame); gSprites[frameSpriteId].invisible = TRUE; textSpriteId = CreateSprite(&sSpriteTemplate_PageSwapText, 204, 84, 1); gSprites[frameSpriteId].sTextSpriteId = textSpriteId; SetSubspriteTables(&gSprites[textSpriteId], sSubspriteTable_PageSwapText); gSprites[textSpriteId].invisible = TRUE; buttonSpriteId = CreateSprite(&sSpriteTemplate_PageSwapButton, 204, 83, 2); gSprites[buttonSpriteId].oam.priority = 1; gSprites[frameSpriteId].sButtonSpriteId = buttonSpriteId; gSprites[buttonSpriteId].invisible = TRUE; } static void StartPageSwapButtonAnim(void) { struct Sprite *sprite = &gSprites[sNamingScreen->swapBtnFrameSpriteId]; sprite->sState = 2; // go to PageSwapSprite_SlideOff sprite->sPage = sNamingScreen->currentPage; } static u8 (*const sPageSwapSpriteFuncs[])(struct Sprite *) = { PageSwapSprite_Init, PageSwapSprite_Idle, PageSwapSprite_SlideOff, PageSwapSprite_SlideOn, }; static void SpriteCB_PageSwap(struct Sprite *sprite) { while (sPageSwapSpriteFuncs[sprite->sState](sprite)); } static bool8 PageSwapSprite_Init(struct Sprite *sprite) { struct Sprite *text = &gSprites[sprite->sTextSpriteId]; struct Sprite *button = &gSprites[sprite->sButtonSpriteId]; SetPageSwapButtonGfx(PageToNextGfxId(sNamingScreen->currentPage), text, button); sprite->sState++; return FALSE; } static bool8 PageSwapSprite_Idle(struct Sprite *sprite) { return FALSE; } static bool8 PageSwapSprite_SlideOff(struct Sprite *sprite) { struct Sprite *text = &gSprites[sprite->sTextSpriteId]; struct Sprite *button = &gSprites[sprite->sButtonSpriteId]; text->y2++; if (text->y2 > 7) { sprite->sState++; text->y2 = -4; text->invisible = TRUE; SetPageSwapButtonGfx(PageToNextGfxId(((u8)sprite->sPage + 1) % KBPAGE_COUNT), text, button); } return FALSE; } static bool8 PageSwapSprite_SlideOn(struct Sprite *sprite) { struct Sprite *text = &gSprites[sprite->sTextSpriteId]; text->invisible = FALSE; text->y2++; if (text->y2 >= 0) { text->y2 = 0; sprite->sState = 1; // go to PageSwapSprite_Idle } return FALSE; } static const u16 sPageSwapPalTags[] = { [PAGE_SWAP_UPPER] = PALTAG_PAGE_SWAP_UPPER, [PAGE_SWAP_OTHERS] = PALTAG_PAGE_SWAP_OTHERS, [PAGE_SWAP_LOWER] = PALTAG_PAGE_SWAP_LOWER }; static const u16 sPageSwapGfxTags[] = { [PAGE_SWAP_UPPER] = GFXTAG_PAGE_SWAP_UPPER, [PAGE_SWAP_OTHERS] = GFXTAG_PAGE_SWAP_OTHERS, [PAGE_SWAP_LOWER] = GFXTAG_PAGE_SWAP_LOWER }; static void SetPageSwapButtonGfx(u8 page, struct Sprite *text, struct Sprite *button) { button->oam.paletteNum = IndexOfSpritePaletteTag(sPageSwapPalTags[page]); text->sheetTileStart = GetSpriteTileStartByTag(sPageSwapGfxTags[page]); text->subspriteTableNum = page; } #undef sState #undef sPage #undef sTextSpriteId #undef sButtonSpriteId static void CreateBackOkSprites(void) { u8 spriteId; spriteId = CreateSprite(&sSpriteTemplate_BackButton, 204, 116, 0); SetSubspriteTables(&gSprites[spriteId], sSubspriteTable_Button); gSprites[spriteId].invisible = TRUE; spriteId = CreateSprite(&sSpriteTemplate_OkButton, 204, 140, 0); SetSubspriteTables(&gSprites[spriteId], sSubspriteTable_Button); gSprites[spriteId].invisible = TRUE; } static void CreateTextEntrySprites(void) { u8 spriteId; s16 xPos; u8 i; xPos = sNamingScreen->inputCharBaseXPos - 5; spriteId = CreateSprite(&sSpriteTemplate_InputArrow, xPos, 56, 0); gSprites[spriteId].oam.priority = 3; gSprites[spriteId].invisible = TRUE; xPos = sNamingScreen->inputCharBaseXPos; for (i = 0; i < sNamingScreen->template->maxChars; i++, xPos += 8) { spriteId = CreateSprite(&sSpriteTemplate_Underscore, xPos + 3, 60, 0); gSprites[spriteId].oam.priority = 3; gSprites[spriteId].data[0] = i; gSprites[spriteId].invisible = TRUE; } } //-------------------------------------------------- // Icon creation (the thing you're naming or giving input to) //-------------------------------------------------- static void NamingScreen_NoIcon(void); static void NamingScreen_CreatePlayerIcon(void); static void NamingScreen_CreatePCIcon(void); static void NamingScreen_CreateMonIcon(void); static void NamingScreen_CreateWaldaDadIcon(void); static void (*const sIconFunctions[])(void) = { NamingScreen_NoIcon, NamingScreen_CreatePlayerIcon, NamingScreen_CreatePCIcon, NamingScreen_CreateMonIcon, NamingScreen_CreateWaldaDadIcon, }; static void CreateInputTargetIcon(void) { sIconFunctions[sNamingScreen->template->iconFunction](); } static void NamingScreen_NoIcon(void) { } static void NamingScreen_CreatePlayerIcon(void) { u8 rivalGfxId; u8 spriteId; rivalGfxId = GetRivalAvatarGraphicsIdByStateIdAndGender(0, sNamingScreen->monSpecies); spriteId = CreateObjectGraphicsSprite(rivalGfxId, SpriteCallbackDummy, 56, 37, 0); gSprites[spriteId].oam.priority = 3; StartSpriteAnim(&gSprites[spriteId], 4); } static void NamingScreen_CreatePCIcon(void) { u8 spriteId; spriteId = CreateSprite(&sSpriteTemplate_PCIcon, 56, 41, 0); SetSubspriteTables(&gSprites[spriteId], sSubspriteTable_PCIcon); gSprites[spriteId].oam.priority = 3; } static void NamingScreen_CreateMonIcon(void) { u8 spriteId; LoadMonIconPalettes(); spriteId = CreateMonIcon(sNamingScreen->monSpecies, SpriteCallbackDummy, 56, 40, 0, sNamingScreen->monPersonality, 1); gSprites[spriteId].oam.priority = 3; } static void NamingScreen_CreateWaldaDadIcon(void) { u8 spriteId; spriteId = CreateObjectGraphicsSprite(OBJ_EVENT_GFX_MAN_1, SpriteCallbackDummy, 56, 37, 0); gSprites[spriteId].oam.priority = 3; StartSpriteAnim(&gSprites[spriteId], 4); } //-------------------------------------------------- // Keyboard handling //-------------------------------------------------- static bool8 KeyboardKeyHandler_Character(u8); static bool8 KeyboardKeyHandler_Page(u8); static bool8 KeyboardKeyHandler_Backspace(u8); static bool8 KeyboardKeyHandler_OK(u8); static bool8 (*const sKeyboardKeyHandlers[])(u8) = { [KEY_ROLE_CHAR] = KeyboardKeyHandler_Character, [KEY_ROLE_PAGE] = KeyboardKeyHandler_Page, [KEY_ROLE_BACKSPACE] = KeyboardKeyHandler_Backspace, [KEY_ROLE_OK] = KeyboardKeyHandler_OK, }; static bool8 HandleKeyboardEvent(void) { u8 input = GetInputEvent(); u8 keyRole = GetKeyRoleAtCursorPos(); if (input == INPUT_SELECT) { return SwapKeyboardPage(); } else if (input == INPUT_B_BUTTON) { DeleteTextCharacter(); return FALSE; } else if (input == INPUT_START) { MoveCursorToOKButton(); return FALSE; } else { return sKeyboardKeyHandlers[keyRole](input); } } static bool8 KeyboardKeyHandler_Character(u8 input) { TryStartButtonFlash(BUTTON_COUNT, FALSE, FALSE); if (input == INPUT_A_BUTTON) { bool8 textFull = AddTextCharacter(); if (sNamingScreen ->currentPage == KBPAGE_LETTERS_UPPER && GetTextEntryPosition() == 1) MainState_StartPageSwap(); SquishCursor(); if (textFull) { SetInputState(INPUT_STATE_OVERRIDE); sNamingScreen->state = STATE_MOVE_TO_OK_BUTTON; } } return FALSE; } static bool8 KeyboardKeyHandler_Page(u8 input) { TryStartButtonFlash(BUTTON_PAGE, TRUE, FALSE); if (input == INPUT_A_BUTTON) return SwapKeyboardPage(); else return FALSE; } static bool8 KeyboardKeyHandler_Backspace(u8 input) { TryStartButtonFlash(BUTTON_BACK, TRUE, FALSE); if (input == INPUT_A_BUTTON) DeleteTextCharacter(); return FALSE; } static bool8 KeyboardKeyHandler_OK(u8 input) { TryStartButtonFlash(BUTTON_OK, TRUE, FALSE); if (input == INPUT_A_BUTTON) { PlaySE(SE_SELECT); sNamingScreen->state = STATE_PRESSED_OK; return TRUE; } else return FALSE; } static bool8 SwapKeyboardPage(void) { sNamingScreen->state = STATE_START_PAGE_SWAP; return TRUE; } //-------------------------------------------------- // Input handling //-------------------------------------------------- #define tState data[0] #define tKeyboardEvent data[1] #define tButtonId data[2] static void Input_Disabled(struct Task *); static void Input_Enabled(struct Task *); static void Input_Override(struct Task *); static void (*const sInputFuncs[])(struct Task *) = { [INPUT_STATE_DISABLED] = Input_Disabled, [INPUT_STATE_ENABLED] = Input_Enabled, [INPUT_STATE_OVERRIDE] = Input_Override, }; static void Task_HandleInput(u8); static void HandleDpadMovement(struct Task *); static void CreateInputHandlerTask(void) { CreateTask(Task_HandleInput, 1); } static u8 GetInputEvent(void) { u8 taskId = FindTaskIdByFunc(Task_HandleInput); return gTasks[taskId].tKeyboardEvent; } static void SetInputState(u8 state) { u8 taskId = FindTaskIdByFunc(Task_HandleInput); gTasks[taskId].tState = state; } static void Task_HandleInput(u8 taskId) { sInputFuncs[gTasks[taskId].tState](&gTasks[taskId]); } static void Input_Disabled(struct Task *task) { task->tKeyboardEvent = INPUT_NONE; } static void Input_Enabled(struct Task *task) { task->tKeyboardEvent = INPUT_NONE; if (JOY_NEW(A_BUTTON)) task->tKeyboardEvent = INPUT_A_BUTTON; else if (JOY_NEW(B_BUTTON)) task->tKeyboardEvent = INPUT_B_BUTTON; else if (JOY_NEW(SELECT_BUTTON)) task->tKeyboardEvent = INPUT_SELECT; else if (JOY_NEW(START_BUTTON)) task->tKeyboardEvent = INPUT_START; else HandleDpadMovement(task); } static void Input_Override(struct Task *task) { task->tKeyboardEvent = INPUT_NONE; } static void HandleDpadMovement(struct Task *task) { const s16 sDpadDeltaX[] = { [INPUT_NONE] = 0, [INPUT_DPAD_UP] = 0, [INPUT_DPAD_DOWN] = 0, [INPUT_DPAD_LEFT] = -1, [INPUT_DPAD_RIGHT] = 1 }; const s16 sDpadDeltaY[] = { [INPUT_NONE] = 0, [INPUT_DPAD_UP] = -1, [INPUT_DPAD_DOWN] = 1, [INPUT_DPAD_LEFT] = 0, [INPUT_DPAD_RIGHT] = 0 }; const s16 sKeyRowToButtonRow[KBROW_COUNT] = {0, 1, 1, 2}; const s16 sButtonRowToKeyRow[BUTTON_COUNT] = {0, 0, 3}; s16 cursorX; s16 cursorY; u16 input; s16 prevCursorX; GetCursorPos(&cursorX, &cursorY); input = INPUT_NONE; if (JOY_REPEAT(DPAD_UP)) input = INPUT_DPAD_UP; if (JOY_REPEAT(DPAD_DOWN)) input = INPUT_DPAD_DOWN; if (JOY_REPEAT(DPAD_LEFT)) input = INPUT_DPAD_LEFT; if (JOY_REPEAT(DPAD_RIGHT)) input = INPUT_DPAD_RIGHT; // Get new cursor position prevCursorX = cursorX; cursorX += sDpadDeltaX[input]; cursorY += sDpadDeltaY[input]; // Wrap cursor position in the X direction if (cursorX < 0) cursorX = GetCurrentPageColumnCount(); if (cursorX > GetCurrentPageColumnCount()) cursorX = 0; // Handle moving on/off the button column if (sDpadDeltaX[input] != 0) { if (cursorX == GetCurrentPageColumnCount()) { // Moved onto button column // Save cursor pos in tButtonId for moving back onto keys task->tButtonId = cursorY; cursorY = sKeyRowToButtonRow[cursorY]; } else if (prevCursorX == GetCurrentPageColumnCount()) { // Moved off button column // If you're on the middle button, go to the row that // the cursor was on previously (saved in tButtonId above) if (cursorY == BUTTON_COUNT / 2) cursorY = task->tButtonId; else cursorY = sButtonRowToKeyRow[cursorY]; } } // Wrap cursor position in the y direction if (cursorX == GetCurrentPageColumnCount()) { // There are only 3 keys in the button column // so wrap Y accordingly if (cursorY < 0) cursorY = BUTTON_COUNT - 1; if (cursorY >= BUTTON_COUNT) cursorY = 0; if (cursorY == 0) task->tButtonId = BUTTON_BACK; else if (cursorY == BUTTON_COUNT - 1) task->tButtonId = BUTTON_OK; } else { if (cursorY < 0) cursorY = KBROW_COUNT - 1; if (cursorY > KBROW_COUNT - 1) cursorY = 0; } SetCursorPos(cursorX, cursorY); } #undef tState #undef tKeyboardEvent #undef tButtonId static void DrawNormalTextEntryBox(void) { FillWindowPixelBuffer(sNamingScreen->windows[WIN_TEXT_ENTRY_BOX], PIXEL_FILL(1)); AddTextPrinterParameterized(sNamingScreen->windows[WIN_TEXT_ENTRY_BOX], FONT_NORMAL, sNamingScreen->template->title, 8, 1, 0, 0); PutWindowTilemap(sNamingScreen->windows[WIN_TEXT_ENTRY_BOX]); } static void DrawMonTextEntryBox(void) { u8 buffer[32]; StringCopy(buffer, gSpeciesNames[sNamingScreen->monSpecies]); StringAppendN(buffer, sNamingScreen->template->title, 15); FillWindowPixelBuffer(sNamingScreen->windows[WIN_TEXT_ENTRY_BOX], PIXEL_FILL(1)); AddTextPrinterParameterized(sNamingScreen->windows[WIN_TEXT_ENTRY_BOX], FONT_NORMAL, buffer, 8, 1, 0, 0); PutWindowTilemap(sNamingScreen->windows[WIN_TEXT_ENTRY_BOX]); } static void (*const sDrawTextEntryBoxFuncs[])(void) = { [NAMING_SCREEN_PLAYER] = DrawNormalTextEntryBox, [NAMING_SCREEN_BOX] = DrawNormalTextEntryBox, [NAMING_SCREEN_CAUGHT_MON] = DrawMonTextEntryBox, [NAMING_SCREEN_NICKNAME] = DrawMonTextEntryBox, [NAMING_SCREEN_WALDA] = DrawNormalTextEntryBox, }; static void DrawTextEntryBox(void) { sDrawTextEntryBoxFuncs[sNamingScreen->templateNum](); } static void DummyGenderIcon(void); static void DrawGenderIcon(void); static void (*const sDrawGenderIconFuncs[])(void) = { [FALSE] = DummyGenderIcon, [TRUE] = DrawGenderIcon, }; static void TryDrawGenderIcon(void) { sDrawGenderIconFuncs[sNamingScreen->template->addGenderIcon](); } static void DummyGenderIcon(void) { } static const u8 sGenderColors[2][3] = { {TEXT_COLOR_TRANSPARENT, TEXT_COLOR_LIGHT_BLUE, TEXT_COLOR_BLUE}, {TEXT_COLOR_TRANSPARENT, TEXT_COLOR_LIGHT_RED, TEXT_COLOR_RED} }; static void DrawGenderIcon(void) { u8 text[2]; bool8 isFemale = FALSE; StringCopy(text, gText_MaleSymbol); if (sNamingScreen->monGender != MON_GENDERLESS) { if (sNamingScreen->monGender == MON_FEMALE) { StringCopy(text, gText_FemaleSymbol); isFemale = TRUE; } AddTextPrinterParameterized3(sNamingScreen->windows[WIN_TEXT_ENTRY], FONT_NORMAL, 0x68, 1, sGenderColors[isFemale], TEXT_SKIP_DRAW, text); } } static u8 GetCharAtKeyboardPos(s16 x, s16 y) { return sKeyboardChars[CurrentPageToKeyboardId()][y][x]; } static u8 GetTextEntryPosition(void) { u8 i; for (i = 0; i < sNamingScreen->template->maxChars; i++) { if (sNamingScreen->textBuffer[i] == EOS) return i; } return sNamingScreen->template->maxChars - 1; } static u8 GetPreviousTextCaretPosition(void) { s8 i; for (i = sNamingScreen->template->maxChars - 1; i > 0; i--) { if (sNamingScreen->textBuffer[i] != EOS) return i; } return 0; } static void DeleteTextCharacter(void) { u8 index; u8 keyRole; index = GetPreviousTextCaretPosition(); sNamingScreen->textBuffer[index] = 0; DrawTextEntry(); CopyBgTilemapBufferToVram(3); sNamingScreen->textBuffer[index] = EOS; keyRole = GetKeyRoleAtCursorPos(); // The below flashes the Back key once on delete // It incorrectly leaves the Back key 1 shade lighter than its default if (keyRole == KEY_ROLE_CHAR || keyRole == KEY_ROLE_BACKSPACE) TryStartButtonFlash(BUTTON_BACK, FALSE, TRUE); PlaySE(SE_BALL); } // Returns TRUE if the text entry is now full static bool8 AddTextCharacter(void) { s16 x; s16 y; GetCursorPos(&x, &y); BufferCharacter(GetCharAtKeyboardPos(x, y)); DrawTextEntry(); CopyBgTilemapBufferToVram(3); PlaySE(SE_SELECT); if (GetPreviousTextCaretPosition() != sNamingScreen->template->maxChars - 1) return FALSE; else return TRUE; } static void BufferCharacter(u8 ch) { u8 index = GetTextEntryPosition(); sNamingScreen->textBuffer[index] = ch; } static void SaveInputText(void) { u8 i; for (i = 0; i < sNamingScreen->template->maxChars; i++) { if (sNamingScreen->textBuffer[i] != CHAR_SPACE && sNamingScreen->textBuffer[i] != EOS) { StringCopyN(sNamingScreen->destBuffer, sNamingScreen->textBuffer, sNamingScreen->template->maxChars + 1); break; } } } static void LoadGfx(void) { LZ77UnCompWram(gNamingScreenMenu_Gfx, sNamingScreen->tileBuffer); LoadBgTiles(1, sNamingScreen->tileBuffer, sizeof(sNamingScreen->tileBuffer), 0); LoadBgTiles(2, sNamingScreen->tileBuffer, sizeof(sNamingScreen->tileBuffer), 0); LoadBgTiles(3, sNamingScreen->tileBuffer, sizeof(sNamingScreen->tileBuffer), 0); LoadSpriteSheets(sSpriteSheets); LoadSpritePalettes(sSpritePalettes); } static void CreateHelperTasks(void) { CreateInputHandlerTask(); CreateButtonFlashTask(); } static void LoadPalettes(void) { LoadPalette(gNamingScreenMenu_Pal, 0, 0xC0); LoadPalette(sKeyboard_Pal, 0xA0, sizeof(sKeyboard_Pal)); LoadPalette(GetTextWindowPalette(2), 0xB0, 0x20); } static void DrawBgTilemap(u8 bg, const void *src) { CopyToBgTilemapBuffer(bg, src, 0, 0); } static void NamingScreen_Dummy(u8 bg, u8 page) { } static void DrawTextEntry(void) { u8 i; u8 temp[2]; u16 extraWidth; u8 maxChars = sNamingScreen->template->maxChars; u16 x = sNamingScreen->inputCharBaseXPos - 0x40; FillWindowPixelBuffer(sNamingScreen->windows[WIN_TEXT_ENTRY], PIXEL_FILL(1)); for (i = 0; i < maxChars; i++) { temp[0] = sNamingScreen->textBuffer[i]; temp[1] = gText_ExpandedPlaceholder_Empty[0]; extraWidth = (IsWideLetter(temp[0]) == TRUE) ? 2 : 0; AddTextPrinterParameterized(sNamingScreen->windows[WIN_TEXT_ENTRY], FONT_NORMAL, temp, i * 8 + x + extraWidth, 1, TEXT_SKIP_DRAW, NULL); } TryDrawGenderIcon(); CopyWindowToVram(sNamingScreen->windows[WIN_TEXT_ENTRY], COPYWIN_GFX); PutWindowTilemap(sNamingScreen->windows[WIN_TEXT_ENTRY]); } struct TextColor // Needed because of alignment { u8 colors[3][4]; }; static const struct TextColor sTextColorStruct = { { {TEXT_DYNAMIC_COLOR_4, TEXT_COLOR_WHITE, TEXT_COLOR_DARK_GRAY}, {TEXT_DYNAMIC_COLOR_5, TEXT_COLOR_WHITE, TEXT_COLOR_DARK_GRAY}, {TEXT_DYNAMIC_COLOR_6, TEXT_COLOR_WHITE, TEXT_COLOR_DARK_GRAY} } }; static const u8 sFillValues[KBPAGE_COUNT] = { [KEYBOARD_LETTERS_LOWER] = PIXEL_FILL(14), [KEYBOARD_LETTERS_UPPER] = PIXEL_FILL(13), [KEYBOARD_SYMBOLS] = PIXEL_FILL(15) }; static const u8 *const sKeyboardTextColors[KBPAGE_COUNT] = { [KEYBOARD_LETTERS_LOWER] = sTextColorStruct.colors[1], [KEYBOARD_LETTERS_UPPER] = sTextColorStruct.colors[0], [KEYBOARD_SYMBOLS] = sTextColorStruct.colors[2] }; static void PrintKeyboardKeys(u8 window, u8 page) { u8 i; FillWindowPixelBuffer(window, sFillValues[page]); for (i = 0; i < KBROW_COUNT; i++) AddTextPrinterParameterized3(window, FONT_NORMAL, 0, i * 16 + 1, sKeyboardTextColors[page], 0, sNamingScreenKeyboardText[page][i]); PutWindowTilemap(window); } static const u8 *const sNextKeyboardPageTilemaps[] = { [KBPAGE_SYMBOLS] = gNamingScreenKeyboardUpper_Tilemap, [KBPAGE_LETTERS_UPPER] = gNamingScreenKeyboardLower_Tilemap, // lower [KBPAGE_LETTERS_LOWER] = gNamingScreenKeyboardSymbols_Tilemap // symbols }; // There are always 2 keyboard pages drawn, the current page and the one that will shown next if the player swaps // When the page swap is complete this function invisibly replaces the old page with the new next one static void DrawKeyboardPageOnDeck(void) { u8 bg; u8 bg_; u8 windowId; u8 bg1Priority = GetGpuReg(REG_OFFSET_BG1CNT) & 3; u8 bg2Priority = GetGpuReg(REG_OFFSET_BG2CNT) & 3; if (bg1Priority > bg2Priority) { bg = 1; bg_ = 1; windowId = sNamingScreen->windows[WIN_KB_PAGE_1]; } else { bg = 2; bg_ = 2; windowId = sNamingScreen->windows[WIN_KB_PAGE_2]; } DrawBgTilemap(bg, sNextKeyboardPageTilemaps[sNamingScreen->currentPage]); PrintKeyboardKeys(windowId, CurrentPageToNextKeyboardId()); NamingScreen_Dummy(bg, CurrentPageToNextKeyboardId()); CopyBgTilemapBufferToVram(bg_); } static void PrintControls(void) { const u8 color[3] = { TEXT_DYNAMIC_COLOR_6, TEXT_COLOR_WHITE, TEXT_COLOR_DARK_GRAY }; FillWindowPixelBuffer(sNamingScreen->windows[WIN_BANNER], PIXEL_FILL(15)); AddTextPrinterParameterized3(sNamingScreen->windows[WIN_BANNER], FONT_SMALL, 2, 1, color, 0, gText_MoveOkBack); PutWindowTilemap(sNamingScreen->windows[WIN_BANNER]); CopyWindowToVram(sNamingScreen->windows[WIN_BANNER], COPYWIN_FULL); } static void CB2_NamingScreen(void) { RunTasks(); AnimateSprites(); BuildOamBuffer(); UpdatePaletteFade(); } static void ResetVHBlank(void) { SetVBlankCallback(NULL); SetHBlankCallback(NULL); } static void SetVBlank(void) { SetVBlankCallback(VBlankCB_NamingScreen); } static void VBlankCB_NamingScreen(void) { LoadOam(); ProcessSpriteCopyRequests(); TransferPlttBuffer(); SetGpuReg(REG_OFFSET_BG1VOFS, sNamingScreen->bg1vOffset); SetGpuReg(REG_OFFSET_BG2VOFS, sNamingScreen->bg2vOffset); SetGpuReg(REG_OFFSET_BG1CNT, GetGpuReg(REG_OFFSET_BG1CNT) & 0xFFFC); SetGpuRegBits(REG_OFFSET_BG1CNT, sNamingScreen->bg1Priority); SetGpuReg(REG_OFFSET_BG2CNT, GetGpuReg(REG_OFFSET_BG2CNT) & 0xFFFC); SetGpuRegBits(REG_OFFSET_BG2CNT, sNamingScreen->bg2Priority); } static void NamingScreen_ShowBgs(void) { ShowBg(0); ShowBg(1); ShowBg(2); ShowBg(3); } // Always false (presumably for non-latin languages) static bool8 IsWideLetter(u8 character) { u8 i; for (i = 0; sText_AlphabetUpperLower[i] != EOS; i++) { if (character == sText_AlphabetUpperLower[i]) return FALSE; } return FALSE; } // Debug? Unused, and arguments aren't sensible for non-player screens. static void Debug_NamingScreenPlayer(void) { DoNamingScreen(NAMING_SCREEN_PLAYER, gSaveBlock2Ptr->playerName, gSaveBlock2Ptr->playerGender, 0, 0, CB2_ReturnToFieldWithOpenMenu); } static void Debug_NamingScreenBox(void) { DoNamingScreen(NAMING_SCREEN_BOX, gSaveBlock2Ptr->playerName, gSaveBlock2Ptr->playerGender, 0, 0, CB2_ReturnToFieldWithOpenMenu); } static void Debug_NamingScreenCaughtMon(void) { DoNamingScreen(NAMING_SCREEN_CAUGHT_MON, gSaveBlock2Ptr->playerName, gSaveBlock2Ptr->playerGender, 0, 0, CB2_ReturnToFieldWithOpenMenu); } static void Debug_NamingScreenNickname(void) { DoNamingScreen(NAMING_SCREEN_NICKNAME, gSaveBlock2Ptr->playerName, gSaveBlock2Ptr->playerGender, 0, 0, CB2_ReturnToFieldWithOpenMenu); } //-------------------------------------------------- // Forward-declared variables //-------------------------------------------------- // Initial pages below are pointless, they're overwritten with KBPAGE_LETTERS_UPPER in MainState_FadeIn() static const struct NamingScreenTemplate sPlayerNamingScreenTemplate = { .copyExistingString = FALSE, .maxChars = PLAYER_NAME_LENGTH, .iconFunction = 1, .addGenderIcon = FALSE, .initialPage = KBPAGE_LETTERS_UPPER, .unused = 35, .title = gText_YourName, }; static const struct NamingScreenTemplate sPCBoxNamingTemplate = { .copyExistingString = FALSE, .maxChars = BOX_NAME_LENGTH, .iconFunction = 2, .addGenderIcon = FALSE, .initialPage = KBPAGE_LETTERS_UPPER, .unused = 19, .title = gText_BoxName, }; static const struct NamingScreenTemplate sMonNamingScreenTemplate = { .copyExistingString = FALSE, .maxChars = POKEMON_NAME_LENGTH, .iconFunction = 3, .addGenderIcon = TRUE, .initialPage = KBPAGE_LETTERS_UPPER, .unused = 35, .title = gText_PkmnsNickname, }; static const struct NamingScreenTemplate sWaldaWordsScreenTemplate = { .copyExistingString = TRUE, .maxChars = WALDA_PHRASE_LENGTH, .iconFunction = 4, .addGenderIcon = FALSE, .initialPage = KBPAGE_LETTERS_UPPER, .unused = 11, .title = gText_TellHimTheWords, }; static const struct NamingScreenTemplate *const sNamingScreenTemplates[] = { [NAMING_SCREEN_PLAYER] = &sPlayerNamingScreenTemplate, [NAMING_SCREEN_BOX] = &sPCBoxNamingTemplate, [NAMING_SCREEN_CAUGHT_MON] = &sMonNamingScreenTemplate, [NAMING_SCREEN_NICKNAME] = &sMonNamingScreenTemplate, [NAMING_SCREEN_WALDA] = &sWaldaWordsScreenTemplate, }; static const struct OamData sOam_8x8 = { .y = 0, .affineMode = ST_OAM_AFFINE_OFF, .objMode = ST_OAM_OBJ_NORMAL, .bpp = ST_OAM_4BPP, .shape = SPRITE_SHAPE(8x8), .x = 0, .size = SPRITE_SIZE(8x8), .tileNum = 0, .priority = 0, .paletteNum = 0, }; static const struct OamData sOam_16x16 = { .y = 0, .affineMode = ST_OAM_AFFINE_OFF, .objMode = ST_OAM_OBJ_NORMAL, .bpp = ST_OAM_4BPP, .shape = SPRITE_SHAPE(16x16), .x = 0, .size = SPRITE_SIZE(16x16), .tileNum = 0, .priority = 0, .paletteNum = 0, }; static const struct OamData sOam_32x16 = { .y = 0, .affineMode = ST_OAM_AFFINE_OFF, .objMode = ST_OAM_OBJ_NORMAL, .bpp = ST_OAM_4BPP, .shape = SPRITE_SHAPE(32x16), .x = 0, .size = SPRITE_SIZE(32x16), .tileNum = 0, .priority = 0, .paletteNum = 0, }; static const struct Subsprite sSubsprites_PageSwapFrame[] = { { .x = -20, .y = -16, .shape = SPRITE_SHAPE(32x8), .size = SPRITE_SIZE(32x8), .tileOffset = 0, .priority = 1 }, { .x = 12, .y = -16, .shape = SPRITE_SHAPE(8x8), .size = SPRITE_SIZE(8x8), .tileOffset = 4, .priority = 1 }, { .x = -20, .y = -8, .shape = SPRITE_SHAPE(32x8), .size = SPRITE_SIZE(32x8), .tileOffset = 5, .priority = 1 }, { .x = 12, .y = -8, .shape = SPRITE_SHAPE(8x8), .size = SPRITE_SIZE(8x8), .tileOffset = 9, .priority = 1 }, { .x = -20, .y = 0, .shape = SPRITE_SHAPE(32x8), .size = SPRITE_SIZE(32x8), .tileOffset = 10, .priority = 1 }, { .x = 12, .y = 0, .shape = SPRITE_SHAPE(8x8), .size = SPRITE_SIZE(8x8), .tileOffset = 14, .priority = 1 }, { .x = -20, .y = 8, .shape = SPRITE_SHAPE(32x8), .size = SPRITE_SIZE(32x8), .tileOffset = 15, .priority = 1 }, { .x = 12, .y = 8, .shape = SPRITE_SHAPE(8x8), .size = SPRITE_SIZE(8x8), .tileOffset = 19, .priority = 1 } }; static const struct Subsprite sSubsprites_PageSwapText[] = { { .x = -12, .y = -4, .shape = SPRITE_SHAPE(16x8), .size = SPRITE_SIZE(16x8), .tileOffset = 0, .priority = 1 }, { .x = 4, .y = -4, .shape = SPRITE_SHAPE(8x8), .size = SPRITE_SIZE(8x8), .tileOffset = 2, .priority = 1 } }; static const struct Subsprite sSubsprites_Button[] = { { .x = -20, .y = -12, .shape = SPRITE_SHAPE(32x8), .size = SPRITE_SIZE(32x8), .tileOffset = 0, .priority = 1 }, { .x = 12, .y = -12, .shape = SPRITE_SHAPE(8x8), .size = SPRITE_SIZE(8x8), .tileOffset = 4, .priority = 1 }, { .x = -20, .y = -4, .shape = SPRITE_SHAPE(32x8), .size = SPRITE_SIZE(32x8), .tileOffset = 5, .priority = 1 }, { .x = 12, .y = -4, .shape = SPRITE_SHAPE(8x8), .size = SPRITE_SIZE(8x8), .tileOffset = 9, .priority = 1 }, { .x = -20, .y = 4, .shape = SPRITE_SHAPE(32x8), .size = SPRITE_SIZE(32x8), .tileOffset = 10, .priority = 1 }, { .x = 12, .y = 4, .shape = SPRITE_SHAPE(8x8), .size = SPRITE_SIZE(8x8), .tileOffset = 14, .priority = 1 } }; static const struct Subsprite sSubsprites_PCIcon[] = { { .x = -8, .y = -12, .shape = SPRITE_SHAPE(16x8), .size = SPRITE_SIZE(16x8), .tileOffset = 0, .priority = 3 }, { .x = -8, .y = -4, .shape = SPRITE_SHAPE(16x8), .size = SPRITE_SIZE(16x8), .tileOffset = 2, .priority = 3 }, { .x = -8, .y = 4, .shape = SPRITE_SHAPE(16x8), .size = SPRITE_SIZE(16x8), .tileOffset = 4, .priority = 3 } }; static const struct SubspriteTable sSubspriteTable_PageSwapFrame[] = { {ARRAY_COUNT(sSubsprites_PageSwapFrame), sSubsprites_PageSwapFrame} }; static const struct SubspriteTable sSubspriteTable_PageSwapText[] = { {ARRAY_COUNT(sSubsprites_PageSwapText), sSubsprites_PageSwapText}, {ARRAY_COUNT(sSubsprites_PageSwapText), sSubsprites_PageSwapText}, {ARRAY_COUNT(sSubsprites_PageSwapText), sSubsprites_PageSwapText} }; static const struct SubspriteTable sSubspriteTable_Button[] = { {ARRAY_COUNT(sSubsprites_Button), sSubsprites_Button} }; static const struct SubspriteTable sSubspriteTable_PCIcon[] = { {ARRAY_COUNT(sSubsprites_PCIcon), sSubsprites_PCIcon} }; static const struct SpriteFrameImage sImageTable_PCIcon[] = { {sPCIconOff_Gfx, sizeof(sPCIconOff_Gfx)}, {sPCIconOn_Gfx, sizeof(sPCIconOn_Gfx)}, }; static const union AnimCmd sAnim_Loop[] = { ANIMCMD_FRAME(0, 1), ANIMCMD_JUMP(0) }; static const union AnimCmd sAnim_CursorSquish[] = { ANIMCMD_FRAME(4, 8), ANIMCMD_FRAME(8, 8), ANIMCMD_END }; static const union AnimCmd sAnim_PCIcon[] = { ANIMCMD_FRAME(0, 2), ANIMCMD_FRAME(1, 2), ANIMCMD_JUMP(0) }; static const union AnimCmd *const sAnims_Loop[] = { sAnim_Loop }; static const union AnimCmd *const sAnims_Cursor[] = { sAnim_Loop, sAnim_CursorSquish }; static const union AnimCmd *const sAnims_PCIcon[] = { sAnim_PCIcon }; static const struct SpriteTemplate sSpriteTemplate_PageSwapFrame = { .tileTag = GFXTAG_PAGE_SWAP_FRAME, .paletteTag = PALTAG_PAGE_SWAP, .oam = &sOam_8x8, .anims = sAnims_Loop, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCB_PageSwap }; static const struct SpriteTemplate sSpriteTemplate_PageSwapButton = { .tileTag = GFXTAG_PAGE_SWAP_BUTTON, .paletteTag = PALTAG_PAGE_SWAP_UPPER, .oam = &sOam_32x16, .anims = sAnims_Loop, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCallbackDummy }; static const struct SpriteTemplate sSpriteTemplate_PageSwapText = { .tileTag = GFXTAG_PAGE_SWAP_UPPER, .paletteTag = PALTAG_PAGE_SWAP, .oam = &sOam_8x8, .anims = sAnims_Loop, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCallbackDummy }; static const struct SpriteTemplate sSpriteTemplate_BackButton = { .tileTag = GFXTAG_BACK_BUTTON, .paletteTag = PALTAG_BACK_BUTTON, .oam = &sOam_8x8, .anims = sAnims_Loop, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCallbackDummy }; static const struct SpriteTemplate sSpriteTemplate_OkButton = { .tileTag = GFXTAG_OK_BUTTON, .paletteTag = PALTAG_OK_BUTTON, .oam = &sOam_8x8, .anims = sAnims_Loop, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCallbackDummy }; static const struct SpriteTemplate sSpriteTemplate_Cursor = { .tileTag = GFXTAG_CURSOR, .paletteTag = PALTAG_CURSOR, .oam = &sOam_16x16, .anims = sAnims_Cursor, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCB_Cursor }; static const struct SpriteTemplate sSpriteTemplate_InputArrow = { .tileTag = GFXTAG_INPUT_ARROW, .paletteTag = PALTAG_PAGE_SWAP_OTHERS, .oam = &sOam_8x8, .anims = sAnims_Loop, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCB_InputArrow }; static const struct SpriteTemplate sSpriteTemplate_Underscore = { .tileTag = GFXTAG_UNDERSCORE, .paletteTag = PALTAG_PAGE_SWAP_OTHERS, .oam = &sOam_8x8, .anims = sAnims_Loop, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCB_Underscore }; static const struct SpriteTemplate sSpriteTemplate_PCIcon = { .tileTag = TAG_NONE, .paletteTag = PALTAG_PC_ICON, .oam = &sOam_8x8, .anims = sAnims_PCIcon, .images = sImageTable_PCIcon, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCallbackDummy }; static const u8* const sNamingScreenKeyboardText[KBPAGE_COUNT][KBROW_COUNT] = { [KEYBOARD_LETTERS_LOWER] = { gText_NamingScreenKeyboard_abcdef, gText_NamingScreenKeyboard_ghijkl, gText_NamingScreenKeyboard_mnopqrs, gText_NamingScreenKeyboard_tuvwxyz }, [KEYBOARD_LETTERS_UPPER] = { gText_NamingScreenKeyboard_ABCDEF, gText_NamingScreenKeyboard_GHIJKL, gText_NamingScreenKeyboard_MNOPQRS, gText_NamingScreenKeyboard_TUVWXYZ }, [KEYBOARD_SYMBOLS] = { gText_NamingScreenKeyboard_01234, gText_NamingScreenKeyboard_56789, gText_NamingScreenKeyboard_Symbols1, gText_NamingScreenKeyboard_Symbols2 }, }; static const struct SpriteSheet sSpriteSheets[] = { {gNamingScreenRWindow_Gfx + 0x280, 0x1E0, GFXTAG_BACK_BUTTON}, {gNamingScreenRWindow_Gfx + 0x460, 0x1E0, GFXTAG_OK_BUTTON}, {gNamingScreenRWindow_Gfx, 0x280, GFXTAG_PAGE_SWAP_FRAME}, {gNamingScreenPageButton_Gfx + 0x20, 0x100, GFXTAG_PAGE_SWAP_BUTTON}, {gNamingScreenROptions_Gfx, 0x060, GFXTAG_PAGE_SWAP_UPPER}, {gNamingScreenROptions_Gfx + 0xA0, 0x060, GFXTAG_PAGE_SWAP_LOWER}, {gNamingScreenROptions_Gfx + 0x140, 0x060, GFXTAG_PAGE_SWAP_OTHERS}, {gNamingScreenCursor_Gfx, 0x080, GFXTAG_CURSOR}, {gNamingScreenCursor_Gfx + 0xA0, 0x080, GFXTAG_CURSOR_SQUISHED}, {gNamingScreenCursor_Gfx + 0x140, 0x080, GFXTAG_CURSOR_FILLED}, {gNamingScreenInputArrow_Gfx, 0x020, GFXTAG_INPUT_ARROW}, {gNamingScreenUnderscore_Gfx, 0x020, GFXTAG_UNDERSCORE}, {} }; static const struct SpritePalette sSpritePalettes[] = { {gNamingScreenMenu_Pal, PALTAG_PC_ICON}, {gNamingScreenMenu_Pal + 0x10, PALTAG_PAGE_SWAP_UPPER}, {gNamingScreenMenu_Pal + 0x20, PALTAG_PAGE_SWAP_LOWER}, {gNamingScreenMenu_Pal + 0x30, PALTAG_PAGE_SWAP_OTHERS}, {gNamingScreenMenu_Pal + 0x40, PALTAG_PAGE_SWAP}, {gNamingScreenMenu_Pal + 0x50, PALTAG_CURSOR}, {gNamingScreenMenu_Pal + 0x40, PALTAG_BACK_BUTTON}, {gNamingScreenMenu_Pal + 0x40, PALTAG_OK_BUTTON}, {} };