From 43e942c3af39bf230e37dde9b406e99b12800f63 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Tue, 9 Nov 2021 12:50:35 -0500 Subject: Clean up pokenav ribbons --- src/pokenav.c | 8 +- src/pokenav_ribbons_1.c | 746 ------------------------ src/pokenav_ribbons_2.c | 1270 ----------------------------------------- src/pokenav_ribbons_list.c | 746 ++++++++++++++++++++++++ src/pokenav_ribbons_summary.c | 1270 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 2020 insertions(+), 2020 deletions(-) delete mode 100644 src/pokenav_ribbons_1.c delete mode 100644 src/pokenav_ribbons_2.c create mode 100644 src/pokenav_ribbons_list.c create mode 100644 src/pokenav_ribbons_summary.c (limited to 'src') diff --git a/src/pokenav.c b/src/pokenav.c index d30c523f9..4338023db 100644 --- a/src/pokenav.c +++ b/src/pokenav.c @@ -179,8 +179,8 @@ const struct PokenavCallbacks PokenavMenuCallbacks[15] = .open = OpenRibbonsMonList, .createLoopTask = CreateRibbonsMonListLoopedTask, .isLoopTaskActive = IsRibbonsMonListLoopedTaskActive, - .free1 = FreeRibbonsMonList1, - .free2 = FreeRibbonsMonList2, + .free1 = FreeRibbonsMonList, + .free2 = FreeRibbonsMonMenu, }, [POKENAV_RIBBONS_SUMMARY_SCREEN - POKENAV_MENU_IDS_START] = { @@ -199,8 +199,8 @@ const struct PokenavCallbacks PokenavMenuCallbacks[15] = .open = OpenRibbonsMonListFromRibbonsSummary, .createLoopTask = CreateRibbonsMonListLoopedTask, .isLoopTaskActive = IsRibbonsMonListLoopedTaskActive, - .free1 = FreeRibbonsMonList1, - .free2 = FreeRibbonsMonList2, + .free1 = FreeRibbonsMonList, + .free2 = FreeRibbonsMonMenu, }, }; diff --git a/src/pokenav_ribbons_1.c b/src/pokenav_ribbons_1.c deleted file mode 100644 index 862128967..000000000 --- a/src/pokenav_ribbons_1.c +++ /dev/null @@ -1,746 +0,0 @@ -#include "global.h" -#include "pokenav.h" -#include "bg.h" -#include "menu.h" -#include "window.h" -#include "sound.h" -#include "string_util.h" -#include "international_string_util.h" -#include "constants/songs.h" - -enum -{ - RIBBONS_MON_LIST_FUNC_NONE, - RIBBONS_MON_LIST_FUNC_MOVE_UP, - RIBBONS_MON_LIST_FUNC_MOVE_DOWN, - RIBBONS_MON_LIST_FUNC_PAGE_UP, - RIBBONS_MON_LIST_FUNC_PAGE_DOWN, - RIBBONS_MON_LIST_FUNC_EXIT, - RIBBONS_MON_LIST_FUNC_OPEN_RIBBONS_SUMMARY -}; - - -struct PokenavSub9 -{ - u32 (*callback)(struct PokenavSub9*); - u32 loopedTaskId; - u16 winid; - s32 boxId; - s32 monId; - u32 changeBgs; - u32 saveMonList; - struct PokenavSub18 *monList; -}; - -struct PokenavSub10 -{ - bool32 (*callback)(void); - u32 ltid; - u16 winid; - bool32 fromSummary; - u8 buff[BG_SCREEN_SIZE]; -}; - -static u32 HandleRibbonsMonListInput_WaitListInit(struct PokenavSub9 *structPtr); -static u32 HandleRibbonsMonListInput(struct PokenavSub9 *structPtr); -static u32 RibbonsMonMenu_ReturnToMainMenu(struct PokenavSub9 *structPtr); -static u32 RibbonsMonMenu_ToSummaryScreen(struct PokenavSub9 *structPtr); -static u32 BuildPartyMonRibbonList(s32 state); -static u32 InitBoxMonRibbonList(s32 state); -static u32 BuildBoxMonRibbonList(s32 state); -static u32 GetMonRibbonListLoopTaskFunc(s32 state); -static void sub_81CFCEC(struct PokenavSub9 *structPtr, struct PokenavMonList *item); -static u32 LoopedTask_OpenRibbonsMonList(s32 state); -static bool32 GetRibbonsMonCurrentLoopedTaskActive(void); -static u32 LoopedTask_RibbonsListMoveCursorUp(s32 state); -static u32 LoopedTask_RibbonsListMoveCursorDown(s32 state); -static u32 LoopedTask_RibbonsListMovePageUp(s32 state); -static u32 LoopedTask_RibbonsListMovePageDown(s32 state); -static u32 LoopedTask_RibbonsListReturnToMainMenu(s32 state); -static u32 LoopedTask_RibbonsListOpenSummary(s32 state); -static void sub_81D02B0(s32 windowId, s32 val1, s32 val2); -static void AddRibbonsMonListWindow(struct PokenavSub10 *ptr); -static void sub_81D0288(struct PokenavSub10 *ptr); -static void InitMonRibbonPokenavListMenuTemplate(void); -static void BufferRibbonMonInfoText(struct PokenavMonList *, u8 *); - -static const LoopedTask sMonRibbonListLoopTaskFuncs[] = -{ - BuildPartyMonRibbonList, - InitBoxMonRibbonList, - BuildBoxMonRibbonList -}; - -static const u16 sMonRibbonListFramePal[] = INCBIN_U16("graphics/pokenav/ribbons/list_bg.gbapal"); -static const u32 sMonRibbonListFrameTiles[] = INCBIN_U32("graphics/pokenav/ribbons/list_bg.4bpp.lz"); -static const u32 sMonRibbonListFrameTilemap[] = INCBIN_U32("graphics/pokenav/ribbons/list_bg.bin.lz"); -static const u16 sMonRibbonListUi_Pal[] = INCBIN_U16("graphics/pokenav/ribbons/list_ui.gbapal"); - -static const struct BgTemplate sMonRibbonListBgTemplates[] = -{ - { - .bg = 1, - .charBaseIndex = 1, - .mapBaseIndex = 0x06, - .screenSize = 0, - .paletteMode = 0, - .priority = 2, - .baseTile = 0 - }, { - .bg = 2, - .charBaseIndex = 2, - .mapBaseIndex = 0x07, - .screenSize = 0, - .paletteMode = 0, - .priority = 3, - .baseTile = 0 - } -}; - -static const LoopedTask sRibbonsMonMenuLoopTaskFuncs[] = -{ - [RIBBONS_MON_LIST_FUNC_NONE] = NULL, - [RIBBONS_MON_LIST_FUNC_MOVE_UP] = LoopedTask_RibbonsListMoveCursorUp, - [RIBBONS_MON_LIST_FUNC_MOVE_DOWN] = LoopedTask_RibbonsListMoveCursorDown, - [RIBBONS_MON_LIST_FUNC_PAGE_UP] = LoopedTask_RibbonsListMovePageUp, - [RIBBONS_MON_LIST_FUNC_PAGE_DOWN] = LoopedTask_RibbonsListMovePageDown, - [RIBBONS_MON_LIST_FUNC_EXIT] = LoopedTask_RibbonsListReturnToMainMenu, - [RIBBONS_MON_LIST_FUNC_OPEN_RIBBONS_SUMMARY] = LoopedTask_RibbonsListOpenSummary -}; - -static const struct WindowTemplate sRibbonsMonListWindowTemplate = -{ - .bg = 1, - .tilemapLeft = 1, - .tilemapTop = 6, - .width = 7, - .height = 2, - .paletteNum = 1, - .baseBlock = 20 -}; - -static const u8 sText_MaleSymbol[] = _("{COLOR_HIGHLIGHT_SHADOW}{LIGHT_RED}{WHITE}{GREEN}♂{COLOR_HIGHLIGHT_SHADOW}{DARK_GRAY}{WHITE}{LIGHT_GRAY}"); -static const u8 sText_FemaleSymbol[] = _("{COLOR_HIGHLIGHT_SHADOW}{LIGHT_GREEN}{WHITE}{BLUE}♀{COLOR_HIGHLIGHT_SHADOW}{DARK_GRAY}{WHITE}{LIGHT_GRAY}"); -static const u8 sText_NoGenderSymbol[] = _("{UNK_SPACER}"); - -bool32 PokenavCallback_Init_MonRibbonList(void) -{ - struct PokenavSub9 *structPtr = AllocSubstruct(POKENAV_SUBSTRUCT_RIBBONS_MON_LIST, sizeof(struct PokenavSub9)); - if (structPtr == NULL) - return FALSE; - - structPtr->monList = AllocSubstruct(POKENAV_SUBSTRUCT_MON_LIST, sizeof(struct PokenavSub18)); - if (structPtr->monList == NULL) - return FALSE; - - structPtr->callback = HandleRibbonsMonListInput_WaitListInit; - structPtr->loopedTaskId = CreateLoopedTask(GetMonRibbonListLoopTaskFunc, 1); - structPtr->changeBgs = 0; - return TRUE; -} - -bool32 PokenavCallback_Init_RibbonsMonListFromSummary(void) -{ - struct PokenavSub9 *structPtr = AllocSubstruct(POKENAV_SUBSTRUCT_RIBBONS_MON_LIST, sizeof(struct PokenavSub9)); - if (structPtr == NULL) - return FALSE; - - structPtr->monList = GetSubstructPtr(POKENAV_SUBSTRUCT_MON_LIST); - structPtr->callback = HandleRibbonsMonListInput; - structPtr->changeBgs = 1; - return TRUE; -} - -u32 GetRibbonsMonListCallback(void) -{ - struct PokenavSub9 *structPtr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_LIST); - return structPtr->callback(structPtr); -} - -void FreeRibbonsMonList1(void) -{ - struct PokenavSub9 *structPtr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_LIST); - if (!structPtr->saveMonList) - FreePokenavSubstruct(POKENAV_SUBSTRUCT_MON_LIST); - FreePokenavSubstruct(POKENAV_SUBSTRUCT_RIBBONS_MON_LIST); -} - -static u32 HandleRibbonsMonListInput_WaitListInit(struct PokenavSub9 *structPtr) -{ - if (!IsLoopedTaskActive(structPtr->loopedTaskId)) - structPtr->callback = HandleRibbonsMonListInput; - return 0; -} - -static u32 HandleRibbonsMonListInput(struct PokenavSub9 *structPtr) -{ - if (JOY_REPEAT(DPAD_UP)) - return RIBBONS_MON_LIST_FUNC_MOVE_UP; - if (JOY_REPEAT(DPAD_DOWN)) - return RIBBONS_MON_LIST_FUNC_MOVE_DOWN; - if (JOY_NEW(DPAD_LEFT)) - return RIBBONS_MON_LIST_FUNC_PAGE_UP; - if (JOY_NEW(DPAD_RIGHT)) - return RIBBONS_MON_LIST_FUNC_PAGE_DOWN; - if (JOY_NEW(B_BUTTON)) - { - structPtr->saveMonList = 0; - structPtr->callback = RibbonsMonMenu_ReturnToMainMenu; - return RIBBONS_MON_LIST_FUNC_EXIT; - } - if (JOY_NEW(A_BUTTON)) - { - structPtr->monList->currIndex = GetSelectedPokenavListIndex(); - structPtr->saveMonList = 1; - structPtr->callback = RibbonsMonMenu_ToSummaryScreen; - return RIBBONS_MON_LIST_FUNC_OPEN_RIBBONS_SUMMARY; - } - return RIBBONS_MON_LIST_FUNC_NONE; -} - -static u32 RibbonsMonMenu_ReturnToMainMenu(struct PokenavSub9 *structPtr) -{ - return POKENAV_MAIN_MENU_CURSOR_ON_RIBBONS; -} - -static u32 RibbonsMonMenu_ToSummaryScreen(struct PokenavSub9 *structPtr) -{ - return POKENAV_RIBBONS_SUMMARY_SCREEN; -} - -static u32 UpdateMonListBgs(void) -{ - struct PokenavSub9 *structPtr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_LIST); - return structPtr->changeBgs; -} - -static struct PokenavMonList *GetMonRibbonMonListData(void) -{ - struct PokenavSub9 * ptr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_LIST); - return ptr->monList->monData; -} - -static s32 GetRibbonsMonListCount(void) -{ - struct PokenavSub9 * ptr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_LIST); - return ptr->monList->listCount; -} - -//unused -static s32 GetMonRibbonSelectedMonData(void) -{ - struct PokenavSub9 * ptr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_LIST); - s32 idx = GetSelectedPokenavListIndex(); - return ptr->monList->monData[idx].data; -} - -static s32 GetRibbonListMenuCurrIndex(void) -{ - struct PokenavSub9 * ptr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_LIST); - return ptr->monList->currIndex; -} - -static u32 GetMonRibbonListLoopTaskFunc(s32 state) -{ - return sMonRibbonListLoopTaskFuncs[state](state); -} - -static u32 BuildPartyMonRibbonList(s32 state) -{ - s32 i; - struct PokenavMonList item; - struct PokenavSub9 * ptr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_LIST); - - ptr->monList->listCount = 0; - ptr->monList->currIndex = 0; - item.boxId = TOTAL_BOXES_COUNT; - for (i = 0; i < PARTY_SIZE; i++) - { - struct Pokemon * pokemon = &gPlayerParty[i]; - if (!GetMonData(pokemon, MON_DATA_SANITY_HAS_SPECIES)) - return LT_INC_AND_CONTINUE; - if (!GetMonData(pokemon, MON_DATA_SANITY_IS_EGG) && !GetMonData(pokemon, MON_DATA_SANITY_IS_BAD_EGG)) - { - u32 ribbonCount = GetMonData(pokemon, MON_DATA_RIBBON_COUNT); - if (ribbonCount != 0) - { - item.monId = i; - item.data = ribbonCount; - sub_81CFCEC(ptr, &item); - } - } - } - - return LT_INC_AND_CONTINUE; -} - -static u32 InitBoxMonRibbonList(s32 state) -{ - struct PokenavSub9 *ptr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_LIST); - ptr->monId = 0; - ptr->boxId = 0; - return LT_INC_AND_CONTINUE; -} - -static u32 BuildBoxMonRibbonList(s32 state) -{ - struct PokenavSub9 * ptr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_LIST); - s32 boxId = ptr->boxId; - s32 monId = ptr->monId; - s32 boxCount = 0; - struct PokenavMonList item; - - while (boxId < TOTAL_BOXES_COUNT) - { - while (monId < IN_BOX_COUNT) - { - if (CheckBoxMonSanityAt(boxId, monId)) - { - u32 ribbonCount = GetBoxMonDataAt(boxId, monId, MON_DATA_RIBBON_COUNT); - if (ribbonCount != 0) - { - item.boxId = boxId; - item.monId = monId; - item.data = ribbonCount; - sub_81CFCEC(ptr, &item); - } - } - boxCount++; - monId++; - if (boxCount > TOTAL_BOXES_COUNT) - { - ptr->boxId = boxId; - ptr->monId = monId; - return LT_CONTINUE; - } - } - monId = 0; - boxId++; - } - - ptr->changeBgs = 1; - return LT_FINISH; -} - -static void sub_81CFCEC(struct PokenavSub9 *structPtr, struct PokenavMonList *item) -{ - u32 left = 0; - u32 right = structPtr->monList->listCount; - u32 insertionIdx = left + (right - left) / 2; - - while (right != insertionIdx) - { - if (item->data > structPtr->monList->monData[insertionIdx].data) - right = insertionIdx; - else - left = insertionIdx + 1; - insertionIdx = left + (right - left) / 2; - } - for (right = structPtr->monList->listCount; right > insertionIdx; right--) - structPtr->monList->monData[right] = structPtr->monList->monData[right - 1]; - structPtr->monList->monData[insertionIdx] = *item; - structPtr->monList->listCount++; -} - -// Unused -static bool32 PlayerHasRibbonsMon(void) -{ - s32 i, j; - - for (i = 0; i < PARTY_SIZE; i++) - { - struct Pokemon *mon = &gPlayerParty[i]; - if (!GetMonData(mon, MON_DATA_SANITY_HAS_SPECIES)) - continue; - if (GetMonData(mon, MON_DATA_SANITY_IS_EGG)) - continue; - if (GetMonData(mon, MON_DATA_RIBBONS)) - return TRUE; - } - - for (i = 0; i < TOTAL_BOXES_COUNT; i++) - { - for (j = 0; j < IN_BOX_COUNT; j++) - { - if (!CheckBoxMonSanityAt(i, j)) - continue; - if (GetBoxMonDataAt(i, j, MON_DATA_RIBBONS)) - return TRUE; - } - } - - return FALSE; -} - -bool32 OpenRibbonsMonList(void) -{ - struct PokenavSub10 *ptr = AllocSubstruct(POKENAV_SUBSTRUCT_RIBBONS_MON_MENU, sizeof(struct PokenavSub10)); - if (ptr == NULL) - return FALSE; - ptr->ltid = CreateLoopedTask(LoopedTask_OpenRibbonsMonList, 1); - ptr->callback = GetRibbonsMonCurrentLoopedTaskActive; - ptr->fromSummary = FALSE; - return TRUE; -} - -bool32 OpenRibbonsMonListFromRibbonsSummary(void) -{ - struct PokenavSub10 *monMenu = AllocSubstruct(POKENAV_SUBSTRUCT_RIBBONS_MON_MENU, sizeof(struct PokenavSub10)); - if (monMenu == NULL) - return FALSE; - monMenu->ltid = CreateLoopedTask(LoopedTask_OpenRibbonsMonList, 1); - monMenu->callback = GetRibbonsMonCurrentLoopedTaskActive; - monMenu->fromSummary = TRUE; - return TRUE; -} - -void CreateRibbonsMonListLoopedTask(s32 idx) -{ - struct PokenavSub10 *monMenu = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_MENU); - monMenu->ltid = CreateLoopedTask(sRibbonsMonMenuLoopTaskFuncs[idx], 1); - monMenu->callback = GetRibbonsMonCurrentLoopedTaskActive; -} - -bool32 IsRibbonsMonListLoopedTaskActive(void) -{ - struct PokenavSub10 *monMenu = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_MENU); - return monMenu->callback(); -} - -bool32 GetRibbonsMonCurrentLoopedTaskActive(void) -{ - struct PokenavSub10 * ptr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_MENU); - return IsLoopedTaskActive(ptr->ltid); -} - -void FreeRibbonsMonList2(void) -{ - struct PokenavSub10 * ptr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_MENU); - sub_81C8234(); - RemoveWindow(ptr->winid); - FreePokenavSubstruct(POKENAV_SUBSTRUCT_RIBBONS_MON_MENU); -} - -static u32 LoopedTask_OpenRibbonsMonList(s32 state) -{ - struct PokenavSub10 *monMenu = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_MENU); - switch (state) - { - case 0: - InitBgTemplates(sMonRibbonListBgTemplates, ARRAY_COUNT(sMonRibbonListBgTemplates)); - DecompressAndCopyTileDataToVram(1, sMonRibbonListFrameTiles, 0, 0, 0); - SetBgTilemapBuffer(1, monMenu->buff); - CopyToBgTilemapBuffer(1, sMonRibbonListFrameTilemap, 0, 0); - CopyPaletteIntoBufferUnfaded(sMonRibbonListFramePal, 0x10, 0x20); - CopyBgTilemapBufferToVram(1); - return LT_INC_AND_PAUSE; - case 1: - if (FreeTempTileDataBuffersIfPossible()) - return LT_PAUSE; - if (!UpdateMonListBgs()) - return LT_PAUSE; - ChangeBgX(1, 0, BG_COORD_SET); - ChangeBgY(1, 0, BG_COORD_SET); - ShowBg(1); - return LT_INC_AND_PAUSE; - case 2: - if (FreeTempTileDataBuffersIfPossible()) - return LT_PAUSE; - CopyPaletteIntoBufferUnfaded(sMonRibbonListUi_Pal, 0x20, 0x20); - InitMonRibbonPokenavListMenuTemplate(); - return LT_INC_AND_PAUSE; - case 3: - if (sub_81C8224()) - return LT_PAUSE; - AddRibbonsMonListWindow(monMenu); - return LT_INC_AND_PAUSE; - case 4: - if (FreeTempTileDataBuffersIfPossible()) - return LT_PAUSE; - ShowBg(2); - HideBg(3); - PrintHelpBarText(HELPBAR_RIBBONS_MON_LIST); - PokenavFadeScreen(1); - if (!monMenu->fromSummary) - { - LoadLeftHeaderGfxForIndex(POKENAV_GFX_RIBBONS_MENU); - ShowLeftHeaderGfx(POKENAV_GFX_RIBBONS_MENU, 1, 0); - } - return LT_INC_AND_PAUSE; - case 5: - if (IsPaletteFadeActive()) - return LT_PAUSE; - if (AreLeftHeaderSpritesMoving()) - return LT_PAUSE; - break; - } - return LT_FINISH; -} - -static u32 LoopedTask_RibbonsListMoveCursorUp(s32 state) -{ - struct PokenavSub10 *monMenu = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_MENU); - switch (state) - { - case 0: - switch (MatchCall_MoveCursorUp()) - { - case 0: - return LT_FINISH; - case 1: - PlaySE(SE_SELECT); - return LT_SET_STATE(2); - case 2: - PlaySE(SE_SELECT); - break; - } - return LT_INC_AND_PAUSE; - case 1: - if (IsMonListLoopedTaskActive()) - return LT_PAUSE; - // fallthrough - case 2: - sub_81D0288(monMenu); - return LT_INC_AND_PAUSE; - case 3: - if (IsDma3ManagerBusyWithBgCopy()) - return LT_PAUSE; - break; - } - return LT_FINISH; -} - -static u32 LoopedTask_RibbonsListMoveCursorDown(s32 state) -{ - struct PokenavSub10 *monMenu = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_MENU); - switch (state) - { - case 0: - switch (MatchCall_MoveCursorDown()) - { - case 0: - return LT_FINISH; - case 1: - PlaySE(SE_SELECT); - return LT_SET_STATE(2); - case 2: - PlaySE(SE_SELECT); - break; - } - return LT_INC_AND_PAUSE; - case 1: - if (IsMonListLoopedTaskActive()) - return LT_PAUSE; - // fallthrough - case 2: - sub_81D0288(monMenu); - return LT_INC_AND_PAUSE; - case 3: - if (IsDma3ManagerBusyWithBgCopy()) - return LT_PAUSE; - break; - } - return LT_FINISH; -} - -static u32 LoopedTask_RibbonsListMovePageUp(s32 state) -{ - struct PokenavSub10 *monMenu = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_MENU); - switch (state) - { - case 0: - switch (MatchCall_PageUp()) - { - case 0: - return LT_FINISH; - case 1: - PlaySE(SE_SELECT); - return LT_SET_STATE(2); - case 2: - PlaySE(SE_SELECT); - break; - } - return LT_INC_AND_PAUSE; - case 1: - if (IsMonListLoopedTaskActive()) - return LT_PAUSE; - // fallthrough - case 2: - sub_81D0288(monMenu); - return LT_INC_AND_PAUSE; - case 3: - if (IsDma3ManagerBusyWithBgCopy()) - return LT_PAUSE; - break; - } - return LT_FINISH; -} - -static u32 LoopedTask_RibbonsListMovePageDown(s32 state) -{ - struct PokenavSub10 *monMenu = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_MENU); - switch (state) - { - case 0: - switch (MatchCall_PageDown()) - { - case 0: - return LT_FINISH; - case 1: - PlaySE(SE_SELECT); - return LT_SET_STATE(2); - case 2: - PlaySE(SE_SELECT); - break; - } - return LT_INC_AND_PAUSE; - case 1: - if (IsMonListLoopedTaskActive()) - return LT_PAUSE; - // fallthrough - case 2: - sub_81D0288(monMenu); - return LT_INC_AND_PAUSE; - case 3: - if (IsDma3ManagerBusyWithBgCopy()) - return LT_PAUSE; - break; - } - return LT_FINISH; -} - -static u32 LoopedTask_RibbonsListReturnToMainMenu(s32 state) -{ - switch (state) - { - case 0: - PlaySE(SE_SELECT); - PokenavFadeScreen(0); - SlideMenuHeaderDown(); - return LT_INC_AND_PAUSE; - case 1: - if (IsPaletteFadeActive()) - return LT_PAUSE; - if (MainMenuLoopedTaskIsBusy()) - return LT_PAUSE; - SetLeftHeaderSpritesInvisibility(); - break; - } - return LT_FINISH; -} - -static u32 LoopedTask_RibbonsListOpenSummary(s32 state) -{ - switch (state) - { - case 0: - PlaySE(SE_SELECT); - PokenavFadeScreen(0); - return LT_INC_AND_PAUSE; - case 1: - if (IsPaletteFadeActive()) - return LT_PAUSE; - break; - } - return LT_FINISH; -} - -static void AddRibbonsMonListWindow(struct PokenavSub10 *monMenu) -{ - s32 r2; - monMenu->winid = AddWindow(&sRibbonsMonListWindowTemplate); - PutWindowTilemap(monMenu->winid); - r2 = GetRibbonsMonListCount(); - sub_81D02B0(monMenu->winid, 0, r2); - CopyWindowToVram(monMenu->winid, COPYWIN_MAP); - sub_81D0288(monMenu); -} - -static void sub_81D0288(struct PokenavSub10 *monMenu) -{ - s32 r4 = GetSelectedPokenavListIndex(); - s32 r2 = GetRibbonsMonListCount(); - sub_81D02B0(monMenu->winid, r4 + 1, r2); - CopyWindowToVram(monMenu->winid, COPYWIN_GFX); -} - -static void sub_81D02B0(s32 windowId, s32 val1, s32 val2) -{ - u8 strbuf[16]; - u32 x; - - u8 * ptr = strbuf; - ptr = ConvertIntToDecimalStringN(ptr, val1, STR_CONV_MODE_RIGHT_ALIGN, 3); - *ptr++ = CHAR_SLASH; - ConvertIntToDecimalStringN(ptr, val2, STR_CONV_MODE_RIGHT_ALIGN, 3); - x = GetStringCenterAlignXOffset(FONT_NORMAL, strbuf, 56); - AddTextPrinterParameterized(windowId, FONT_NORMAL, strbuf, x, 1, TEXT_SKIP_DRAW, NULL); -} - -static void InitMonRibbonPokenavListMenuTemplate(void) -{ - struct PokenavListTemplate template; - template.list.monList = GetMonRibbonMonListData(); - template.count = GetRibbonsMonListCount(); - template.unk8 = 4; - template.unk6 = GetRibbonListMenuCurrIndex(); - template.item_X = 13; - template.windowWidth = 17; - template.listTop = 1; - template.maxShowed = 8; - template.fillValue = 2; - template.fontId = FONT_NORMAL; - template.listFunc.printMonFunc = BufferRibbonMonInfoText; - template.unk14 = NULL; - sub_81C81D4(&sMonRibbonListBgTemplates[1], &template, 0); -} - -// Buffers the "Nickname gender/level" text for the ribbon mon list -static void BufferRibbonMonInfoText(struct PokenavMonList * item0, u8 * dest) -{ - u8 gender; - u8 level; - u8 * s; - const u8 * genderStr; - struct PokenavMonList * item = item0; - - // Mon is in party - if (item->boxId == TOTAL_BOXES_COUNT) - { - struct Pokemon * mon = &gPlayerParty[item->monId]; - gender = GetMonGender(mon); - level = GetLevelFromMonExp(mon); - GetMonData(mon, MON_DATA_NICKNAME, gStringVar3); - } - // Mon is in PC - else - { - struct BoxPokemon * mon = GetBoxedMonPtr(item->boxId, item->monId); - gender = GetBoxMonGender(mon); - level = GetLevelFromBoxMonExp(mon); - GetBoxMonData(mon, MON_DATA_NICKNAME, gStringVar3); - } - - StringGetEnd10(gStringVar3); - dest = GetStringClearToWidth(dest, FONT_NORMAL, gStringVar3, 60); - switch (gender) - { - default: - genderStr = sText_NoGenderSymbol; - break; - case MON_MALE: - genderStr = sText_MaleSymbol; - break; - case MON_FEMALE: - genderStr = sText_FemaleSymbol; - break; - } - - s = StringCopy(gStringVar1, genderStr); - *s++ = CHAR_SLASH; - *s++ = CHAR_EXTRA_SYMBOL; - *s++ = CHAR_LV_2; - ConvertIntToDecimalStringN(s, level, STR_CONV_MODE_LEFT_ALIGN, 3); - dest = GetStringClearToWidth(dest, FONT_NORMAL, gStringVar1, 54); - ConvertIntToDecimalStringN(dest, item->data, STR_CONV_MODE_RIGHT_ALIGN, 2); -} diff --git a/src/pokenav_ribbons_2.c b/src/pokenav_ribbons_2.c deleted file mode 100644 index ef08ba392..000000000 --- a/src/pokenav_ribbons_2.c +++ /dev/null @@ -1,1270 +0,0 @@ -#include "global.h" -#include "decompress.h" -#include "dynamic_placeholder_text_util.h" -#include "graphics.h" -#include "international_string_util.h" -#include "pokenav.h" -#include "sound.h" -#include "sprite.h" -#include "string_util.h" -#include "strings.h" -#include "text.h" -#include "trainer_pokemon_sprites.h" -#include "window.h" -#include "constants/songs.h" - -enum -{ - RIBBONS_SUMMARY_FUNC_NONE, - RIBBONS_SUMMARY_FUNC_SWITCH_MONS, - RIBBONS_SUMMARY_FUNC_SELECT_RIBBON, - RIBBONS_SUMMARY_FUNC_EXPANDED_CURSOR_MOVE, - RIBBONS_SUMMARY_FUNC_EXPANDED_CANCEL, - RIBBONS_SUMMARY_FUNC_EXIT, -}; - -#define GFXTAG_RIBBON_ICONS_BIG 9 - -#define PALTAG_RIBBON_ICONS_1 15 -#define PALTAG_RIBBON_ICONS_2 16 -#define PALTAG_RIBBON_ICONS_3 17 -#define PALTAG_RIBBON_ICONS_4 18 -#define PALTAG_RIBBON_ICONS_5 19 - -#define RIBBONS_PER_ROW 9 -#define GIFT_RIBBON_ROW (1 + (FIRST_GIFT_RIBBON / RIBBONS_PER_ROW)) // Gift ribbons start on a new row after the normal ribbons. -#define GIFT_RIBBON_START_POS (RIBBONS_PER_ROW * GIFT_RIBBON_ROW) - -#define MON_SPRITE_X_ON 40 -#define MON_SPRITE_X_OFF -32 -#define MON_SPRITE_Y 104 - -struct PokenavSub13 -{ - u8 unused1[8]; - struct PokenavSub18 *monList; - u16 selectedPos; - u16 normalRibbonLastRowStart; - u16 numNormalRibbons; - u16 numGiftRibbons; - u32 ribbonIds[FIRST_GIFT_RIBBON]; - u32 giftRibbonIds[NUM_GIFT_RIBBONS]; - u32 unused2; - u32 (*callback)(struct PokenavSub13 *); -}; - -struct PokenavSub14 -{ - u32 (*callback)(void); - u32 loopedTaskId; - u16 nameWindowId; - u16 ribbonCountWindowId; - u16 listIdxWindowId; - u16 unusedWindowId; - u16 monSpriteId; - struct Sprite *bigRibbonSprite; - u32 unused; - u8 tilemapBuffers[2][BG_SCREEN_SIZE]; -}; - -// Used for the initial drawing of the ribbons -static u32 sRibbonDraw_Total; -static u32 sRibbonDraw_Current; - -static void PrintCurrentMonRibbonCount(struct PokenavSub14 *); -static void PrintRibbbonsSummaryMonInfo(struct PokenavSub14 *); -static void PrintRibbonsMonListIndex(struct PokenavSub14 *); -static void ZoomOutSelectedRibbon(struct PokenavSub14 *); -static void UpdateAndZoomInSelectedRibbon(struct PokenavSub14 *); -static void PrintRibbonNameAndDescription(struct PokenavSub14 *); -static void ResetSpritesAndDrawMonFrontPic(struct PokenavSub14 *); -static void AddRibbonListIndexWindow(struct PokenavSub14 *); -static void DestroyRibbonsMonFrontPic(struct PokenavSub14 *); -static void SlideMonSpriteOff(struct PokenavSub14 *); -static void SlideMonSpriteOn(struct PokenavSub14 *); -static void AddRibbonCountWindow(struct PokenavSub14 *); -static void CreateBigRibbonSprite(struct PokenavSub14 *); -static void AddRibbonSummaryMonNameWindow(struct PokenavSub14 *); -static void DrawAllRibbonsSmall(struct PokenavSub14 *); -static bool32 IsRibbonAnimating(struct PokenavSub14 *); -static bool32 IsMonSpriteAnimating(struct PokenavSub14 *); -static void GetMonRibbons(struct PokenavSub13 *); -static u32 HandleExpandedRibbonInput(struct PokenavSub13 *); -static u32 RibbonsSummaryHandleInput(struct PokenavSub13 *); -static u32 ReturnToRibbonsListFromSummary(struct PokenavSub13 *); -static bool32 TrySelectRibbonUp(struct PokenavSub13 *); -static bool32 TrySelectRibbonRight(struct PokenavSub13 *); -static bool32 TrySelectRibbonLeft(struct PokenavSub13 *); -static bool32 TrySelectRibbonDown(struct PokenavSub13 *); -static bool32 GetCurrentLoopedTaskActive(void); -static u32 GetRibbonsSummaryCurrentIndex(void); -static u32 GetRibbonsSummaryMonListCount(void); -static u16 DrawRibbonsMonFrontPic(s32, s32); -static void StartMonSpriteSlide(struct Sprite *, s32, s32, s32); -static void SpriteCB_MonSpriteSlide(struct Sprite *); -static void ClearRibbonsSummaryBg(void); -static void BufferSmallRibbonGfxData(u16 *, u32); -static void DrawRibbonSmall(u32, u32); -static void SpriteCB_WaitForRibbonAnimation(struct Sprite *); -static u32 LoopedTask_OpenRibbonsSummaryMenu(s32); -static u32 LoopedTask_SwitchRibbonsSummaryMon(s32); -static u32 LoopedTask_ExpandSelectedRibbon(s32); -static u32 LoopedTask_MoveRibbonsCursorExpanded(s32); -static u32 LoopedTask_ShrinkExpandedRibbon(s32); -static u32 LoopedTask_ExitRibbonsSummaryMenu(s32); - -struct -{ - u8 numBits; // The number of bits needed to represent numRibbons - u8 numRibbons; // Never read. The contest ribbons have 4 (1 for each rank), the rest are just 1 ribbon - u8 ribbonId; - bool8 isGiftRibbon; -} static const sRibbonData[] = -{ - {1, 1, CHAMPION_RIBBON, FALSE}, - {3, 4, COOL_RIBBON_NORMAL, FALSE}, - {3, 4, BEAUTY_RIBBON_NORMAL, FALSE}, - {3, 4, CUTE_RIBBON_NORMAL, FALSE}, - {3, 4, SMART_RIBBON_NORMAL, FALSE}, - {3, 4, TOUGH_RIBBON_NORMAL, FALSE}, - {1, 1, WINNING_RIBBON, FALSE}, - {1, 1, VICTORY_RIBBON, FALSE}, - {1, 1, ARTIST_RIBBON, FALSE}, - {1, 1, EFFORT_RIBBON, FALSE}, - {1, 1, MARINE_RIBBON, TRUE}, - {1, 1, LAND_RIBBON, TRUE}, - {1, 1, SKY_RIBBON, TRUE}, - {1, 1, COUNTRY_RIBBON, TRUE}, - {1, 1, NATIONAL_RIBBON, TRUE}, - {1, 1, EARTH_RIBBON, TRUE}, - {1, 1, WORLD_RIBBON, TRUE} -}; - -#include "data/text/ribbon_descriptions.h" -#include "data/text/gift_ribbon_descriptions.h" - -static const u16 sRibbonIcons1_Pal[] = INCBIN_U16("graphics/pokenav/ribbons/icons1.gbapal"); -static const u16 sRibbonIcons2_Pal[] = INCBIN_U16("graphics/pokenav/ribbons/icons2.gbapal"); -static const u16 sRibbonIcons3_Pal[] = INCBIN_U16("graphics/pokenav/ribbons/icons3.gbapal"); -static const u16 sRibbonIcons4_Pal[] = INCBIN_U16("graphics/pokenav/ribbons/icons4.gbapal"); -static const u16 sRibbonIcons5_Pal[] = INCBIN_U16("graphics/pokenav/ribbons/icons5.gbapal"); -static const u16 sMonInfo_Pal[] = INCBIN_U16("graphics/pokenav/ribbons/mon_info.gbapal"); // palette for Pokémon's name/gender/level text -static const u32 sRibbonIconsSmall_Gfx[] = INCBIN_U32("graphics/pokenav/ribbons/icons.4bpp.lz"); -static const u32 sRibbonIconsBig_Gfx[] = INCBIN_U32("graphics/pokenav/ribbons/icons_big.4bpp.lz"); - -static const struct BgTemplate sBgTemplates[] = -{ - { - .bg = 1, - .charBaseIndex = 3, - .mapBaseIndex = 0x07, - .screenSize = 0, - .paletteMode = 0, - .priority = 1, - .baseTile = 0 - }, - { - .bg = 2, - .charBaseIndex = 1, - .mapBaseIndex = 0x06, - .screenSize = 0, - .paletteMode = 0, - .priority = 2, - .baseTile = 0 - } -}; - -static const LoopedTask sRibbonsSummaryMenuLoopTaskFuncs[] = -{ - [RIBBONS_SUMMARY_FUNC_NONE] = NULL, - [RIBBONS_SUMMARY_FUNC_SWITCH_MONS] = LoopedTask_SwitchRibbonsSummaryMon, - [RIBBONS_SUMMARY_FUNC_SELECT_RIBBON] = LoopedTask_ExpandSelectedRibbon, - [RIBBONS_SUMMARY_FUNC_EXPANDED_CURSOR_MOVE] = LoopedTask_MoveRibbonsCursorExpanded, - [RIBBONS_SUMMARY_FUNC_EXPANDED_CANCEL] = LoopedTask_ShrinkExpandedRibbon, - [RIBBONS_SUMMARY_FUNC_EXIT] = LoopedTask_ExitRibbonsSummaryMenu -}; - -bool32 PokenavCallback_Init_RibbonsSummaryMenu(void) -{ - struct PokenavSub13 *structPtr = AllocSubstruct(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_LIST, sizeof(struct PokenavSub13)); - if (structPtr == NULL) - return FALSE; - - structPtr->monList = GetSubstructPtr(POKENAV_SUBSTRUCT_MON_LIST); - if (structPtr->monList == NULL) - return FALSE; - - GetMonRibbons(structPtr); - structPtr->callback = RibbonsSummaryHandleInput; - gKeyRepeatContinueDelay = 3; - gKeyRepeatStartDelay = 10; - return TRUE; -} - -u32 GetRibbonsSummaryMenuCallback(void) -{ - struct PokenavSub13 *structPtr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_LIST); - return structPtr->callback(structPtr); -} - -void FreeRibbonsSummaryScreen1(void) -{ - FreePokenavSubstruct(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_LIST); -} - -// Handles input when a specific ribbon is not currently selected -static u32 RibbonsSummaryHandleInput(struct PokenavSub13 *structPtr) -{ - // Handle Up/Down movement to select a new Pokémon to show ribbons for - if (JOY_REPEAT(DPAD_UP) && structPtr->monList->currIndex != 0) - { - structPtr->monList->currIndex--; - structPtr->selectedPos = 0; - GetMonRibbons(structPtr); - return RIBBONS_SUMMARY_FUNC_SWITCH_MONS; - } - if (JOY_REPEAT(DPAD_DOWN) && structPtr->monList->currIndex < structPtr->monList->listCount - 1) - { - structPtr->monList->currIndex++; - structPtr->selectedPos = 0; - GetMonRibbons(structPtr); - return RIBBONS_SUMMARY_FUNC_SWITCH_MONS; - } - - if (JOY_NEW(A_BUTTON)) - { - // Enter ribbon selection - structPtr->callback = HandleExpandedRibbonInput; - return RIBBONS_SUMMARY_FUNC_SELECT_RIBBON; - } - if (JOY_NEW(B_BUTTON)) - { - // Exit ribbon summary menu - structPtr->callback = ReturnToRibbonsListFromSummary; - return RIBBONS_SUMMARY_FUNC_EXIT; - } - return RIBBONS_SUMMARY_FUNC_NONE; -} - -// Handles input when a ribbon is selected -static u32 HandleExpandedRibbonInput(struct PokenavSub13 *structPtr) -{ - // Handle movement while a ribbon is selected - if (JOY_REPEAT(DPAD_UP) && TrySelectRibbonUp(structPtr)) - return RIBBONS_SUMMARY_FUNC_EXPANDED_CURSOR_MOVE; - if (JOY_REPEAT(DPAD_DOWN) && TrySelectRibbonDown(structPtr)) - return RIBBONS_SUMMARY_FUNC_EXPANDED_CURSOR_MOVE; - if (JOY_REPEAT(DPAD_LEFT) && TrySelectRibbonLeft(structPtr)) - return RIBBONS_SUMMARY_FUNC_EXPANDED_CURSOR_MOVE; - if (JOY_REPEAT(DPAD_RIGHT) && TrySelectRibbonRight(structPtr)) - return RIBBONS_SUMMARY_FUNC_EXPANDED_CURSOR_MOVE; - - if (JOY_NEW(B_BUTTON)) - { - // Exit ribbon selection - structPtr->callback = RibbonsSummaryHandleInput; - return RIBBONS_SUMMARY_FUNC_EXPANDED_CANCEL; - } - return RIBBONS_SUMMARY_FUNC_NONE; -} - -static u32 ReturnToRibbonsListFromSummary(struct PokenavSub13 *structPtr) -{ - return POKENAV_RIBBONS_RETURN_TO_MON_LIST; -} - -static bool32 TrySelectRibbonUp(struct PokenavSub13 *structPtr) -{ - if (structPtr->selectedPos < FIRST_GIFT_RIBBON) - { - // In normal ribbons, try to move up a row - if (structPtr->selectedPos < RIBBONS_PER_ROW) - return FALSE; - - structPtr->selectedPos -= RIBBONS_PER_ROW; - return TRUE; - } - if (structPtr->numNormalRibbons != 0) - { - // In gift ribbons, try to move up into normal ribbons - // If there's > 1 row of gift ribbons (not normally possible) - // it's impossible to move up between them - u32 ribbonPos = structPtr->selectedPos - GIFT_RIBBON_START_POS; - structPtr->selectedPos = ribbonPos + structPtr->normalRibbonLastRowStart; - if (structPtr->selectedPos >= structPtr->numNormalRibbons) - structPtr->selectedPos = structPtr->numNormalRibbons - 1; - return TRUE; - } - return FALSE; -} - -static bool32 TrySelectRibbonDown(struct PokenavSub13 *structPtr) -{ - if (structPtr->selectedPos >= FIRST_GIFT_RIBBON) - return FALSE; - if (structPtr->selectedPos < structPtr->normalRibbonLastRowStart) - { - // Not in last row of normal ribbons, advance to next row - structPtr->selectedPos += RIBBONS_PER_ROW; - if (structPtr->selectedPos >= structPtr->numNormalRibbons) - structPtr->selectedPos = structPtr->numNormalRibbons - 1; - return TRUE; - } - if (structPtr->numGiftRibbons != 0) - { - // In/beyond last of row of normal ribbons and gift ribbons present, move down to gift ribbon row - int ribbonPos = structPtr->selectedPos - structPtr->normalRibbonLastRowStart; - if (ribbonPos >= structPtr->numGiftRibbons) - ribbonPos = structPtr->numGiftRibbons - 1; - - structPtr->selectedPos = ribbonPos + GIFT_RIBBON_START_POS; - return TRUE; - } - return FALSE; -} - -static bool32 TrySelectRibbonLeft(struct PokenavSub13 *structPtr) -{ - u16 column = structPtr->selectedPos % RIBBONS_PER_ROW; - if (column != 0) - { - structPtr->selectedPos--; - return TRUE; - } - - return FALSE; -} - -static bool32 TrySelectRibbonRight(struct PokenavSub13 *structPtr) -{ - int column = structPtr->selectedPos % RIBBONS_PER_ROW; - - if (column >= RIBBONS_PER_ROW - 1) - return FALSE; - - if (structPtr->selectedPos < GIFT_RIBBON_START_POS) - { - // Move right in normal ribbon row - if (structPtr->selectedPos < structPtr->numNormalRibbons - 1) - { - structPtr->selectedPos++; - return TRUE; - } - } - else - { - // Move right in gift ribbon row - if (column < structPtr->numGiftRibbons - 1) - { - structPtr->selectedPos++; - return TRUE; - } - } - return FALSE; -} - -static u32 GetRibbonsSummaryCurrentIndex(void) -{ - struct PokenavSub13 *structPtr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_LIST); - return structPtr->monList->currIndex; -} - -static u32 GetRibbonsSummaryMonListCount(void) -{ - struct PokenavSub13 *structPtr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_LIST); - return structPtr->monList->listCount; -} - -static void GetMonNicknameLevelGender(u8 *nick, u8 *level, u8 *gender) -{ - struct PokenavSub13 *structPtr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_LIST); - struct PokenavSub18 *mons = structPtr->monList; - struct PokenavMonList *monInfo = &mons->monData[mons->currIndex]; - - if (monInfo->boxId == TOTAL_BOXES_COUNT) - { - // Get info for party mon - struct Pokemon *mon = &gPlayerParty[monInfo->monId]; - GetMonData(mon, MON_DATA_NICKNAME, nick); - *level = GetLevelFromMonExp(mon); - *gender = GetMonGender(mon); - } - else - { - // Get info for PC box mon - struct BoxPokemon *boxMon = GetBoxedMonPtr(monInfo->boxId, monInfo->monId); - *gender = GetBoxMonGender(boxMon); - *level = GetLevelFromBoxMonExp(boxMon); - GetBoxMonData(boxMon, MON_DATA_NICKNAME, nick); - } - StringGetEnd10(nick); -} - -static void GetMonSpeciesPersonalityOtId(u16 *species, u32 *personality, u32 *otId) -{ - struct PokenavSub13 *structPtr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_LIST); - struct PokenavSub18 *mons = structPtr->monList; - struct PokenavMonList *monInfo = &mons->monData[mons->currIndex]; - - if (monInfo->boxId == TOTAL_BOXES_COUNT) - { - // Get info for party mon - struct Pokemon *mon = &gPlayerParty[monInfo->monId]; - *species = GetMonData(mon, MON_DATA_SPECIES); - *personality = GetMonData(mon, MON_DATA_PERSONALITY); - *otId = GetMonData(mon, MON_DATA_OT_ID); - } - else - { - // Get info for PC box mon - struct BoxPokemon *boxMon = GetBoxedMonPtr(monInfo->boxId, monInfo->monId); - *species = GetBoxMonData(boxMon, MON_DATA_SPECIES); - *personality = GetBoxMonData(boxMon, MON_DATA_PERSONALITY); - *otId = GetBoxMonData(boxMon, MON_DATA_OT_ID); - } -} - -static u32 GetCurrMonRibbonCount(void) -{ - struct PokenavSub13 *structPtr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_LIST); - struct PokenavSub18 *mons = structPtr->monList; - struct PokenavMonList *monInfo = &mons->monData[mons->currIndex]; - - if (monInfo->boxId == TOTAL_BOXES_COUNT) - return GetMonData(&gPlayerParty[monInfo->monId], MON_DATA_RIBBON_COUNT); - else - return GetBoxMonDataAt(monInfo->boxId, monInfo->monId, MON_DATA_RIBBON_COUNT); -} - -static void GetMonRibbons(struct PokenavSub13 *structPtr) -{ - u32 ribbonFlags; - s32 i, j; - struct PokenavSub18 *mons = structPtr->monList; - struct PokenavMonList *monInfo = &mons->monData[mons->currIndex]; - - if (monInfo->boxId == TOTAL_BOXES_COUNT) - ribbonFlags = GetMonData(&gPlayerParty[monInfo->monId], MON_DATA_RIBBONS); - else - ribbonFlags = GetBoxMonDataAt(monInfo->boxId, monInfo->monId, MON_DATA_RIBBONS); - - structPtr->numNormalRibbons = 0; - structPtr->numGiftRibbons = 0; - for (i = 0; i < ARRAY_COUNT(sRibbonData); i++) - { - // For all non-contest ribbons, numRibbons will be 1 if they have it, 0 if they don't - // For contest ribbons, numRibbons will be 0-4 - s32 numRibbons = ((1 << sRibbonData[i].numBits) - 1) & ribbonFlags; - if (!sRibbonData[i].isGiftRibbon) - { - for (j = 0; j < numRibbons; j++) - structPtr->ribbonIds[structPtr->numNormalRibbons++] = sRibbonData[i].ribbonId + j; - } - else - { - for (j = 0; j < numRibbons; j++) - structPtr->giftRibbonIds[structPtr->numGiftRibbons++] = sRibbonData[i].ribbonId + j; - } - ribbonFlags >>= sRibbonData[i].numBits; - } - - if (structPtr->numNormalRibbons != 0) - { - structPtr->normalRibbonLastRowStart = ((structPtr->numNormalRibbons - 1) / RIBBONS_PER_ROW) * RIBBONS_PER_ROW; - structPtr->selectedPos = 0; - } - else - { - // There are no normal ribbons, move cursor to first gift ribbon - structPtr->normalRibbonLastRowStart = 0; - structPtr->selectedPos = GIFT_RIBBON_START_POS; - } -} - -static u32 *GetNormalRibbonIds(u32 *size) -{ - struct PokenavSub13 *structPtr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_LIST); - *size = structPtr->numNormalRibbons; - return structPtr->ribbonIds; -} - -static u32 *GetGiftRibbonIds(u32 *size) -{ - struct PokenavSub13 *structPtr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_LIST); - *size = structPtr->numGiftRibbons; - return structPtr->giftRibbonIds; -} - -static u16 GetSelectedPosition(void) -{ - struct PokenavSub13 *structPtr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_LIST); - return structPtr->selectedPos; -} - -static u32 GetRibbonId(void) -{ - struct PokenavSub13 *structPtr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_LIST); - int ribbonPos = structPtr->selectedPos; - if (ribbonPos < FIRST_GIFT_RIBBON) - return structPtr->ribbonIds[ribbonPos]; - else - return structPtr->giftRibbonIds[ribbonPos - GIFT_RIBBON_START_POS]; -} - -bool32 OpenRibbonsSummaryMenu(void) -{ - struct PokenavSub14 *structPtr = AllocSubstruct(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_MENU, sizeof(struct PokenavSub14)); - if (structPtr == NULL) - return FALSE; - - structPtr->loopedTaskId = CreateLoopedTask(LoopedTask_OpenRibbonsSummaryMenu, 1); - structPtr->callback = GetCurrentLoopedTaskActive; - return TRUE; -} - -void CreateRibbonsSummaryLoopedTask(s32 id) -{ - struct PokenavSub14 *structPtr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_MENU); - structPtr->loopedTaskId = CreateLoopedTask(sRibbonsSummaryMenuLoopTaskFuncs[id], 1); - structPtr->callback = GetCurrentLoopedTaskActive; -} - -u32 IsRibbonsSummaryLoopedTaskActive(void) -{ - struct PokenavSub14 *structPtr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_MENU); - return structPtr->callback(); -} - -void FreeRibbonsSummaryScreen2(void) -{ - struct PokenavSub14 *structPtr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_MENU); - RemoveWindow(structPtr->ribbonCountWindowId); - RemoveWindow(structPtr->nameWindowId); - RemoveWindow(structPtr->listIdxWindowId); -#ifndef BUGFIX - RemoveWindow(structPtr->unusedWindowId); // Removing window, but window id is never set -#endif - DestroyRibbonsMonFrontPic(structPtr); - FreeSpriteTilesByTag(GFXTAG_RIBBON_ICONS_BIG); - FreeSpritePaletteByTag(PALTAG_RIBBON_ICONS_1); - FreeSpritePaletteByTag(PALTAG_RIBBON_ICONS_2); - FreeSpritePaletteByTag(PALTAG_RIBBON_ICONS_3); - FreeSpritePaletteByTag(PALTAG_RIBBON_ICONS_4); - FreeSpritePaletteByTag(PALTAG_RIBBON_ICONS_5); - FreeSpriteOamMatrix(structPtr->bigRibbonSprite); - DestroySprite(structPtr->bigRibbonSprite); - FreePokenavSubstruct(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_MENU); -} - -static bool32 GetCurrentLoopedTaskActive(void) -{ - struct PokenavSub14 *structPtr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_MENU); - return IsLoopedTaskActive(structPtr->loopedTaskId); -} - -static u32 LoopedTask_OpenRibbonsSummaryMenu(s32 state) -{ - struct PokenavSub14 *structPtr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_MENU); - switch (state) - { - case 0: - InitBgTemplates(sBgTemplates, ARRAY_COUNT(sBgTemplates)); - DecompressAndCopyTileDataToVram(2, gPokenavRibbonsSummaryBg_Gfx, 0, 0, 0); - SetBgTilemapBuffer(2, structPtr->tilemapBuffers[0]); - CopyToBgTilemapBuffer(2, gPokenavRibbonsSummaryBg_Tilemap, 0, 0); - CopyPaletteIntoBufferUnfaded(gPokenavRibbonsSummaryBg_Pal, 0x10, 0x20); - CopyBgTilemapBufferToVram(2); - return LT_INC_AND_PAUSE; - case 1: - if (!FreeTempTileDataBuffersIfPossible()) - { - BgDmaFill(1, 0, 0, 1); - DecompressAndCopyTileDataToVram(1, sRibbonIconsSmall_Gfx, 0, 1, 0); - SetBgTilemapBuffer(1, structPtr->tilemapBuffers[1]); - FillBgTilemapBufferRect_Palette0(1, 0, 0, 0, 32, 20); - CopyPaletteIntoBufferUnfaded(sRibbonIcons1_Pal, 0x20, 0xA0); - CopyPaletteIntoBufferUnfaded(sMonInfo_Pal, 0xA0, 0x20); - CopyBgTilemapBufferToVram(1); - return LT_INC_AND_PAUSE; - } - return LT_PAUSE; - case 2: - if (!FreeTempTileDataBuffersIfPossible()) - { - AddRibbonCountWindow(structPtr); - return LT_INC_AND_PAUSE; - } - return LT_PAUSE; - case 3: - if (!FreeTempTileDataBuffersIfPossible()) - { - AddRibbonSummaryMonNameWindow(structPtr); - return LT_INC_AND_PAUSE; - } - return LT_PAUSE; - case 4: - if (!FreeTempTileDataBuffersIfPossible()) - { - AddRibbonListIndexWindow(structPtr); - return LT_INC_AND_PAUSE; - } - return LT_PAUSE; - case 5: - if (!IsDma3ManagerBusyWithBgCopy()) - { - CopyBgTilemapBufferToVram(2); - return LT_INC_AND_PAUSE; - } - return LT_PAUSE; - case 6: - if (!IsDma3ManagerBusyWithBgCopy()) - { - ResetSpritesAndDrawMonFrontPic(structPtr); - return LT_INC_AND_CONTINUE; - } - return LT_PAUSE; - case 7: - DrawAllRibbonsSmall(structPtr); - PrintHelpBarText(HELPBAR_RIBBONS_LIST); - return LT_INC_AND_PAUSE; - case 8: - if (!IsDma3ManagerBusyWithBgCopy()) - { - CreateBigRibbonSprite(structPtr); - ChangeBgX(1, 0, BG_COORD_SET); - ChangeBgY(1, 0, BG_COORD_SET); - ChangeBgX(2, 0, BG_COORD_SET); - ChangeBgY(2, 0, BG_COORD_SET); - ShowBg(1); - ShowBg(2); - HideBg(3); - PokenavFadeScreen(1); - return LT_INC_AND_PAUSE; - } - return LT_PAUSE; - case 9: - if (IsPaletteFadeActive()) - return LT_PAUSE; - } - return LT_FINISH; -} - -static u32 LoopedTask_ExitRibbonsSummaryMenu(s32 state) -{ - switch (state) - { - case 0: - PlaySE(SE_SELECT); - PokenavFadeScreen(0); - return LT_INC_AND_PAUSE; - case 1: - if (IsPaletteFadeActive()) - return LT_PAUSE; - return LT_FINISH; - } - return LT_FINISH; -} - -static u32 LoopedTask_SwitchRibbonsSummaryMon(s32 state) -{ - struct PokenavSub14 *structPtr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_MENU); - switch (state) - { - case 0: - PlaySE(SE_SELECT); - SlideMonSpriteOff(structPtr); - return LT_INC_AND_PAUSE; - case 1: - if (!IsMonSpriteAnimating(structPtr)) - { - PrintRibbbonsSummaryMonInfo(structPtr); - return LT_INC_AND_CONTINUE; - } - return LT_PAUSE; - case 2: - DrawAllRibbonsSmall(structPtr); - return LT_INC_AND_CONTINUE; - case 3: - PrintRibbonsMonListIndex(structPtr); - return LT_INC_AND_CONTINUE; - case 4: - PrintCurrentMonRibbonCount(structPtr); - return LT_INC_AND_CONTINUE; - case 5: - if (!IsDma3ManagerBusyWithBgCopy()) - { - SlideMonSpriteOn(structPtr); - return LT_INC_AND_PAUSE; - } - return LT_PAUSE; - case 6: - if (IsMonSpriteAnimating(structPtr)) - return LT_PAUSE; - } - return LT_FINISH; -} - -static u32 LoopedTask_ExpandSelectedRibbon(s32 state) -{ - struct PokenavSub14 *structPtr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_MENU); - switch (state) - { - case 0: - PlaySE(SE_SELECT); - UpdateAndZoomInSelectedRibbon(structPtr); - return LT_INC_AND_PAUSE; - case 1: - if (!IsRibbonAnimating(structPtr)) - { - PrintRibbonNameAndDescription(structPtr); - PrintHelpBarText(HELPBAR_RIBBONS_CHECK); - return LT_INC_AND_PAUSE; - } - return LT_PAUSE; - case 2: - if (IsDma3ManagerBusyWithBgCopy()) - return LT_PAUSE; - } - return LT_FINISH; -} - -static u32 LoopedTask_MoveRibbonsCursorExpanded(s32 state) -{ - struct PokenavSub14 *structPtr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_MENU); - switch (state) - { - case 0: - PlaySE(SE_SELECT); - ZoomOutSelectedRibbon(structPtr); - return LT_INC_AND_PAUSE; - case 1: - if (!IsRibbonAnimating(structPtr)) - { - UpdateAndZoomInSelectedRibbon(structPtr); - return LT_INC_AND_PAUSE; - } - return LT_PAUSE; - case 2: - if (!IsRibbonAnimating(structPtr)) - { - PrintRibbonNameAndDescription(structPtr); - return LT_INC_AND_PAUSE; - } - return LT_PAUSE; - case 3: - if (IsDma3ManagerBusyWithBgCopy()) - return LT_PAUSE; - } - return LT_FINISH; -} - -static u32 LoopedTask_ShrinkExpandedRibbon(s32 state) -{ - struct PokenavSub14 *structPtr = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_MENU); - switch (state) - { - case 0: - PlaySE(SE_SELECT); - ZoomOutSelectedRibbon(structPtr); - return LT_INC_AND_PAUSE; - case 1: - if (!IsRibbonAnimating(structPtr)) - { - PrintCurrentMonRibbonCount(structPtr); - PrintHelpBarText(HELPBAR_RIBBONS_LIST); - return LT_INC_AND_PAUSE; - } - return LT_PAUSE; - case 2: - if (IsDma3ManagerBusyWithBgCopy()) - return LT_PAUSE; - } - return LT_FINISH; -} - -static const struct WindowTemplate sRibbonCountWindowTemplate = -{ - .bg = 2, - .tilemapLeft = 12, - .tilemapTop = 13, - .width = 16, - .height = 4, - .paletteNum = 1, - .baseBlock = 0x14, -}; - -static void AddRibbonCountWindow(struct PokenavSub14 *structPtr) -{ - structPtr->ribbonCountWindowId = AddWindow(&sRibbonCountWindowTemplate); - PutWindowTilemap(structPtr->ribbonCountWindowId); - PrintCurrentMonRibbonCount(structPtr); -} - -static void PrintCurrentMonRibbonCount(struct PokenavSub14 *structPtr) -{ - u8 color[] = {TEXT_COLOR_RED, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_LIGHT_GRAY}; - - ConvertIntToDecimalStringN(gStringVar1, GetCurrMonRibbonCount(), STR_CONV_MODE_LEFT_ALIGN, 2); - DynamicPlaceholderTextUtil_Reset(); - DynamicPlaceholderTextUtil_SetPlaceholderPtr(0, gStringVar1); - DynamicPlaceholderTextUtil_ExpandPlaceholders(gStringVar4, gText_RibbonsF700); - FillWindowPixelBuffer(structPtr->ribbonCountWindowId, PIXEL_FILL(4)); - AddTextPrinterParameterized3(structPtr->ribbonCountWindowId, FONT_NORMAL, 0, 1, color, TEXT_SKIP_DRAW, gStringVar4); - CopyWindowToVram(structPtr->ribbonCountWindowId, COPYWIN_GFX); -} - -static void PrintRibbonNameAndDescription(struct PokenavSub14 *structPtr) -{ - s32 i; - u32 ribbonId = GetRibbonId(); - u8 color[] = {TEXT_COLOR_RED, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_LIGHT_GRAY}; - - FillWindowPixelBuffer(structPtr->ribbonCountWindowId, PIXEL_FILL(4)); - if (ribbonId < FIRST_GIFT_RIBBON) - { - // Print normal ribbon name/description - for (i = 0; i < 2; i++) - AddTextPrinterParameterized3(structPtr->ribbonCountWindowId, FONT_NORMAL, 0, (i * 16) + 1, color, TEXT_SKIP_DRAW, gRibbonDescriptionPointers[ribbonId][i]); - } - else - { - // ribbonId here is one of the 'gift' ribbon slots, used to read - // its actual value from giftRibbons to determine which specific - // gift ribbon it is - ribbonId = gSaveBlock1Ptr->giftRibbons[ribbonId - FIRST_GIFT_RIBBON]; - - // If 0, this gift ribbon slot is unoccupied - if (ribbonId == 0) - return; - - // Print gift ribbon name/description - ribbonId--; - for (i = 0; i < 2; i++) - AddTextPrinterParameterized3(structPtr->ribbonCountWindowId, FONT_NORMAL, 0, (i * 16) + 1, color, TEXT_SKIP_DRAW, gGiftRibbonDescriptionPointers[ribbonId][i]); - } - - CopyWindowToVram(structPtr->ribbonCountWindowId, COPYWIN_GFX); -} - -static const struct WindowTemplate sRibbonSummaryMonNameWindowTemplate = -{ - .bg = 2, - .tilemapLeft = 14, - .tilemapTop = 1, - .width = 13, - .height = 2, - .paletteNum = 10, - .baseBlock = 0x54, -}; - -static void AddRibbonSummaryMonNameWindow(struct PokenavSub14 *structPtr) -{ - structPtr->nameWindowId = AddWindow(&sRibbonSummaryMonNameWindowTemplate); - PutWindowTilemap(structPtr->nameWindowId); - PrintRibbbonsSummaryMonInfo(structPtr); -} - -static const u8 sMaleIconString[] = _("{COLOR_HIGHLIGHT_SHADOW}{LIGHT_RED}{WHITE}{GREEN}♂{COLOR_HIGHLIGHT_SHADOW}{DARK_GRAY}{WHITE}{LIGHT_GRAY}"); -static const u8 sFemaleIconString[] = _("{COLOR_HIGHLIGHT_SHADOW}{LIGHT_GREEN}{WHITE}{BLUE}♀{COLOR_HIGHLIGHT_SHADOW}{DARK_GRAY}{WHITE}{LIGHT_GRAY}"); -static const u8 sGenderlessIconString[] = _("{UNK_SPACER}"); - -static void PrintRibbbonsSummaryMonInfo(struct PokenavSub14 *structPtr) -{ - const u8 *genderTxt; - u8 *txtPtr; - u8 level, gender; - u16 windowId = structPtr->nameWindowId; - - FillWindowPixelBuffer(windowId, PIXEL_FILL(1)); - GetMonNicknameLevelGender(gStringVar3, &level, &gender); - AddTextPrinterParameterized(windowId, FONT_NORMAL, gStringVar3, 0, 1, TEXT_SKIP_DRAW, NULL); - switch (gender) - { - case MON_MALE: - genderTxt = sMaleIconString; - break; - case MON_FEMALE: - genderTxt = sFemaleIconString; - break; - default: - genderTxt = sGenderlessIconString; - break; - } - - txtPtr = StringCopy(gStringVar1, genderTxt); - *(txtPtr++) = CHAR_SLASH; - *(txtPtr++) = CHAR_EXTRA_SYMBOL; - *(txtPtr++) = CHAR_LV_2; - ConvertIntToDecimalStringN(txtPtr, level, STR_CONV_MODE_LEFT_ALIGN, 3); - AddTextPrinterParameterized(windowId, FONT_NORMAL, gStringVar1, 60, 1, TEXT_SKIP_DRAW, NULL); - CopyWindowToVram(windowId, COPYWIN_GFX); -} - -static const struct WindowTemplate sRibbonMonListIndexWindowTemplate[] = -{ - { - .bg = 2, - .tilemapLeft = 1, - .tilemapTop = 5, - .width = 7, - .height = 2, - .paletteNum = 1, - .baseBlock = 0x6E, - }, - {}, -}; - -static void AddRibbonListIndexWindow(struct PokenavSub14 *structPtr) -{ - structPtr->listIdxWindowId = AddWindow(sRibbonMonListIndexWindowTemplate); - FillWindowPixelBuffer(structPtr->listIdxWindowId, PIXEL_FILL(1)); - PutWindowTilemap(structPtr->listIdxWindowId); - PrintRibbonsMonListIndex(structPtr); -} - -static void PrintRibbonsMonListIndex(struct PokenavSub14 *structPtr) -{ - s32 x; - u8 *txtPtr; - u32 id = GetRibbonsSummaryCurrentIndex() + 1; - u32 count = GetRibbonsSummaryMonListCount(); - - txtPtr = ConvertIntToDecimalStringN(gStringVar1, id, STR_CONV_MODE_RIGHT_ALIGN, 3); - *(txtPtr++) = CHAR_SLASH; - ConvertIntToDecimalStringN(txtPtr, count, STR_CONV_MODE_RIGHT_ALIGN, 3); - x = GetStringCenterAlignXOffset(FONT_NORMAL, gStringVar1, 56); - AddTextPrinterParameterized(structPtr->listIdxWindowId, FONT_NORMAL, gStringVar1, x, 1, TEXT_SKIP_DRAW, NULL); - CopyWindowToVram(structPtr->listIdxWindowId, COPYWIN_GFX); -} - -static void ResetSpritesAndDrawMonFrontPic(struct PokenavSub14 *structPtr) -{ - u16 species; - u32 personality, otId; - - GetMonSpeciesPersonalityOtId(&species, &personality, &otId); - ResetAllPicSprites(); - structPtr->monSpriteId = DrawRibbonsMonFrontPic(MON_SPRITE_X_ON, MON_SPRITE_Y); - PokenavFillPalette(15, 0); -} - -static void DestroyRibbonsMonFrontPic(struct PokenavSub14 *structPtr) -{ - FreeAndDestroyMonPicSprite(structPtr->monSpriteId); -} - -// x and y arguments are ignored -// y is always given as MON_SPRITE_Y -// x is given as either MON_SPRITE_X_ON or MON_SPRITE_X_OFF (but ignored and MON_SPRITE_X_ON is used) -static u16 DrawRibbonsMonFrontPic(s32 x, s32 y) -{ - u16 species, spriteId; - u32 personality, otId; - - GetMonSpeciesPersonalityOtId(&species, &personality, &otId); - spriteId = CreateMonPicSprite_HandleDeoxys(species, otId, personality, TRUE, MON_SPRITE_X_ON, MON_SPRITE_Y, 15, TAG_NONE); - gSprites[spriteId].oam.priority = 0; - return spriteId; -} - -static void SlideMonSpriteOff(struct PokenavSub14 *structPtr) -{ - StartMonSpriteSlide(&gSprites[structPtr->monSpriteId], MON_SPRITE_X_ON, MON_SPRITE_X_OFF, 6); -} - -static void SlideMonSpriteOn(struct PokenavSub14 *structPtr) -{ - // Switch to new mon sprite - FreeAndDestroyMonPicSprite(structPtr->monSpriteId); - structPtr->monSpriteId = DrawRibbonsMonFrontPic(MON_SPRITE_X_OFF, MON_SPRITE_Y); - - // Slide on - StartMonSpriteSlide(&gSprites[structPtr->monSpriteId], MON_SPRITE_X_OFF, MON_SPRITE_X_ON, 6); -} - -// Is Pokémon summary sprite still sliding off/on -static bool32 IsMonSpriteAnimating(struct PokenavSub14 *structPtr) -{ - return (gSprites[structPtr->monSpriteId].callback != SpriteCallbackDummy); -} - -#define sCurrX data[0] -#define sMoveIncr data[1] -#define sTime data[2] -#define sDestX data[3] - -static void StartMonSpriteSlide(struct Sprite *sprite, s32 startX, s32 destX, s32 time) -{ - u32 delta = destX - startX; - - sprite->x = startX; - sprite->sCurrX = startX << 4; - sprite->sMoveIncr = (delta << 4) / time; - sprite->sTime = time; - sprite->sDestX = destX; - - sprite->callback = SpriteCB_MonSpriteSlide; -} - -static void SpriteCB_MonSpriteSlide(struct Sprite *sprite) -{ - if (sprite->sTime != 0) - { - sprite->sTime--; - sprite->sCurrX += sprite->sMoveIncr; - sprite->x = sprite->sCurrX >> 4; - if (sprite->x <= MON_SPRITE_X_OFF) - sprite->invisible = TRUE; - else - sprite->invisible = FALSE; - } - else - { - sprite->x = sprite->sDestX; - sprite->callback = SpriteCallbackDummy; - } -} - -#undef sCurrX -#undef sMoveIncr -#undef sTime -#undef sDestX - -static void DrawAllRibbonsSmall(struct PokenavSub14 *structPtr) -{ - u32 *ribbonIds; - - ClearRibbonsSummaryBg(); - - ribbonIds = GetNormalRibbonIds(&sRibbonDraw_Total); - for (sRibbonDraw_Current = 0; sRibbonDraw_Current < sRibbonDraw_Total; sRibbonDraw_Current++) - DrawRibbonSmall(sRibbonDraw_Current, *(ribbonIds++)); - - ribbonIds = GetGiftRibbonIds(&sRibbonDraw_Total); - for (sRibbonDraw_Current = 0; sRibbonDraw_Current < sRibbonDraw_Total; sRibbonDraw_Current++) - DrawRibbonSmall(sRibbonDraw_Current + GIFT_RIBBON_START_POS, *(ribbonIds++)); - - CopyBgTilemapBufferToVram(1); -} - -// Redundant, the same FillBg is called in LoopedTask_OpenRibbonsSummaryMenu -static void ClearRibbonsSummaryBg(void) -{ - FillBgTilemapBufferRect_Palette0(1, 0, 0, 0, 32, 20); -} - -static void DrawRibbonSmall(u32 i, u32 ribbonId) -{ - u16 bgData[4]; - u32 destX = (i % RIBBONS_PER_ROW) * 2 + 11; - u32 destY = (i / RIBBONS_PER_ROW) * 2 + 4; - - BufferSmallRibbonGfxData(bgData, ribbonId); - CopyToBgTilemapBufferRect(1, bgData, destX, destY, 2, 2); -} - -// Below correspond to a ribbon icon in ribbons/icons.png and ribbons/icons_big.png; 0 at top, 11 at bottom -enum { - RIBBONGFX_CHAMPION, - RIBBONGFX_CONTEST_NORMAL, - RIBBONGFX_CONTEST_SUPER, - RIBBONGFX_CONTEST_HYPER, - RIBBONGFX_CONTEST_MASTER, - RIBBONGFX_WINNING, - RIBBONGFX_VICTORY, - RIBBONGFX_ARTIST, - RIBBONGFX_EFFORT, - RIBBONGFX_GIFT_1, - RIBBONGFX_GIFT_2, - RIBBONGFX_GIFT_3, -}; - -#define TO_PAL_OFFSET(palNum)((palNum) - PALTAG_RIBBON_ICONS_1) - -struct -{ - u16 tileNumOffset; - u16 palNumOffset; -} static const sRibbonGfxData[] = -{ - [CHAMPION_RIBBON] = { RIBBONGFX_CHAMPION, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_1)}, - [COOL_RIBBON_NORMAL] = { RIBBONGFX_CONTEST_NORMAL, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_1)}, - [COOL_RIBBON_SUPER] = { RIBBONGFX_CONTEST_SUPER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_1)}, - [COOL_RIBBON_HYPER] = { RIBBONGFX_CONTEST_HYPER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_1)}, - [COOL_RIBBON_MASTER] = { RIBBONGFX_CONTEST_MASTER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_1)}, - [BEAUTY_RIBBON_NORMAL] = { RIBBONGFX_CONTEST_NORMAL, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_2)}, - [BEAUTY_RIBBON_SUPER] = { RIBBONGFX_CONTEST_SUPER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_2)}, - [BEAUTY_RIBBON_HYPER] = { RIBBONGFX_CONTEST_HYPER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_2)}, - [BEAUTY_RIBBON_MASTER] = { RIBBONGFX_CONTEST_MASTER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_2)}, - [CUTE_RIBBON_NORMAL] = { RIBBONGFX_CONTEST_NORMAL, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_3)}, - [CUTE_RIBBON_SUPER] = { RIBBONGFX_CONTEST_SUPER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_3)}, - [CUTE_RIBBON_HYPER] = { RIBBONGFX_CONTEST_HYPER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_3)}, - [CUTE_RIBBON_MASTER] = { RIBBONGFX_CONTEST_MASTER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_3)}, - [SMART_RIBBON_NORMAL] = { RIBBONGFX_CONTEST_NORMAL, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_4)}, - [SMART_RIBBON_SUPER] = { RIBBONGFX_CONTEST_SUPER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_4)}, - [SMART_RIBBON_HYPER] = { RIBBONGFX_CONTEST_HYPER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_4)}, - [SMART_RIBBON_MASTER] = { RIBBONGFX_CONTEST_MASTER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_4)}, - [TOUGH_RIBBON_NORMAL] = { RIBBONGFX_CONTEST_NORMAL, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_5)}, - [TOUGH_RIBBON_SUPER] = { RIBBONGFX_CONTEST_SUPER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_5)}, - [TOUGH_RIBBON_HYPER] = { RIBBONGFX_CONTEST_HYPER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_5)}, - [TOUGH_RIBBON_MASTER] = { RIBBONGFX_CONTEST_MASTER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_5)}, - [WINNING_RIBBON] = { RIBBONGFX_WINNING, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_1)}, - [VICTORY_RIBBON] = { RIBBONGFX_VICTORY, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_1)}, - [ARTIST_RIBBON] = { RIBBONGFX_ARTIST, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_2)}, - [EFFORT_RIBBON] = { RIBBONGFX_EFFORT, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_3)}, - [MARINE_RIBBON] = { RIBBONGFX_GIFT_1, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_2)}, - [LAND_RIBBON] = { RIBBONGFX_GIFT_1, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_4)}, - [SKY_RIBBON] = { RIBBONGFX_GIFT_1, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_5)}, - [COUNTRY_RIBBON] = { RIBBONGFX_GIFT_2, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_4)}, - [NATIONAL_RIBBON] = { RIBBONGFX_GIFT_2, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_5)}, - [EARTH_RIBBON] = { RIBBONGFX_GIFT_3, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_1)}, - [WORLD_RIBBON] = { RIBBONGFX_GIFT_3, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_2)}, -}; - -#undef TO_PAL_OFFSET - -static void BufferSmallRibbonGfxData(u16 *dst, u32 ribbonId) -{ - u16 palNum = sRibbonGfxData[ribbonId].palNumOffset + 2; - u16 tileNum = (sRibbonGfxData[ribbonId].tileNumOffset * 2) + 1; - - dst[0] = tileNum | (palNum << 12); - dst[1] = tileNum | (palNum << 12) | 0x400; - dst[2] = (tileNum + 1) | (palNum << 12); - dst[3] = (tileNum + 1) | (palNum << 12) | 0x400; -} - -static const struct CompressedSpriteSheet sSpriteSheet_RibbonIconsBig = -{ - sRibbonIconsBig_Gfx, 0x1800, GFXTAG_RIBBON_ICONS_BIG -}; - -static const struct SpritePalette sSpritePalettes_RibbonIcons[] = -{ - {sRibbonIcons1_Pal, PALTAG_RIBBON_ICONS_1}, - {sRibbonIcons2_Pal, PALTAG_RIBBON_ICONS_2}, - {sRibbonIcons3_Pal, PALTAG_RIBBON_ICONS_3}, - {sRibbonIcons4_Pal, PALTAG_RIBBON_ICONS_4}, - {sRibbonIcons5_Pal, PALTAG_RIBBON_ICONS_5}, - {}, -}; - -static const struct OamData sOamData_RibbonIconBig = -{ - .y = 0, - .affineMode = ST_OAM_AFFINE_NORMAL, - .objMode = ST_OAM_OBJ_NORMAL, - .mosaic = 0, - .bpp = ST_OAM_4BPP, - .shape = SPRITE_SHAPE(32x32), - .x = 0, - .matrixNum = 0, - .size = SPRITE_SIZE(32x32), - .tileNum = 0, - .priority = 1, - .paletteNum = 0, - .affineParam = 0 -}; - -static const union AffineAnimCmd sAffineAnim_RibbonIconBig_Normal[] = -{ - AFFINEANIMCMD_FRAME(128, 128, 0, 0), - AFFINEANIMCMD_END -}; - -static const union AffineAnimCmd sAffineAnim_RibbonIconBig_ZoomIn[] = -{ - AFFINEANIMCMD_FRAME(128, 128, 0, 0), - AFFINEANIMCMD_FRAME(32, 32, 0, 4), - AFFINEANIMCMD_END -}; - -static const union AffineAnimCmd sAffineAnim_RibbonIconBig_ZoomOut[] = -{ - AFFINEANIMCMD_FRAME(256, 256, 0, 0), - AFFINEANIMCMD_FRAME(-32, -32, 0, 4), - AFFINEANIMCMD_END -}; - -enum { - RIBBONANIM_NORMAL, - RIBBONANIM_ZOOM_IN, - RIBBONANIM_ZOOM_OUT, -}; - -static const union AffineAnimCmd *const sAffineAnims_RibbonIconBig[] = -{ - [RIBBONANIM_NORMAL] = sAffineAnim_RibbonIconBig_Normal, - [RIBBONANIM_ZOOM_IN] = sAffineAnim_RibbonIconBig_ZoomIn, - [RIBBONANIM_ZOOM_OUT] = sAffineAnim_RibbonIconBig_ZoomOut -}; - -static const struct SpriteTemplate sSpriteTemplate_RibbonIconBig = -{ - .tileTag = GFXTAG_RIBBON_ICONS_BIG, - .paletteTag = PALTAG_RIBBON_ICONS_1, - .oam = &sOamData_RibbonIconBig, - .anims = gDummySpriteAnimTable, - .images = NULL, - .affineAnims = sAffineAnims_RibbonIconBig, - .callback = SpriteCallbackDummy, -}; - -// Create dummy sprite to be used for the zoomed in version of the selected ribbon -static void CreateBigRibbonSprite(struct PokenavSub14 *structPtr) -{ - u8 spriteId; - - LoadCompressedSpriteSheet(&sSpriteSheet_RibbonIconsBig); - Pokenav_AllocAndLoadPalettes(sSpritePalettes_RibbonIcons); - - spriteId = CreateSprite(&sSpriteTemplate_RibbonIconBig, 0, 0, 0); - structPtr->bigRibbonSprite = &gSprites[spriteId]; - structPtr->bigRibbonSprite->invisible = TRUE; -} - -#define sInvisibleWhenDone data[0] - -static void UpdateAndZoomInSelectedRibbon(struct PokenavSub14 *structPtr) -{ - u32 ribbonId; - s32 position = GetSelectedPosition(); - s32 x = (position % RIBBONS_PER_ROW) * 16 + 96; - s32 y = (position / RIBBONS_PER_ROW) * 16 + 40; - - structPtr->bigRibbonSprite->x = x; - structPtr->bigRibbonSprite->y = y; - - // Set new selected ribbon's gfx data - ribbonId = GetRibbonId(); - structPtr->bigRibbonSprite->oam.tileNum = (sRibbonGfxData[ribbonId].tileNumOffset * 16) + GetSpriteTileStartByTag(GFXTAG_RIBBON_ICONS_BIG); - structPtr->bigRibbonSprite->oam.paletteNum = IndexOfSpritePaletteTag(sRibbonGfxData[ribbonId].palNumOffset + PALTAG_RIBBON_ICONS_1); - - // Start zoom in animation - StartSpriteAffineAnim(structPtr->bigRibbonSprite, RIBBONANIM_ZOOM_IN); - structPtr->bigRibbonSprite->invisible = FALSE; - structPtr->bigRibbonSprite->sInvisibleWhenDone = FALSE; - structPtr->bigRibbonSprite->callback = SpriteCB_WaitForRibbonAnimation; -} - -// Start animation to zoom out of selected ribbon -static void ZoomOutSelectedRibbon(struct PokenavSub14 *structPtr) -{ - structPtr->bigRibbonSprite->sInvisibleWhenDone = TRUE; - StartSpriteAffineAnim(structPtr->bigRibbonSprite, RIBBONANIM_ZOOM_OUT); - structPtr->bigRibbonSprite->callback = SpriteCB_WaitForRibbonAnimation; -} - -static bool32 IsRibbonAnimating(struct PokenavSub14 *structPtr) -{ - return (structPtr->bigRibbonSprite->callback != SpriteCallbackDummy); -} - -static void SpriteCB_WaitForRibbonAnimation(struct Sprite *sprite) -{ - if (sprite->affineAnimEnded) - { - sprite->invisible = sprite->sInvisibleWhenDone; - sprite->callback = SpriteCallbackDummy; - } -} diff --git a/src/pokenav_ribbons_list.c b/src/pokenav_ribbons_list.c new file mode 100644 index 000000000..b5d412e12 --- /dev/null +++ b/src/pokenav_ribbons_list.c @@ -0,0 +1,746 @@ +#include "global.h" +#include "pokenav.h" +#include "bg.h" +#include "menu.h" +#include "window.h" +#include "sound.h" +#include "string_util.h" +#include "international_string_util.h" +#include "constants/songs.h" + +enum +{ + RIBBONS_MON_LIST_FUNC_NONE, + RIBBONS_MON_LIST_FUNC_MOVE_UP, + RIBBONS_MON_LIST_FUNC_MOVE_DOWN, + RIBBONS_MON_LIST_FUNC_PAGE_UP, + RIBBONS_MON_LIST_FUNC_PAGE_DOWN, + RIBBONS_MON_LIST_FUNC_EXIT, + RIBBONS_MON_LIST_FUNC_OPEN_RIBBONS_SUMMARY +}; + + +struct Pokenav_RibbonsMonList +{ + u32 (*callback)(struct Pokenav_RibbonsMonList*); + u32 loopedTaskId; + u16 winid; + s32 boxId; + s32 monId; + u32 changeBgs; + u32 saveMonList; + struct PokenavSub18 *monList; +}; + +struct Pokenav_RibbonsMonMenu +{ + bool32 (*callback)(void); + u32 loopedTaskId; + u16 winid; + bool32 fromSummary; + u8 buff[BG_SCREEN_SIZE]; +}; + +static u32 HandleRibbonsMonListInput_WaitListInit(struct Pokenav_RibbonsMonList *); +static u32 HandleRibbonsMonListInput(struct Pokenav_RibbonsMonList *); +static u32 RibbonsMonMenu_ReturnToMainMenu(struct Pokenav_RibbonsMonList *); +static u32 RibbonsMonMenu_ToSummaryScreen(struct Pokenav_RibbonsMonList *); +static u32 BuildPartyMonRibbonList(s32); +static u32 InitBoxMonRibbonList(s32); +static u32 BuildBoxMonRibbonList(s32); +static u32 GetMonRibbonListLoopTaskFunc(s32); +static void InsertMonListItem(struct Pokenav_RibbonsMonList *, struct PokenavMonList *); +static u32 LoopedTask_OpenRibbonsMonList(s32); +static bool32 GetRibbonsMonCurrentLoopedTaskActive(void); +static u32 LoopedTask_RibbonsListMoveCursorUp(s32); +static u32 LoopedTask_RibbonsListMoveCursorDown(s32); +static u32 LoopedTask_RibbonsListMovePageUp(s32); +static u32 LoopedTask_RibbonsListMovePageDown(s32); +static u32 LoopedTask_RibbonsListReturnToMainMenu(s32); +static u32 LoopedTask_RibbonsListOpenSummary(s32); +static void DrawListIndexNumber(s32, s32, s32); +static void AddRibbonsMonListWindow(struct Pokenav_RibbonsMonMenu *); +static void UpdateIndexNumberDisplay(struct Pokenav_RibbonsMonMenu *); +static void InitMonRibbonPokenavListMenuTemplate(void); +static void BufferRibbonMonInfoText(struct PokenavMonList *, u8 *); + +static const LoopedTask sMonRibbonListLoopTaskFuncs[] = +{ + BuildPartyMonRibbonList, + InitBoxMonRibbonList, + BuildBoxMonRibbonList +}; + +static const u16 sMonRibbonListFramePal[] = INCBIN_U16("graphics/pokenav/ribbons/list_bg.gbapal"); +static const u32 sMonRibbonListFrameTiles[] = INCBIN_U32("graphics/pokenav/ribbons/list_bg.4bpp.lz"); +static const u32 sMonRibbonListFrameTilemap[] = INCBIN_U32("graphics/pokenav/ribbons/list_bg.bin.lz"); +static const u16 sMonRibbonListUi_Pal[] = INCBIN_U16("graphics/pokenav/ribbons/list_ui.gbapal"); + +static const struct BgTemplate sMonRibbonListBgTemplates[] = +{ + { + .bg = 1, + .charBaseIndex = 1, + .mapBaseIndex = 0x06, + .screenSize = 0, + .paletteMode = 0, + .priority = 2, + .baseTile = 0 + }, { + .bg = 2, + .charBaseIndex = 2, + .mapBaseIndex = 0x07, + .screenSize = 0, + .paletteMode = 0, + .priority = 3, + .baseTile = 0 + } +}; + +static const LoopedTask sRibbonsMonMenuLoopTaskFuncs[] = +{ + [RIBBONS_MON_LIST_FUNC_NONE] = NULL, + [RIBBONS_MON_LIST_FUNC_MOVE_UP] = LoopedTask_RibbonsListMoveCursorUp, + [RIBBONS_MON_LIST_FUNC_MOVE_DOWN] = LoopedTask_RibbonsListMoveCursorDown, + [RIBBONS_MON_LIST_FUNC_PAGE_UP] = LoopedTask_RibbonsListMovePageUp, + [RIBBONS_MON_LIST_FUNC_PAGE_DOWN] = LoopedTask_RibbonsListMovePageDown, + [RIBBONS_MON_LIST_FUNC_EXIT] = LoopedTask_RibbonsListReturnToMainMenu, + [RIBBONS_MON_LIST_FUNC_OPEN_RIBBONS_SUMMARY] = LoopedTask_RibbonsListOpenSummary +}; + +static const struct WindowTemplate sRibbonsMonListWindowTemplate = +{ + .bg = 1, + .tilemapLeft = 1, + .tilemapTop = 6, + .width = 7, + .height = 2, + .paletteNum = 1, + .baseBlock = 20 +}; + +static const u8 sText_MaleSymbol[] = _("{COLOR_HIGHLIGHT_SHADOW}{LIGHT_RED}{WHITE}{GREEN}♂{COLOR_HIGHLIGHT_SHADOW}{DARK_GRAY}{WHITE}{LIGHT_GRAY}"); +static const u8 sText_FemaleSymbol[] = _("{COLOR_HIGHLIGHT_SHADOW}{LIGHT_GREEN}{WHITE}{BLUE}♀{COLOR_HIGHLIGHT_SHADOW}{DARK_GRAY}{WHITE}{LIGHT_GRAY}"); +static const u8 sText_NoGenderSymbol[] = _("{UNK_SPACER}"); + +bool32 PokenavCallback_Init_MonRibbonList(void) +{ + struct Pokenav_RibbonsMonList *list = AllocSubstruct(POKENAV_SUBSTRUCT_RIBBONS_MON_LIST, sizeof(struct Pokenav_RibbonsMonList)); + if (list == NULL) + return FALSE; + + list->monList = AllocSubstruct(POKENAV_SUBSTRUCT_MON_LIST, sizeof(struct PokenavSub18)); + if (list->monList == NULL) + return FALSE; + + list->callback = HandleRibbonsMonListInput_WaitListInit; + list->loopedTaskId = CreateLoopedTask(GetMonRibbonListLoopTaskFunc, 1); + list->changeBgs = 0; + return TRUE; +} + +bool32 PokenavCallback_Init_RibbonsMonListFromSummary(void) +{ + struct Pokenav_RibbonsMonList *list = AllocSubstruct(POKENAV_SUBSTRUCT_RIBBONS_MON_LIST, sizeof(struct Pokenav_RibbonsMonList)); + if (list == NULL) + return FALSE; + + list->monList = GetSubstructPtr(POKENAV_SUBSTRUCT_MON_LIST); + list->callback = HandleRibbonsMonListInput; + list->changeBgs = 1; + return TRUE; +} + +u32 GetRibbonsMonListCallback(void) +{ + struct Pokenav_RibbonsMonList *list = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_LIST); + return list->callback(list); +} + +void FreeRibbonsMonList(void) +{ + struct Pokenav_RibbonsMonList *list = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_LIST); + if (!list->saveMonList) + FreePokenavSubstruct(POKENAV_SUBSTRUCT_MON_LIST); + FreePokenavSubstruct(POKENAV_SUBSTRUCT_RIBBONS_MON_LIST); +} + +static u32 HandleRibbonsMonListInput_WaitListInit(struct Pokenav_RibbonsMonList *list) +{ + if (!IsLoopedTaskActive(list->loopedTaskId)) + list->callback = HandleRibbonsMonListInput; + return 0; +} + +static u32 HandleRibbonsMonListInput(struct Pokenav_RibbonsMonList *list) +{ + if (JOY_REPEAT(DPAD_UP)) + return RIBBONS_MON_LIST_FUNC_MOVE_UP; + if (JOY_REPEAT(DPAD_DOWN)) + return RIBBONS_MON_LIST_FUNC_MOVE_DOWN; + if (JOY_NEW(DPAD_LEFT)) + return RIBBONS_MON_LIST_FUNC_PAGE_UP; + if (JOY_NEW(DPAD_RIGHT)) + return RIBBONS_MON_LIST_FUNC_PAGE_DOWN; + if (JOY_NEW(B_BUTTON)) + { + list->saveMonList = 0; + list->callback = RibbonsMonMenu_ReturnToMainMenu; + return RIBBONS_MON_LIST_FUNC_EXIT; + } + if (JOY_NEW(A_BUTTON)) + { + list->monList->currIndex = GetSelectedPokenavListIndex(); + list->saveMonList = 1; + list->callback = RibbonsMonMenu_ToSummaryScreen; + return RIBBONS_MON_LIST_FUNC_OPEN_RIBBONS_SUMMARY; + } + return RIBBONS_MON_LIST_FUNC_NONE; +} + +static u32 RibbonsMonMenu_ReturnToMainMenu(struct Pokenav_RibbonsMonList *list) +{ + return POKENAV_MAIN_MENU_CURSOR_ON_RIBBONS; +} + +static u32 RibbonsMonMenu_ToSummaryScreen(struct Pokenav_RibbonsMonList *list) +{ + return POKENAV_RIBBONS_SUMMARY_SCREEN; +} + +static u32 UpdateMonListBgs(void) +{ + struct Pokenav_RibbonsMonList *list = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_LIST); + return list->changeBgs; +} + +static struct PokenavMonList *GetMonRibbonMonListData(void) +{ + struct Pokenav_RibbonsMonList * list = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_LIST); + return list->monList->monData; +} + +static s32 GetRibbonsMonListCount(void) +{ + struct Pokenav_RibbonsMonList * list = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_LIST); + return list->monList->listCount; +} + +//unused +static s32 GetMonRibbonSelectedMonData(void) +{ + struct Pokenav_RibbonsMonList * list = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_LIST); + s32 idx = GetSelectedPokenavListIndex(); + return list->monList->monData[idx].data; +} + +static s32 GetRibbonListMenuCurrIndex(void) +{ + struct Pokenav_RibbonsMonList * list = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_LIST); + return list->monList->currIndex; +} + +static u32 GetMonRibbonListLoopTaskFunc(s32 state) +{ + return sMonRibbonListLoopTaskFuncs[state](state); +} + +static u32 BuildPartyMonRibbonList(s32 state) +{ + s32 i; + struct PokenavMonList item; + struct Pokenav_RibbonsMonList * list = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_LIST); + + list->monList->listCount = 0; + list->monList->currIndex = 0; + item.boxId = TOTAL_BOXES_COUNT; + for (i = 0; i < PARTY_SIZE; i++) + { + struct Pokemon * pokemon = &gPlayerParty[i]; + if (!GetMonData(pokemon, MON_DATA_SANITY_HAS_SPECIES)) + return LT_INC_AND_CONTINUE; + if (!GetMonData(pokemon, MON_DATA_SANITY_IS_EGG) && !GetMonData(pokemon, MON_DATA_SANITY_IS_BAD_EGG)) + { + u32 ribbonCount = GetMonData(pokemon, MON_DATA_RIBBON_COUNT); + if (ribbonCount != 0) + { + item.monId = i; + item.data = ribbonCount; + InsertMonListItem(list, &item); + } + } + } + + return LT_INC_AND_CONTINUE; +} + +static u32 InitBoxMonRibbonList(s32 state) +{ + struct Pokenav_RibbonsMonList *list = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_LIST); + list->monId = 0; + list->boxId = 0; + return LT_INC_AND_CONTINUE; +} + +static u32 BuildBoxMonRibbonList(s32 state) +{ + struct Pokenav_RibbonsMonList * list = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_LIST); + s32 boxId = list->boxId; + s32 monId = list->monId; + s32 boxCount = 0; + struct PokenavMonList item; + + while (boxId < TOTAL_BOXES_COUNT) + { + while (monId < IN_BOX_COUNT) + { + if (CheckBoxMonSanityAt(boxId, monId)) + { + u32 ribbonCount = GetBoxMonDataAt(boxId, monId, MON_DATA_RIBBON_COUNT); + if (ribbonCount != 0) + { + item.boxId = boxId; + item.monId = monId; + item.data = ribbonCount; + InsertMonListItem(list, &item); + } + } + boxCount++; + monId++; + if (boxCount > TOTAL_BOXES_COUNT) + { + list->boxId = boxId; + list->monId = monId; + return LT_CONTINUE; + } + } + monId = 0; + boxId++; + } + + list->changeBgs = 1; + return LT_FINISH; +} + +static void InsertMonListItem(struct Pokenav_RibbonsMonList *list, struct PokenavMonList *item) +{ + u32 left = 0; + u32 right = list->monList->listCount; + u32 insertionIdx = left + (right - left) / 2; + + while (right != insertionIdx) + { + if (item->data > list->monList->monData[insertionIdx].data) + right = insertionIdx; + else + left = insertionIdx + 1; + insertionIdx = left + (right - left) / 2; + } + for (right = list->monList->listCount; right > insertionIdx; right--) + list->monList->monData[right] = list->monList->monData[right - 1]; + list->monList->monData[insertionIdx] = *item; + list->monList->listCount++; +} + +// Unused +static bool32 PlayerHasRibbonsMon(void) +{ + s32 i, j; + + for (i = 0; i < PARTY_SIZE; i++) + { + struct Pokemon *mon = &gPlayerParty[i]; + if (!GetMonData(mon, MON_DATA_SANITY_HAS_SPECIES)) + continue; + if (GetMonData(mon, MON_DATA_SANITY_IS_EGG)) + continue; + if (GetMonData(mon, MON_DATA_RIBBONS)) + return TRUE; + } + + for (i = 0; i < TOTAL_BOXES_COUNT; i++) + { + for (j = 0; j < IN_BOX_COUNT; j++) + { + if (!CheckBoxMonSanityAt(i, j)) + continue; + if (GetBoxMonDataAt(i, j, MON_DATA_RIBBONS)) + return TRUE; + } + } + + return FALSE; +} + +bool32 OpenRibbonsMonList(void) +{ + struct Pokenav_RibbonsMonMenu *menu = AllocSubstruct(POKENAV_SUBSTRUCT_RIBBONS_MON_MENU, sizeof(struct Pokenav_RibbonsMonMenu)); + if (menu == NULL) + return FALSE; + menu->loopedTaskId = CreateLoopedTask(LoopedTask_OpenRibbonsMonList, 1); + menu->callback = GetRibbonsMonCurrentLoopedTaskActive; + menu->fromSummary = FALSE; + return TRUE; +} + +bool32 OpenRibbonsMonListFromRibbonsSummary(void) +{ + struct Pokenav_RibbonsMonMenu *menu = AllocSubstruct(POKENAV_SUBSTRUCT_RIBBONS_MON_MENU, sizeof(struct Pokenav_RibbonsMonMenu)); + if (menu == NULL) + return FALSE; + menu->loopedTaskId = CreateLoopedTask(LoopedTask_OpenRibbonsMonList, 1); + menu->callback = GetRibbonsMonCurrentLoopedTaskActive; + menu->fromSummary = TRUE; + return TRUE; +} + +void CreateRibbonsMonListLoopedTask(s32 idx) +{ + struct Pokenav_RibbonsMonMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_MENU); + menu->loopedTaskId = CreateLoopedTask(sRibbonsMonMenuLoopTaskFuncs[idx], 1); + menu->callback = GetRibbonsMonCurrentLoopedTaskActive; +} + +bool32 IsRibbonsMonListLoopedTaskActive(void) +{ + struct Pokenav_RibbonsMonMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_MENU); + return menu->callback(); +} + +bool32 GetRibbonsMonCurrentLoopedTaskActive(void) +{ + struct Pokenav_RibbonsMonMenu * menu = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_MENU); + return IsLoopedTaskActive(menu->loopedTaskId); +} + +void FreeRibbonsMonMenu(void) +{ + struct Pokenav_RibbonsMonMenu * menu = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_MENU); + sub_81C8234(); + RemoveWindow(menu->winid); + FreePokenavSubstruct(POKENAV_SUBSTRUCT_RIBBONS_MON_MENU); +} + +static u32 LoopedTask_OpenRibbonsMonList(s32 state) +{ + struct Pokenav_RibbonsMonMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_MENU); + switch (state) + { + case 0: + InitBgTemplates(sMonRibbonListBgTemplates, ARRAY_COUNT(sMonRibbonListBgTemplates)); + DecompressAndCopyTileDataToVram(1, sMonRibbonListFrameTiles, 0, 0, 0); + SetBgTilemapBuffer(1, menu->buff); + CopyToBgTilemapBuffer(1, sMonRibbonListFrameTilemap, 0, 0); + CopyPaletteIntoBufferUnfaded(sMonRibbonListFramePal, 0x10, 0x20); + CopyBgTilemapBufferToVram(1); + return LT_INC_AND_PAUSE; + case 1: + if (FreeTempTileDataBuffersIfPossible()) + return LT_PAUSE; + if (!UpdateMonListBgs()) + return LT_PAUSE; + ChangeBgX(1, 0, BG_COORD_SET); + ChangeBgY(1, 0, BG_COORD_SET); + ShowBg(1); + return LT_INC_AND_PAUSE; + case 2: + if (FreeTempTileDataBuffersIfPossible()) + return LT_PAUSE; + CopyPaletteIntoBufferUnfaded(sMonRibbonListUi_Pal, 0x20, 0x20); + InitMonRibbonPokenavListMenuTemplate(); + return LT_INC_AND_PAUSE; + case 3: + if (sub_81C8224()) + return LT_PAUSE; + AddRibbonsMonListWindow(menu); + return LT_INC_AND_PAUSE; + case 4: + if (FreeTempTileDataBuffersIfPossible()) + return LT_PAUSE; + ShowBg(2); + HideBg(3); + PrintHelpBarText(HELPBAR_RIBBONS_MON_LIST); + PokenavFadeScreen(1); + if (!menu->fromSummary) + { + LoadLeftHeaderGfxForIndex(POKENAV_GFX_RIBBONS_MENU); + ShowLeftHeaderGfx(POKENAV_GFX_RIBBONS_MENU, 1, 0); + } + return LT_INC_AND_PAUSE; + case 5: + if (IsPaletteFadeActive()) + return LT_PAUSE; + if (AreLeftHeaderSpritesMoving()) + return LT_PAUSE; + break; + } + return LT_FINISH; +} + +static u32 LoopedTask_RibbonsListMoveCursorUp(s32 state) +{ + struct Pokenav_RibbonsMonMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_MENU); + switch (state) + { + case 0: + switch (MatchCall_MoveCursorUp()) + { + case 0: + return LT_FINISH; + case 1: + PlaySE(SE_SELECT); + return LT_SET_STATE(2); + case 2: + PlaySE(SE_SELECT); + break; + } + return LT_INC_AND_PAUSE; + case 1: + if (IsMonListLoopedTaskActive()) + return LT_PAUSE; + // fallthrough + case 2: + UpdateIndexNumberDisplay(menu); + return LT_INC_AND_PAUSE; + case 3: + if (IsDma3ManagerBusyWithBgCopy()) + return LT_PAUSE; + break; + } + return LT_FINISH; +} + +static u32 LoopedTask_RibbonsListMoveCursorDown(s32 state) +{ + struct Pokenav_RibbonsMonMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_MENU); + switch (state) + { + case 0: + switch (MatchCall_MoveCursorDown()) + { + case 0: + return LT_FINISH; + case 1: + PlaySE(SE_SELECT); + return LT_SET_STATE(2); + case 2: + PlaySE(SE_SELECT); + break; + } + return LT_INC_AND_PAUSE; + case 1: + if (IsMonListLoopedTaskActive()) + return LT_PAUSE; + // fallthrough + case 2: + UpdateIndexNumberDisplay(menu); + return LT_INC_AND_PAUSE; + case 3: + if (IsDma3ManagerBusyWithBgCopy()) + return LT_PAUSE; + break; + } + return LT_FINISH; +} + +static u32 LoopedTask_RibbonsListMovePageUp(s32 state) +{ + struct Pokenav_RibbonsMonMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_MENU); + switch (state) + { + case 0: + switch (MatchCall_PageUp()) + { + case 0: + return LT_FINISH; + case 1: + PlaySE(SE_SELECT); + return LT_SET_STATE(2); + case 2: + PlaySE(SE_SELECT); + break; + } + return LT_INC_AND_PAUSE; + case 1: + if (IsMonListLoopedTaskActive()) + return LT_PAUSE; + // fallthrough + case 2: + UpdateIndexNumberDisplay(menu); + return LT_INC_AND_PAUSE; + case 3: + if (IsDma3ManagerBusyWithBgCopy()) + return LT_PAUSE; + break; + } + return LT_FINISH; +} + +static u32 LoopedTask_RibbonsListMovePageDown(s32 state) +{ + struct Pokenav_RibbonsMonMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_MON_MENU); + switch (state) + { + case 0: + switch (MatchCall_PageDown()) + { + case 0: + return LT_FINISH; + case 1: + PlaySE(SE_SELECT); + return LT_SET_STATE(2); + case 2: + PlaySE(SE_SELECT); + break; + } + return LT_INC_AND_PAUSE; + case 1: + if (IsMonListLoopedTaskActive()) + return LT_PAUSE; + // fallthrough + case 2: + UpdateIndexNumberDisplay(menu); + return LT_INC_AND_PAUSE; + case 3: + if (IsDma3ManagerBusyWithBgCopy()) + return LT_PAUSE; + break; + } + return LT_FINISH; +} + +static u32 LoopedTask_RibbonsListReturnToMainMenu(s32 state) +{ + switch (state) + { + case 0: + PlaySE(SE_SELECT); + PokenavFadeScreen(0); + SlideMenuHeaderDown(); + return LT_INC_AND_PAUSE; + case 1: + if (IsPaletteFadeActive()) + return LT_PAUSE; + if (MainMenuLoopedTaskIsBusy()) + return LT_PAUSE; + SetLeftHeaderSpritesInvisibility(); + break; + } + return LT_FINISH; +} + +static u32 LoopedTask_RibbonsListOpenSummary(s32 state) +{ + switch (state) + { + case 0: + PlaySE(SE_SELECT); + PokenavFadeScreen(0); + return LT_INC_AND_PAUSE; + case 1: + if (IsPaletteFadeActive()) + return LT_PAUSE; + break; + } + return LT_FINISH; +} + +static void AddRibbonsMonListWindow(struct Pokenav_RibbonsMonMenu *menu) +{ + s32 listCount; + menu->winid = AddWindow(&sRibbonsMonListWindowTemplate); + PutWindowTilemap(menu->winid); + listCount = GetRibbonsMonListCount(); + DrawListIndexNumber(menu->winid, 0, listCount); + CopyWindowToVram(menu->winid, COPYWIN_MAP); + UpdateIndexNumberDisplay(menu); +} + +static void UpdateIndexNumberDisplay(struct Pokenav_RibbonsMonMenu *menu) +{ + s32 listIndex = GetSelectedPokenavListIndex(); + s32 listCount = GetRibbonsMonListCount(); + DrawListIndexNumber(menu->winid, listIndex + 1, listCount); + CopyWindowToVram(menu->winid, COPYWIN_GFX); +} + +static void DrawListIndexNumber(s32 windowId, s32 index, s32 max) +{ + u8 strbuf[16]; + u32 x; + + u8 * ptr = strbuf; + ptr = ConvertIntToDecimalStringN(ptr, index, STR_CONV_MODE_RIGHT_ALIGN, 3); + *ptr++ = CHAR_SLASH; + ConvertIntToDecimalStringN(ptr, max, STR_CONV_MODE_RIGHT_ALIGN, 3); + x = GetStringCenterAlignXOffset(FONT_NORMAL, strbuf, 56); + AddTextPrinterParameterized(windowId, FONT_NORMAL, strbuf, x, 1, TEXT_SKIP_DRAW, NULL); +} + +static void InitMonRibbonPokenavListMenuTemplate(void) +{ + struct PokenavListTemplate template; + template.list.monList = GetMonRibbonMonListData(); + template.count = GetRibbonsMonListCount(); + template.unk8 = 4; + template.unk6 = GetRibbonListMenuCurrIndex(); + template.item_X = 13; + template.windowWidth = 17; + template.listTop = 1; + template.maxShowed = 8; + template.fillValue = 2; + template.fontId = FONT_NORMAL; + template.listFunc.printMonFunc = BufferRibbonMonInfoText; + template.unk14 = NULL; + sub_81C81D4(&sMonRibbonListBgTemplates[1], &template, 0); +} + +// Buffers the "Nickname gender/level" text for the ribbon mon list +static void BufferRibbonMonInfoText(struct PokenavMonList * item0, u8 * dest) +{ + u8 gender; + u8 level; + u8 * s; + const u8 * genderStr; + struct PokenavMonList * item = item0; + + // Mon is in party + if (item->boxId == TOTAL_BOXES_COUNT) + { + struct Pokemon * mon = &gPlayerParty[item->monId]; + gender = GetMonGender(mon); + level = GetLevelFromMonExp(mon); + GetMonData(mon, MON_DATA_NICKNAME, gStringVar3); + } + // Mon is in PC + else + { + struct BoxPokemon * mon = GetBoxedMonPtr(item->boxId, item->monId); + gender = GetBoxMonGender(mon); + level = GetLevelFromBoxMonExp(mon); + GetBoxMonData(mon, MON_DATA_NICKNAME, gStringVar3); + } + + StringGetEnd10(gStringVar3); + dest = GetStringClearToWidth(dest, FONT_NORMAL, gStringVar3, 60); + switch (gender) + { + default: + genderStr = sText_NoGenderSymbol; + break; + case MON_MALE: + genderStr = sText_MaleSymbol; + break; + case MON_FEMALE: + genderStr = sText_FemaleSymbol; + break; + } + + s = StringCopy(gStringVar1, genderStr); + *s++ = CHAR_SLASH; + *s++ = CHAR_EXTRA_SYMBOL; + *s++ = CHAR_LV_2; + ConvertIntToDecimalStringN(s, level, STR_CONV_MODE_LEFT_ALIGN, 3); + dest = GetStringClearToWidth(dest, FONT_NORMAL, gStringVar1, 54); + ConvertIntToDecimalStringN(dest, item->data, STR_CONV_MODE_RIGHT_ALIGN, 2); +} diff --git a/src/pokenav_ribbons_summary.c b/src/pokenav_ribbons_summary.c new file mode 100644 index 000000000..a7a27ee31 --- /dev/null +++ b/src/pokenav_ribbons_summary.c @@ -0,0 +1,1270 @@ +#include "global.h" +#include "decompress.h" +#include "dynamic_placeholder_text_util.h" +#include "graphics.h" +#include "international_string_util.h" +#include "pokenav.h" +#include "sound.h" +#include "sprite.h" +#include "string_util.h" +#include "strings.h" +#include "text.h" +#include "trainer_pokemon_sprites.h" +#include "window.h" +#include "constants/songs.h" + +enum +{ + RIBBONS_SUMMARY_FUNC_NONE, + RIBBONS_SUMMARY_FUNC_SWITCH_MONS, + RIBBONS_SUMMARY_FUNC_SELECT_RIBBON, + RIBBONS_SUMMARY_FUNC_EXPANDED_CURSOR_MOVE, + RIBBONS_SUMMARY_FUNC_EXPANDED_CANCEL, + RIBBONS_SUMMARY_FUNC_EXIT, +}; + +#define GFXTAG_RIBBON_ICONS_BIG 9 + +#define PALTAG_RIBBON_ICONS_1 15 +#define PALTAG_RIBBON_ICONS_2 16 +#define PALTAG_RIBBON_ICONS_3 17 +#define PALTAG_RIBBON_ICONS_4 18 +#define PALTAG_RIBBON_ICONS_5 19 + +#define RIBBONS_PER_ROW 9 +#define GIFT_RIBBON_ROW (1 + (FIRST_GIFT_RIBBON / RIBBONS_PER_ROW)) // Gift ribbons start on a new row after the normal ribbons. +#define GIFT_RIBBON_START_POS (RIBBONS_PER_ROW * GIFT_RIBBON_ROW) + +#define MON_SPRITE_X_ON 40 +#define MON_SPRITE_X_OFF -32 +#define MON_SPRITE_Y 104 + +struct Pokenav_RibbonsSummaryList +{ + u8 unused1[8]; + struct PokenavSub18 *monList; + u16 selectedPos; + u16 normalRibbonLastRowStart; + u16 numNormalRibbons; + u16 numGiftRibbons; + u32 ribbonIds[FIRST_GIFT_RIBBON]; + u32 giftRibbonIds[NUM_GIFT_RIBBONS]; + u32 unused2; + u32 (*callback)(struct Pokenav_RibbonsSummaryList *); +}; + +struct Pokenav_RibbonsSummaryMenu +{ + u32 (*callback)(void); + u32 loopedTaskId; + u16 nameWindowId; + u16 ribbonCountWindowId; + u16 listIdxWindowId; + u16 unusedWindowId; + u16 monSpriteId; + struct Sprite *bigRibbonSprite; + u32 unused; + u8 tilemapBuffers[2][BG_SCREEN_SIZE]; +}; + +// Used for the initial drawing of the ribbons +static u32 sRibbonDraw_Total; +static u32 sRibbonDraw_Current; + +static void PrintCurrentMonRibbonCount(struct Pokenav_RibbonsSummaryMenu *); +static void PrintRibbbonsSummaryMonInfo(struct Pokenav_RibbonsSummaryMenu *); +static void PrintRibbonsMonListIndex(struct Pokenav_RibbonsSummaryMenu *); +static void ZoomOutSelectedRibbon(struct Pokenav_RibbonsSummaryMenu *); +static void UpdateAndZoomInSelectedRibbon(struct Pokenav_RibbonsSummaryMenu *); +static void PrintRibbonNameAndDescription(struct Pokenav_RibbonsSummaryMenu *); +static void ResetSpritesAndDrawMonFrontPic(struct Pokenav_RibbonsSummaryMenu *); +static void AddRibbonListIndexWindow(struct Pokenav_RibbonsSummaryMenu *); +static void DestroyRibbonsMonFrontPic(struct Pokenav_RibbonsSummaryMenu *); +static void SlideMonSpriteOff(struct Pokenav_RibbonsSummaryMenu *); +static void SlideMonSpriteOn(struct Pokenav_RibbonsSummaryMenu *); +static void AddRibbonCountWindow(struct Pokenav_RibbonsSummaryMenu *); +static void CreateBigRibbonSprite(struct Pokenav_RibbonsSummaryMenu *); +static void AddRibbonSummaryMonNameWindow(struct Pokenav_RibbonsSummaryMenu *); +static void DrawAllRibbonsSmall(struct Pokenav_RibbonsSummaryMenu *); +static bool32 IsRibbonAnimating(struct Pokenav_RibbonsSummaryMenu *); +static bool32 IsMonSpriteAnimating(struct Pokenav_RibbonsSummaryMenu *); +static void GetMonRibbons(struct Pokenav_RibbonsSummaryList *); +static u32 HandleExpandedRibbonInput(struct Pokenav_RibbonsSummaryList *); +static u32 RibbonsSummaryHandleInput(struct Pokenav_RibbonsSummaryList *); +static u32 ReturnToRibbonsListFromSummary(struct Pokenav_RibbonsSummaryList *); +static bool32 TrySelectRibbonUp(struct Pokenav_RibbonsSummaryList *); +static bool32 TrySelectRibbonRight(struct Pokenav_RibbonsSummaryList *); +static bool32 TrySelectRibbonLeft(struct Pokenav_RibbonsSummaryList *); +static bool32 TrySelectRibbonDown(struct Pokenav_RibbonsSummaryList *); +static bool32 GetCurrentLoopedTaskActive(void); +static u32 GetRibbonsSummaryCurrentIndex(void); +static u32 GetRibbonsSummaryMonListCount(void); +static u16 DrawRibbonsMonFrontPic(s32, s32); +static void StartMonSpriteSlide(struct Sprite *, s32, s32, s32); +static void SpriteCB_MonSpriteSlide(struct Sprite *); +static void ClearRibbonsSummaryBg(void); +static void BufferSmallRibbonGfxData(u16 *, u32); +static void DrawRibbonSmall(u32, u32); +static void SpriteCB_WaitForRibbonAnimation(struct Sprite *); +static u32 LoopedTask_OpenRibbonsSummaryMenu(s32); +static u32 LoopedTask_SwitchRibbonsSummaryMon(s32); +static u32 LoopedTask_ExpandSelectedRibbon(s32); +static u32 LoopedTask_MoveRibbonsCursorExpanded(s32); +static u32 LoopedTask_ShrinkExpandedRibbon(s32); +static u32 LoopedTask_ExitRibbonsSummaryMenu(s32); + +struct +{ + u8 numBits; // The number of bits needed to represent numRibbons + u8 numRibbons; // Never read. The contest ribbons have 4 (1 for each rank), the rest are just 1 ribbon + u8 ribbonId; + bool8 isGiftRibbon; +} static const sRibbonData[] = +{ + {1, 1, CHAMPION_RIBBON, FALSE}, + {3, 4, COOL_RIBBON_NORMAL, FALSE}, + {3, 4, BEAUTY_RIBBON_NORMAL, FALSE}, + {3, 4, CUTE_RIBBON_NORMAL, FALSE}, + {3, 4, SMART_RIBBON_NORMAL, FALSE}, + {3, 4, TOUGH_RIBBON_NORMAL, FALSE}, + {1, 1, WINNING_RIBBON, FALSE}, + {1, 1, VICTORY_RIBBON, FALSE}, + {1, 1, ARTIST_RIBBON, FALSE}, + {1, 1, EFFORT_RIBBON, FALSE}, + {1, 1, MARINE_RIBBON, TRUE}, + {1, 1, LAND_RIBBON, TRUE}, + {1, 1, SKY_RIBBON, TRUE}, + {1, 1, COUNTRY_RIBBON, TRUE}, + {1, 1, NATIONAL_RIBBON, TRUE}, + {1, 1, EARTH_RIBBON, TRUE}, + {1, 1, WORLD_RIBBON, TRUE} +}; + +#include "data/text/ribbon_descriptions.h" +#include "data/text/gift_ribbon_descriptions.h" + +static const u16 sRibbonIcons1_Pal[] = INCBIN_U16("graphics/pokenav/ribbons/icons1.gbapal"); +static const u16 sRibbonIcons2_Pal[] = INCBIN_U16("graphics/pokenav/ribbons/icons2.gbapal"); +static const u16 sRibbonIcons3_Pal[] = INCBIN_U16("graphics/pokenav/ribbons/icons3.gbapal"); +static const u16 sRibbonIcons4_Pal[] = INCBIN_U16("graphics/pokenav/ribbons/icons4.gbapal"); +static const u16 sRibbonIcons5_Pal[] = INCBIN_U16("graphics/pokenav/ribbons/icons5.gbapal"); +static const u16 sMonInfo_Pal[] = INCBIN_U16("graphics/pokenav/ribbons/mon_info.gbapal"); // palette for Pokémon's name/gender/level text +static const u32 sRibbonIconsSmall_Gfx[] = INCBIN_U32("graphics/pokenav/ribbons/icons.4bpp.lz"); +static const u32 sRibbonIconsBig_Gfx[] = INCBIN_U32("graphics/pokenav/ribbons/icons_big.4bpp.lz"); + +static const struct BgTemplate sBgTemplates[] = +{ + { + .bg = 1, + .charBaseIndex = 3, + .mapBaseIndex = 0x07, + .screenSize = 0, + .paletteMode = 0, + .priority = 1, + .baseTile = 0 + }, + { + .bg = 2, + .charBaseIndex = 1, + .mapBaseIndex = 0x06, + .screenSize = 0, + .paletteMode = 0, + .priority = 2, + .baseTile = 0 + } +}; + +static const LoopedTask sRibbonsSummaryMenuLoopTaskFuncs[] = +{ + [RIBBONS_SUMMARY_FUNC_NONE] = NULL, + [RIBBONS_SUMMARY_FUNC_SWITCH_MONS] = LoopedTask_SwitchRibbonsSummaryMon, + [RIBBONS_SUMMARY_FUNC_SELECT_RIBBON] = LoopedTask_ExpandSelectedRibbon, + [RIBBONS_SUMMARY_FUNC_EXPANDED_CURSOR_MOVE] = LoopedTask_MoveRibbonsCursorExpanded, + [RIBBONS_SUMMARY_FUNC_EXPANDED_CANCEL] = LoopedTask_ShrinkExpandedRibbon, + [RIBBONS_SUMMARY_FUNC_EXIT] = LoopedTask_ExitRibbonsSummaryMenu +}; + +bool32 PokenavCallback_Init_RibbonsSummaryMenu(void) +{ + struct Pokenav_RibbonsSummaryList *list = AllocSubstruct(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_LIST, sizeof(struct Pokenav_RibbonsSummaryList)); + if (list == NULL) + return FALSE; + + list->monList = GetSubstructPtr(POKENAV_SUBSTRUCT_MON_LIST); + if (list->monList == NULL) + return FALSE; + + GetMonRibbons(list); + list->callback = RibbonsSummaryHandleInput; + gKeyRepeatContinueDelay = 3; + gKeyRepeatStartDelay = 10; + return TRUE; +} + +u32 GetRibbonsSummaryMenuCallback(void) +{ + struct Pokenav_RibbonsSummaryList *list = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_LIST); + return list->callback(list); +} + +void FreeRibbonsSummaryScreen1(void) +{ + FreePokenavSubstruct(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_LIST); +} + +// Handles input when a specific ribbon is not currently selected +static u32 RibbonsSummaryHandleInput(struct Pokenav_RibbonsSummaryList *list) +{ + // Handle Up/Down movement to select a new Pokémon to show ribbons for + if (JOY_REPEAT(DPAD_UP) && list->monList->currIndex != 0) + { + list->monList->currIndex--; + list->selectedPos = 0; + GetMonRibbons(list); + return RIBBONS_SUMMARY_FUNC_SWITCH_MONS; + } + if (JOY_REPEAT(DPAD_DOWN) && list->monList->currIndex < list->monList->listCount - 1) + { + list->monList->currIndex++; + list->selectedPos = 0; + GetMonRibbons(list); + return RIBBONS_SUMMARY_FUNC_SWITCH_MONS; + } + + if (JOY_NEW(A_BUTTON)) + { + // Enter ribbon selection + list->callback = HandleExpandedRibbonInput; + return RIBBONS_SUMMARY_FUNC_SELECT_RIBBON; + } + if (JOY_NEW(B_BUTTON)) + { + // Exit ribbon summary menu + list->callback = ReturnToRibbonsListFromSummary; + return RIBBONS_SUMMARY_FUNC_EXIT; + } + return RIBBONS_SUMMARY_FUNC_NONE; +} + +// Handles input when a ribbon is selected +static u32 HandleExpandedRibbonInput(struct Pokenav_RibbonsSummaryList *list) +{ + // Handle movement while a ribbon is selected + if (JOY_REPEAT(DPAD_UP) && TrySelectRibbonUp(list)) + return RIBBONS_SUMMARY_FUNC_EXPANDED_CURSOR_MOVE; + if (JOY_REPEAT(DPAD_DOWN) && TrySelectRibbonDown(list)) + return RIBBONS_SUMMARY_FUNC_EXPANDED_CURSOR_MOVE; + if (JOY_REPEAT(DPAD_LEFT) && TrySelectRibbonLeft(list)) + return RIBBONS_SUMMARY_FUNC_EXPANDED_CURSOR_MOVE; + if (JOY_REPEAT(DPAD_RIGHT) && TrySelectRibbonRight(list)) + return RIBBONS_SUMMARY_FUNC_EXPANDED_CURSOR_MOVE; + + if (JOY_NEW(B_BUTTON)) + { + // Exit ribbon selection + list->callback = RibbonsSummaryHandleInput; + return RIBBONS_SUMMARY_FUNC_EXPANDED_CANCEL; + } + return RIBBONS_SUMMARY_FUNC_NONE; +} + +static u32 ReturnToRibbonsListFromSummary(struct Pokenav_RibbonsSummaryList *list) +{ + return POKENAV_RIBBONS_RETURN_TO_MON_LIST; +} + +static bool32 TrySelectRibbonUp(struct Pokenav_RibbonsSummaryList *list) +{ + if (list->selectedPos < FIRST_GIFT_RIBBON) + { + // In normal ribbons, try to move up a row + if (list->selectedPos < RIBBONS_PER_ROW) + return FALSE; + + list->selectedPos -= RIBBONS_PER_ROW; + return TRUE; + } + if (list->numNormalRibbons != 0) + { + // In gift ribbons, try to move up into normal ribbons + // If there's > 1 row of gift ribbons (not normally possible) + // it's impossible to move up between them + u32 ribbonPos = list->selectedPos - GIFT_RIBBON_START_POS; + list->selectedPos = ribbonPos + list->normalRibbonLastRowStart; + if (list->selectedPos >= list->numNormalRibbons) + list->selectedPos = list->numNormalRibbons - 1; + return TRUE; + } + return FALSE; +} + +static bool32 TrySelectRibbonDown(struct Pokenav_RibbonsSummaryList *list) +{ + if (list->selectedPos >= FIRST_GIFT_RIBBON) + return FALSE; + if (list->selectedPos < list->normalRibbonLastRowStart) + { + // Not in last row of normal ribbons, advance to next row + list->selectedPos += RIBBONS_PER_ROW; + if (list->selectedPos >= list->numNormalRibbons) + list->selectedPos = list->numNormalRibbons - 1; + return TRUE; + } + if (list->numGiftRibbons != 0) + { + // In/beyond last of row of normal ribbons and gift ribbons present, move down to gift ribbon row + int ribbonPos = list->selectedPos - list->normalRibbonLastRowStart; + if (ribbonPos >= list->numGiftRibbons) + ribbonPos = list->numGiftRibbons - 1; + + list->selectedPos = ribbonPos + GIFT_RIBBON_START_POS; + return TRUE; + } + return FALSE; +} + +static bool32 TrySelectRibbonLeft(struct Pokenav_RibbonsSummaryList *list) +{ + u16 column = list->selectedPos % RIBBONS_PER_ROW; + if (column != 0) + { + list->selectedPos--; + return TRUE; + } + + return FALSE; +} + +static bool32 TrySelectRibbonRight(struct Pokenav_RibbonsSummaryList *list) +{ + int column = list->selectedPos % RIBBONS_PER_ROW; + + if (column >= RIBBONS_PER_ROW - 1) + return FALSE; + + if (list->selectedPos < GIFT_RIBBON_START_POS) + { + // Move right in normal ribbon row + if (list->selectedPos < list->numNormalRibbons - 1) + { + list->selectedPos++; + return TRUE; + } + } + else + { + // Move right in gift ribbon row + if (column < list->numGiftRibbons - 1) + { + list->selectedPos++; + return TRUE; + } + } + return FALSE; +} + +static u32 GetRibbonsSummaryCurrentIndex(void) +{ + struct Pokenav_RibbonsSummaryList *list = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_LIST); + return list->monList->currIndex; +} + +static u32 GetRibbonsSummaryMonListCount(void) +{ + struct Pokenav_RibbonsSummaryList *list = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_LIST); + return list->monList->listCount; +} + +static void GetMonNicknameLevelGender(u8 *nick, u8 *level, u8 *gender) +{ + struct Pokenav_RibbonsSummaryList *list = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_LIST); + struct PokenavSub18 *mons = list->monList; + struct PokenavMonList *monInfo = &mons->monData[mons->currIndex]; + + if (monInfo->boxId == TOTAL_BOXES_COUNT) + { + // Get info for party mon + struct Pokemon *mon = &gPlayerParty[monInfo->monId]; + GetMonData(mon, MON_DATA_NICKNAME, nick); + *level = GetLevelFromMonExp(mon); + *gender = GetMonGender(mon); + } + else + { + // Get info for PC box mon + struct BoxPokemon *boxMon = GetBoxedMonPtr(monInfo->boxId, monInfo->monId); + *gender = GetBoxMonGender(boxMon); + *level = GetLevelFromBoxMonExp(boxMon); + GetBoxMonData(boxMon, MON_DATA_NICKNAME, nick); + } + StringGetEnd10(nick); +} + +static void GetMonSpeciesPersonalityOtId(u16 *species, u32 *personality, u32 *otId) +{ + struct Pokenav_RibbonsSummaryList *list = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_LIST); + struct PokenavSub18 *mons = list->monList; + struct PokenavMonList *monInfo = &mons->monData[mons->currIndex]; + + if (monInfo->boxId == TOTAL_BOXES_COUNT) + { + // Get info for party mon + struct Pokemon *mon = &gPlayerParty[monInfo->monId]; + *species = GetMonData(mon, MON_DATA_SPECIES); + *personality = GetMonData(mon, MON_DATA_PERSONALITY); + *otId = GetMonData(mon, MON_DATA_OT_ID); + } + else + { + // Get info for PC box mon + struct BoxPokemon *boxMon = GetBoxedMonPtr(monInfo->boxId, monInfo->monId); + *species = GetBoxMonData(boxMon, MON_DATA_SPECIES); + *personality = GetBoxMonData(boxMon, MON_DATA_PERSONALITY); + *otId = GetBoxMonData(boxMon, MON_DATA_OT_ID); + } +} + +static u32 GetCurrMonRibbonCount(void) +{ + struct Pokenav_RibbonsSummaryList *list = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_LIST); + struct PokenavSub18 *mons = list->monList; + struct PokenavMonList *monInfo = &mons->monData[mons->currIndex]; + + if (monInfo->boxId == TOTAL_BOXES_COUNT) + return GetMonData(&gPlayerParty[monInfo->monId], MON_DATA_RIBBON_COUNT); + else + return GetBoxMonDataAt(monInfo->boxId, monInfo->monId, MON_DATA_RIBBON_COUNT); +} + +static void GetMonRibbons(struct Pokenav_RibbonsSummaryList *list) +{ + u32 ribbonFlags; + s32 i, j; + struct PokenavSub18 *mons = list->monList; + struct PokenavMonList *monInfo = &mons->monData[mons->currIndex]; + + if (monInfo->boxId == TOTAL_BOXES_COUNT) + ribbonFlags = GetMonData(&gPlayerParty[monInfo->monId], MON_DATA_RIBBONS); + else + ribbonFlags = GetBoxMonDataAt(monInfo->boxId, monInfo->monId, MON_DATA_RIBBONS); + + list->numNormalRibbons = 0; + list->numGiftRibbons = 0; + for (i = 0; i < ARRAY_COUNT(sRibbonData); i++) + { + // For all non-contest ribbons, numRibbons will be 1 if they have it, 0 if they don't + // For contest ribbons, numRibbons will be 0-4 + s32 numRibbons = ((1 << sRibbonData[i].numBits) - 1) & ribbonFlags; + if (!sRibbonData[i].isGiftRibbon) + { + for (j = 0; j < numRibbons; j++) + list->ribbonIds[list->numNormalRibbons++] = sRibbonData[i].ribbonId + j; + } + else + { + for (j = 0; j < numRibbons; j++) + list->giftRibbonIds[list->numGiftRibbons++] = sRibbonData[i].ribbonId + j; + } + ribbonFlags >>= sRibbonData[i].numBits; + } + + if (list->numNormalRibbons != 0) + { + list->normalRibbonLastRowStart = ((list->numNormalRibbons - 1) / RIBBONS_PER_ROW) * RIBBONS_PER_ROW; + list->selectedPos = 0; + } + else + { + // There are no normal ribbons, move cursor to first gift ribbon + list->normalRibbonLastRowStart = 0; + list->selectedPos = GIFT_RIBBON_START_POS; + } +} + +static u32 *GetNormalRibbonIds(u32 *size) +{ + struct Pokenav_RibbonsSummaryList *list = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_LIST); + *size = list->numNormalRibbons; + return list->ribbonIds; +} + +static u32 *GetGiftRibbonIds(u32 *size) +{ + struct Pokenav_RibbonsSummaryList *list = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_LIST); + *size = list->numGiftRibbons; + return list->giftRibbonIds; +} + +static u16 GetSelectedPosition(void) +{ + struct Pokenav_RibbonsSummaryList *list = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_LIST); + return list->selectedPos; +} + +static u32 GetRibbonId(void) +{ + struct Pokenav_RibbonsSummaryList *list = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_LIST); + int ribbonPos = list->selectedPos; + if (ribbonPos < FIRST_GIFT_RIBBON) + return list->ribbonIds[ribbonPos]; + else + return list->giftRibbonIds[ribbonPos - GIFT_RIBBON_START_POS]; +} + +bool32 OpenRibbonsSummaryMenu(void) +{ + struct Pokenav_RibbonsSummaryMenu *menu = AllocSubstruct(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_MENU, sizeof(struct Pokenav_RibbonsSummaryMenu)); + if (menu == NULL) + return FALSE; + + menu->loopedTaskId = CreateLoopedTask(LoopedTask_OpenRibbonsSummaryMenu, 1); + menu->callback = GetCurrentLoopedTaskActive; + return TRUE; +} + +void CreateRibbonsSummaryLoopedTask(s32 id) +{ + struct Pokenav_RibbonsSummaryMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_MENU); + menu->loopedTaskId = CreateLoopedTask(sRibbonsSummaryMenuLoopTaskFuncs[id], 1); + menu->callback = GetCurrentLoopedTaskActive; +} + +u32 IsRibbonsSummaryLoopedTaskActive(void) +{ + struct Pokenav_RibbonsSummaryMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_MENU); + return menu->callback(); +} + +void FreeRibbonsSummaryScreen2(void) +{ + struct Pokenav_RibbonsSummaryMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_MENU); + RemoveWindow(menu->ribbonCountWindowId); + RemoveWindow(menu->nameWindowId); + RemoveWindow(menu->listIdxWindowId); +#ifndef BUGFIX + RemoveWindow(menu->unusedWindowId); // Removing window, but window id is never set +#endif + DestroyRibbonsMonFrontPic(menu); + FreeSpriteTilesByTag(GFXTAG_RIBBON_ICONS_BIG); + FreeSpritePaletteByTag(PALTAG_RIBBON_ICONS_1); + FreeSpritePaletteByTag(PALTAG_RIBBON_ICONS_2); + FreeSpritePaletteByTag(PALTAG_RIBBON_ICONS_3); + FreeSpritePaletteByTag(PALTAG_RIBBON_ICONS_4); + FreeSpritePaletteByTag(PALTAG_RIBBON_ICONS_5); + FreeSpriteOamMatrix(menu->bigRibbonSprite); + DestroySprite(menu->bigRibbonSprite); + FreePokenavSubstruct(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_MENU); +} + +static bool32 GetCurrentLoopedTaskActive(void) +{ + struct Pokenav_RibbonsSummaryMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_MENU); + return IsLoopedTaskActive(menu->loopedTaskId); +} + +static u32 LoopedTask_OpenRibbonsSummaryMenu(s32 state) +{ + struct Pokenav_RibbonsSummaryMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_MENU); + switch (state) + { + case 0: + InitBgTemplates(sBgTemplates, ARRAY_COUNT(sBgTemplates)); + DecompressAndCopyTileDataToVram(2, gPokenavRibbonsSummaryBg_Gfx, 0, 0, 0); + SetBgTilemapBuffer(2, menu->tilemapBuffers[0]); + CopyToBgTilemapBuffer(2, gPokenavRibbonsSummaryBg_Tilemap, 0, 0); + CopyPaletteIntoBufferUnfaded(gPokenavRibbonsSummaryBg_Pal, 0x10, 0x20); + CopyBgTilemapBufferToVram(2); + return LT_INC_AND_PAUSE; + case 1: + if (!FreeTempTileDataBuffersIfPossible()) + { + BgDmaFill(1, 0, 0, 1); + DecompressAndCopyTileDataToVram(1, sRibbonIconsSmall_Gfx, 0, 1, 0); + SetBgTilemapBuffer(1, menu->tilemapBuffers[1]); + FillBgTilemapBufferRect_Palette0(1, 0, 0, 0, 32, 20); + CopyPaletteIntoBufferUnfaded(sRibbonIcons1_Pal, 0x20, 0xA0); + CopyPaletteIntoBufferUnfaded(sMonInfo_Pal, 0xA0, 0x20); + CopyBgTilemapBufferToVram(1); + return LT_INC_AND_PAUSE; + } + return LT_PAUSE; + case 2: + if (!FreeTempTileDataBuffersIfPossible()) + { + AddRibbonCountWindow(menu); + return LT_INC_AND_PAUSE; + } + return LT_PAUSE; + case 3: + if (!FreeTempTileDataBuffersIfPossible()) + { + AddRibbonSummaryMonNameWindow(menu); + return LT_INC_AND_PAUSE; + } + return LT_PAUSE; + case 4: + if (!FreeTempTileDataBuffersIfPossible()) + { + AddRibbonListIndexWindow(menu); + return LT_INC_AND_PAUSE; + } + return LT_PAUSE; + case 5: + if (!IsDma3ManagerBusyWithBgCopy()) + { + CopyBgTilemapBufferToVram(2); + return LT_INC_AND_PAUSE; + } + return LT_PAUSE; + case 6: + if (!IsDma3ManagerBusyWithBgCopy()) + { + ResetSpritesAndDrawMonFrontPic(menu); + return LT_INC_AND_CONTINUE; + } + return LT_PAUSE; + case 7: + DrawAllRibbonsSmall(menu); + PrintHelpBarText(HELPBAR_RIBBONS_LIST); + return LT_INC_AND_PAUSE; + case 8: + if (!IsDma3ManagerBusyWithBgCopy()) + { + CreateBigRibbonSprite(menu); + ChangeBgX(1, 0, BG_COORD_SET); + ChangeBgY(1, 0, BG_COORD_SET); + ChangeBgX(2, 0, BG_COORD_SET); + ChangeBgY(2, 0, BG_COORD_SET); + ShowBg(1); + ShowBg(2); + HideBg(3); + PokenavFadeScreen(1); + return LT_INC_AND_PAUSE; + } + return LT_PAUSE; + case 9: + if (IsPaletteFadeActive()) + return LT_PAUSE; + } + return LT_FINISH; +} + +static u32 LoopedTask_ExitRibbonsSummaryMenu(s32 state) +{ + switch (state) + { + case 0: + PlaySE(SE_SELECT); + PokenavFadeScreen(0); + return LT_INC_AND_PAUSE; + case 1: + if (IsPaletteFadeActive()) + return LT_PAUSE; + return LT_FINISH; + } + return LT_FINISH; +} + +static u32 LoopedTask_SwitchRibbonsSummaryMon(s32 state) +{ + struct Pokenav_RibbonsSummaryMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_MENU); + switch (state) + { + case 0: + PlaySE(SE_SELECT); + SlideMonSpriteOff(menu); + return LT_INC_AND_PAUSE; + case 1: + if (!IsMonSpriteAnimating(menu)) + { + PrintRibbbonsSummaryMonInfo(menu); + return LT_INC_AND_CONTINUE; + } + return LT_PAUSE; + case 2: + DrawAllRibbonsSmall(menu); + return LT_INC_AND_CONTINUE; + case 3: + PrintRibbonsMonListIndex(menu); + return LT_INC_AND_CONTINUE; + case 4: + PrintCurrentMonRibbonCount(menu); + return LT_INC_AND_CONTINUE; + case 5: + if (!IsDma3ManagerBusyWithBgCopy()) + { + SlideMonSpriteOn(menu); + return LT_INC_AND_PAUSE; + } + return LT_PAUSE; + case 6: + if (IsMonSpriteAnimating(menu)) + return LT_PAUSE; + } + return LT_FINISH; +} + +static u32 LoopedTask_ExpandSelectedRibbon(s32 state) +{ + struct Pokenav_RibbonsSummaryMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_MENU); + switch (state) + { + case 0: + PlaySE(SE_SELECT); + UpdateAndZoomInSelectedRibbon(menu); + return LT_INC_AND_PAUSE; + case 1: + if (!IsRibbonAnimating(menu)) + { + PrintRibbonNameAndDescription(menu); + PrintHelpBarText(HELPBAR_RIBBONS_CHECK); + return LT_INC_AND_PAUSE; + } + return LT_PAUSE; + case 2: + if (IsDma3ManagerBusyWithBgCopy()) + return LT_PAUSE; + } + return LT_FINISH; +} + +static u32 LoopedTask_MoveRibbonsCursorExpanded(s32 state) +{ + struct Pokenav_RibbonsSummaryMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_MENU); + switch (state) + { + case 0: + PlaySE(SE_SELECT); + ZoomOutSelectedRibbon(menu); + return LT_INC_AND_PAUSE; + case 1: + if (!IsRibbonAnimating(menu)) + { + UpdateAndZoomInSelectedRibbon(menu); + return LT_INC_AND_PAUSE; + } + return LT_PAUSE; + case 2: + if (!IsRibbonAnimating(menu)) + { + PrintRibbonNameAndDescription(menu); + return LT_INC_AND_PAUSE; + } + return LT_PAUSE; + case 3: + if (IsDma3ManagerBusyWithBgCopy()) + return LT_PAUSE; + } + return LT_FINISH; +} + +static u32 LoopedTask_ShrinkExpandedRibbon(s32 state) +{ + struct Pokenav_RibbonsSummaryMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_MENU); + switch (state) + { + case 0: + PlaySE(SE_SELECT); + ZoomOutSelectedRibbon(menu); + return LT_INC_AND_PAUSE; + case 1: + if (!IsRibbonAnimating(menu)) + { + PrintCurrentMonRibbonCount(menu); + PrintHelpBarText(HELPBAR_RIBBONS_LIST); + return LT_INC_AND_PAUSE; + } + return LT_PAUSE; + case 2: + if (IsDma3ManagerBusyWithBgCopy()) + return LT_PAUSE; + } + return LT_FINISH; +} + +static const struct WindowTemplate sRibbonCountWindowTemplate = +{ + .bg = 2, + .tilemapLeft = 12, + .tilemapTop = 13, + .width = 16, + .height = 4, + .paletteNum = 1, + .baseBlock = 0x14, +}; + +static void AddRibbonCountWindow(struct Pokenav_RibbonsSummaryMenu *menu) +{ + menu->ribbonCountWindowId = AddWindow(&sRibbonCountWindowTemplate); + PutWindowTilemap(menu->ribbonCountWindowId); + PrintCurrentMonRibbonCount(menu); +} + +static void PrintCurrentMonRibbonCount(struct Pokenav_RibbonsSummaryMenu *menu) +{ + u8 color[] = {TEXT_COLOR_RED, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_LIGHT_GRAY}; + + ConvertIntToDecimalStringN(gStringVar1, GetCurrMonRibbonCount(), STR_CONV_MODE_LEFT_ALIGN, 2); + DynamicPlaceholderTextUtil_Reset(); + DynamicPlaceholderTextUtil_SetPlaceholderPtr(0, gStringVar1); + DynamicPlaceholderTextUtil_ExpandPlaceholders(gStringVar4, gText_RibbonsF700); + FillWindowPixelBuffer(menu->ribbonCountWindowId, PIXEL_FILL(4)); + AddTextPrinterParameterized3(menu->ribbonCountWindowId, FONT_NORMAL, 0, 1, color, TEXT_SKIP_DRAW, gStringVar4); + CopyWindowToVram(menu->ribbonCountWindowId, COPYWIN_GFX); +} + +static void PrintRibbonNameAndDescription(struct Pokenav_RibbonsSummaryMenu *menu) +{ + s32 i; + u32 ribbonId = GetRibbonId(); + u8 color[] = {TEXT_COLOR_RED, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_LIGHT_GRAY}; + + FillWindowPixelBuffer(menu->ribbonCountWindowId, PIXEL_FILL(4)); + if (ribbonId < FIRST_GIFT_RIBBON) + { + // Print normal ribbon name/description + for (i = 0; i < 2; i++) + AddTextPrinterParameterized3(menu->ribbonCountWindowId, FONT_NORMAL, 0, (i * 16) + 1, color, TEXT_SKIP_DRAW, gRibbonDescriptionPointers[ribbonId][i]); + } + else + { + // ribbonId here is one of the 'gift' ribbon slots, used to read + // its actual value from giftRibbons to determine which specific + // gift ribbon it is + ribbonId = gSaveBlock1Ptr->giftRibbons[ribbonId - FIRST_GIFT_RIBBON]; + + // If 0, this gift ribbon slot is unoccupied + if (ribbonId == 0) + return; + + // Print gift ribbon name/description + ribbonId--; + for (i = 0; i < 2; i++) + AddTextPrinterParameterized3(menu->ribbonCountWindowId, FONT_NORMAL, 0, (i * 16) + 1, color, TEXT_SKIP_DRAW, gGiftRibbonDescriptionPointers[ribbonId][i]); + } + + CopyWindowToVram(menu->ribbonCountWindowId, COPYWIN_GFX); +} + +static const struct WindowTemplate sRibbonSummaryMonNameWindowTemplate = +{ + .bg = 2, + .tilemapLeft = 14, + .tilemapTop = 1, + .width = 13, + .height = 2, + .paletteNum = 10, + .baseBlock = 0x54, +}; + +static void AddRibbonSummaryMonNameWindow(struct Pokenav_RibbonsSummaryMenu *menu) +{ + menu->nameWindowId = AddWindow(&sRibbonSummaryMonNameWindowTemplate); + PutWindowTilemap(menu->nameWindowId); + PrintRibbbonsSummaryMonInfo(menu); +} + +static const u8 sMaleIconString[] = _("{COLOR_HIGHLIGHT_SHADOW}{LIGHT_RED}{WHITE}{GREEN}♂{COLOR_HIGHLIGHT_SHADOW}{DARK_GRAY}{WHITE}{LIGHT_GRAY}"); +static const u8 sFemaleIconString[] = _("{COLOR_HIGHLIGHT_SHADOW}{LIGHT_GREEN}{WHITE}{BLUE}♀{COLOR_HIGHLIGHT_SHADOW}{DARK_GRAY}{WHITE}{LIGHT_GRAY}"); +static const u8 sGenderlessIconString[] = _("{UNK_SPACER}"); + +static void PrintRibbbonsSummaryMonInfo(struct Pokenav_RibbonsSummaryMenu *menu) +{ + const u8 *genderTxt; + u8 *txtPtr; + u8 level, gender; + u16 windowId = menu->nameWindowId; + + FillWindowPixelBuffer(windowId, PIXEL_FILL(1)); + GetMonNicknameLevelGender(gStringVar3, &level, &gender); + AddTextPrinterParameterized(windowId, FONT_NORMAL, gStringVar3, 0, 1, TEXT_SKIP_DRAW, NULL); + switch (gender) + { + case MON_MALE: + genderTxt = sMaleIconString; + break; + case MON_FEMALE: + genderTxt = sFemaleIconString; + break; + default: + genderTxt = sGenderlessIconString; + break; + } + + txtPtr = StringCopy(gStringVar1, genderTxt); + *(txtPtr++) = CHAR_SLASH; + *(txtPtr++) = CHAR_EXTRA_SYMBOL; + *(txtPtr++) = CHAR_LV_2; + ConvertIntToDecimalStringN(txtPtr, level, STR_CONV_MODE_LEFT_ALIGN, 3); + AddTextPrinterParameterized(windowId, FONT_NORMAL, gStringVar1, 60, 1, TEXT_SKIP_DRAW, NULL); + CopyWindowToVram(windowId, COPYWIN_GFX); +} + +static const struct WindowTemplate sRibbonMonListIndexWindowTemplate[] = +{ + { + .bg = 2, + .tilemapLeft = 1, + .tilemapTop = 5, + .width = 7, + .height = 2, + .paletteNum = 1, + .baseBlock = 0x6E, + }, + {}, +}; + +static void AddRibbonListIndexWindow(struct Pokenav_RibbonsSummaryMenu *menu) +{ + menu->listIdxWindowId = AddWindow(sRibbonMonListIndexWindowTemplate); + FillWindowPixelBuffer(menu->listIdxWindowId, PIXEL_FILL(1)); + PutWindowTilemap(menu->listIdxWindowId); + PrintRibbonsMonListIndex(menu); +} + +static void PrintRibbonsMonListIndex(struct Pokenav_RibbonsSummaryMenu *menu) +{ + s32 x; + u8 *txtPtr; + u32 id = GetRibbonsSummaryCurrentIndex() + 1; + u32 count = GetRibbonsSummaryMonListCount(); + + txtPtr = ConvertIntToDecimalStringN(gStringVar1, id, STR_CONV_MODE_RIGHT_ALIGN, 3); + *(txtPtr++) = CHAR_SLASH; + ConvertIntToDecimalStringN(txtPtr, count, STR_CONV_MODE_RIGHT_ALIGN, 3); + x = GetStringCenterAlignXOffset(FONT_NORMAL, gStringVar1, 56); + AddTextPrinterParameterized(menu->listIdxWindowId, FONT_NORMAL, gStringVar1, x, 1, TEXT_SKIP_DRAW, NULL); + CopyWindowToVram(menu->listIdxWindowId, COPYWIN_GFX); +} + +static void ResetSpritesAndDrawMonFrontPic(struct Pokenav_RibbonsSummaryMenu *menu) +{ + u16 species; + u32 personality, otId; + + GetMonSpeciesPersonalityOtId(&species, &personality, &otId); + ResetAllPicSprites(); + menu->monSpriteId = DrawRibbonsMonFrontPic(MON_SPRITE_X_ON, MON_SPRITE_Y); + PokenavFillPalette(15, 0); +} + +static void DestroyRibbonsMonFrontPic(struct Pokenav_RibbonsSummaryMenu *menu) +{ + FreeAndDestroyMonPicSprite(menu->monSpriteId); +} + +// x and y arguments are ignored +// y is always given as MON_SPRITE_Y +// x is given as either MON_SPRITE_X_ON or MON_SPRITE_X_OFF (but ignored and MON_SPRITE_X_ON is used) +static u16 DrawRibbonsMonFrontPic(s32 x, s32 y) +{ + u16 species, spriteId; + u32 personality, otId; + + GetMonSpeciesPersonalityOtId(&species, &personality, &otId); + spriteId = CreateMonPicSprite_HandleDeoxys(species, otId, personality, TRUE, MON_SPRITE_X_ON, MON_SPRITE_Y, 15, TAG_NONE); + gSprites[spriteId].oam.priority = 0; + return spriteId; +} + +static void SlideMonSpriteOff(struct Pokenav_RibbonsSummaryMenu *menu) +{ + StartMonSpriteSlide(&gSprites[menu->monSpriteId], MON_SPRITE_X_ON, MON_SPRITE_X_OFF, 6); +} + +static void SlideMonSpriteOn(struct Pokenav_RibbonsSummaryMenu *menu) +{ + // Switch to new mon sprite + FreeAndDestroyMonPicSprite(menu->monSpriteId); + menu->monSpriteId = DrawRibbonsMonFrontPic(MON_SPRITE_X_OFF, MON_SPRITE_Y); + + // Slide on + StartMonSpriteSlide(&gSprites[menu->monSpriteId], MON_SPRITE_X_OFF, MON_SPRITE_X_ON, 6); +} + +// Is Pokémon summary sprite still sliding off/on +static bool32 IsMonSpriteAnimating(struct Pokenav_RibbonsSummaryMenu *menu) +{ + return (gSprites[menu->monSpriteId].callback != SpriteCallbackDummy); +} + +#define sCurrX data[0] +#define sMoveIncr data[1] +#define sTime data[2] +#define sDestX data[3] + +static void StartMonSpriteSlide(struct Sprite *sprite, s32 startX, s32 destX, s32 time) +{ + u32 delta = destX - startX; + + sprite->x = startX; + sprite->sCurrX = startX << 4; + sprite->sMoveIncr = (delta << 4) / time; + sprite->sTime = time; + sprite->sDestX = destX; + + sprite->callback = SpriteCB_MonSpriteSlide; +} + +static void SpriteCB_MonSpriteSlide(struct Sprite *sprite) +{ + if (sprite->sTime != 0) + { + sprite->sTime--; + sprite->sCurrX += sprite->sMoveIncr; + sprite->x = sprite->sCurrX >> 4; + if (sprite->x <= MON_SPRITE_X_OFF) + sprite->invisible = TRUE; + else + sprite->invisible = FALSE; + } + else + { + sprite->x = sprite->sDestX; + sprite->callback = SpriteCallbackDummy; + } +} + +#undef sCurrX +#undef sMoveIncr +#undef sTime +#undef sDestX + +static void DrawAllRibbonsSmall(struct Pokenav_RibbonsSummaryMenu *menu) +{ + u32 *ribbonIds; + + ClearRibbonsSummaryBg(); + + ribbonIds = GetNormalRibbonIds(&sRibbonDraw_Total); + for (sRibbonDraw_Current = 0; sRibbonDraw_Current < sRibbonDraw_Total; sRibbonDraw_Current++) + DrawRibbonSmall(sRibbonDraw_Current, *(ribbonIds++)); + + ribbonIds = GetGiftRibbonIds(&sRibbonDraw_Total); + for (sRibbonDraw_Current = 0; sRibbonDraw_Current < sRibbonDraw_Total; sRibbonDraw_Current++) + DrawRibbonSmall(sRibbonDraw_Current + GIFT_RIBBON_START_POS, *(ribbonIds++)); + + CopyBgTilemapBufferToVram(1); +} + +// Redundant, the same FillBg is called in LoopedTask_OpenRibbonsSummaryMenu +static void ClearRibbonsSummaryBg(void) +{ + FillBgTilemapBufferRect_Palette0(1, 0, 0, 0, 32, 20); +} + +static void DrawRibbonSmall(u32 i, u32 ribbonId) +{ + u16 bgData[4]; + u32 destX = (i % RIBBONS_PER_ROW) * 2 + 11; + u32 destY = (i / RIBBONS_PER_ROW) * 2 + 4; + + BufferSmallRibbonGfxData(bgData, ribbonId); + CopyToBgTilemapBufferRect(1, bgData, destX, destY, 2, 2); +} + +// Below correspond to a ribbon icon in ribbons/icons.png and ribbons/icons_big.png; 0 at top, 11 at bottom +enum { + RIBBONGFX_CHAMPION, + RIBBONGFX_CONTEST_NORMAL, + RIBBONGFX_CONTEST_SUPER, + RIBBONGFX_CONTEST_HYPER, + RIBBONGFX_CONTEST_MASTER, + RIBBONGFX_WINNING, + RIBBONGFX_VICTORY, + RIBBONGFX_ARTIST, + RIBBONGFX_EFFORT, + RIBBONGFX_GIFT_1, + RIBBONGFX_GIFT_2, + RIBBONGFX_GIFT_3, +}; + +#define TO_PAL_OFFSET(palNum)((palNum) - PALTAG_RIBBON_ICONS_1) + +struct +{ + u16 tileNumOffset; + u16 palNumOffset; +} static const sRibbonGfxData[] = +{ + [CHAMPION_RIBBON] = { RIBBONGFX_CHAMPION, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_1)}, + [COOL_RIBBON_NORMAL] = { RIBBONGFX_CONTEST_NORMAL, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_1)}, + [COOL_RIBBON_SUPER] = { RIBBONGFX_CONTEST_SUPER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_1)}, + [COOL_RIBBON_HYPER] = { RIBBONGFX_CONTEST_HYPER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_1)}, + [COOL_RIBBON_MASTER] = { RIBBONGFX_CONTEST_MASTER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_1)}, + [BEAUTY_RIBBON_NORMAL] = { RIBBONGFX_CONTEST_NORMAL, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_2)}, + [BEAUTY_RIBBON_SUPER] = { RIBBONGFX_CONTEST_SUPER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_2)}, + [BEAUTY_RIBBON_HYPER] = { RIBBONGFX_CONTEST_HYPER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_2)}, + [BEAUTY_RIBBON_MASTER] = { RIBBONGFX_CONTEST_MASTER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_2)}, + [CUTE_RIBBON_NORMAL] = { RIBBONGFX_CONTEST_NORMAL, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_3)}, + [CUTE_RIBBON_SUPER] = { RIBBONGFX_CONTEST_SUPER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_3)}, + [CUTE_RIBBON_HYPER] = { RIBBONGFX_CONTEST_HYPER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_3)}, + [CUTE_RIBBON_MASTER] = { RIBBONGFX_CONTEST_MASTER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_3)}, + [SMART_RIBBON_NORMAL] = { RIBBONGFX_CONTEST_NORMAL, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_4)}, + [SMART_RIBBON_SUPER] = { RIBBONGFX_CONTEST_SUPER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_4)}, + [SMART_RIBBON_HYPER] = { RIBBONGFX_CONTEST_HYPER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_4)}, + [SMART_RIBBON_MASTER] = { RIBBONGFX_CONTEST_MASTER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_4)}, + [TOUGH_RIBBON_NORMAL] = { RIBBONGFX_CONTEST_NORMAL, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_5)}, + [TOUGH_RIBBON_SUPER] = { RIBBONGFX_CONTEST_SUPER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_5)}, + [TOUGH_RIBBON_HYPER] = { RIBBONGFX_CONTEST_HYPER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_5)}, + [TOUGH_RIBBON_MASTER] = { RIBBONGFX_CONTEST_MASTER, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_5)}, + [WINNING_RIBBON] = { RIBBONGFX_WINNING, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_1)}, + [VICTORY_RIBBON] = { RIBBONGFX_VICTORY, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_1)}, + [ARTIST_RIBBON] = { RIBBONGFX_ARTIST, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_2)}, + [EFFORT_RIBBON] = { RIBBONGFX_EFFORT, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_3)}, + [MARINE_RIBBON] = { RIBBONGFX_GIFT_1, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_2)}, + [LAND_RIBBON] = { RIBBONGFX_GIFT_1, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_4)}, + [SKY_RIBBON] = { RIBBONGFX_GIFT_1, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_5)}, + [COUNTRY_RIBBON] = { RIBBONGFX_GIFT_2, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_4)}, + [NATIONAL_RIBBON] = { RIBBONGFX_GIFT_2, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_5)}, + [EARTH_RIBBON] = { RIBBONGFX_GIFT_3, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_1)}, + [WORLD_RIBBON] = { RIBBONGFX_GIFT_3, TO_PAL_OFFSET(PALTAG_RIBBON_ICONS_2)}, +}; + +#undef TO_PAL_OFFSET + +static void BufferSmallRibbonGfxData(u16 *dst, u32 ribbonId) +{ + u16 palNum = sRibbonGfxData[ribbonId].palNumOffset + 2; + u16 tileNum = (sRibbonGfxData[ribbonId].tileNumOffset * 2) + 1; + + dst[0] = tileNum | (palNum << 12); + dst[1] = tileNum | (palNum << 12) | 0x400; + dst[2] = (tileNum + 1) | (palNum << 12); + dst[3] = (tileNum + 1) | (palNum << 12) | 0x400; +} + +static const struct CompressedSpriteSheet sSpriteSheet_RibbonIconsBig = +{ + sRibbonIconsBig_Gfx, 0x1800, GFXTAG_RIBBON_ICONS_BIG +}; + +static const struct SpritePalette sSpritePalettes_RibbonIcons[] = +{ + {sRibbonIcons1_Pal, PALTAG_RIBBON_ICONS_1}, + {sRibbonIcons2_Pal, PALTAG_RIBBON_ICONS_2}, + {sRibbonIcons3_Pal, PALTAG_RIBBON_ICONS_3}, + {sRibbonIcons4_Pal, PALTAG_RIBBON_ICONS_4}, + {sRibbonIcons5_Pal, PALTAG_RIBBON_ICONS_5}, + {}, +}; + +static const struct OamData sOamData_RibbonIconBig = +{ + .y = 0, + .affineMode = ST_OAM_AFFINE_NORMAL, + .objMode = ST_OAM_OBJ_NORMAL, + .mosaic = 0, + .bpp = ST_OAM_4BPP, + .shape = SPRITE_SHAPE(32x32), + .x = 0, + .matrixNum = 0, + .size = SPRITE_SIZE(32x32), + .tileNum = 0, + .priority = 1, + .paletteNum = 0, + .affineParam = 0 +}; + +static const union AffineAnimCmd sAffineAnim_RibbonIconBig_Normal[] = +{ + AFFINEANIMCMD_FRAME(128, 128, 0, 0), + AFFINEANIMCMD_END +}; + +static const union AffineAnimCmd sAffineAnim_RibbonIconBig_ZoomIn[] = +{ + AFFINEANIMCMD_FRAME(128, 128, 0, 0), + AFFINEANIMCMD_FRAME(32, 32, 0, 4), + AFFINEANIMCMD_END +}; + +static const union AffineAnimCmd sAffineAnim_RibbonIconBig_ZoomOut[] = +{ + AFFINEANIMCMD_FRAME(256, 256, 0, 0), + AFFINEANIMCMD_FRAME(-32, -32, 0, 4), + AFFINEANIMCMD_END +}; + +enum { + RIBBONANIM_NORMAL, + RIBBONANIM_ZOOM_IN, + RIBBONANIM_ZOOM_OUT, +}; + +static const union AffineAnimCmd *const sAffineAnims_RibbonIconBig[] = +{ + [RIBBONANIM_NORMAL] = sAffineAnim_RibbonIconBig_Normal, + [RIBBONANIM_ZOOM_IN] = sAffineAnim_RibbonIconBig_ZoomIn, + [RIBBONANIM_ZOOM_OUT] = sAffineAnim_RibbonIconBig_ZoomOut +}; + +static const struct SpriteTemplate sSpriteTemplate_RibbonIconBig = +{ + .tileTag = GFXTAG_RIBBON_ICONS_BIG, + .paletteTag = PALTAG_RIBBON_ICONS_1, + .oam = &sOamData_RibbonIconBig, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = sAffineAnims_RibbonIconBig, + .callback = SpriteCallbackDummy, +}; + +// Create dummy sprite to be used for the zoomed in version of the selected ribbon +static void CreateBigRibbonSprite(struct Pokenav_RibbonsSummaryMenu *menu) +{ + u8 spriteId; + + LoadCompressedSpriteSheet(&sSpriteSheet_RibbonIconsBig); + Pokenav_AllocAndLoadPalettes(sSpritePalettes_RibbonIcons); + + spriteId = CreateSprite(&sSpriteTemplate_RibbonIconBig, 0, 0, 0); + menu->bigRibbonSprite = &gSprites[spriteId]; + menu->bigRibbonSprite->invisible = TRUE; +} + +#define sInvisibleWhenDone data[0] + +static void UpdateAndZoomInSelectedRibbon(struct Pokenav_RibbonsSummaryMenu *menu) +{ + u32 ribbonId; + s32 position = GetSelectedPosition(); + s32 x = (position % RIBBONS_PER_ROW) * 16 + 96; + s32 y = (position / RIBBONS_PER_ROW) * 16 + 40; + + menu->bigRibbonSprite->x = x; + menu->bigRibbonSprite->y = y; + + // Set new selected ribbon's gfx data + ribbonId = GetRibbonId(); + menu->bigRibbonSprite->oam.tileNum = (sRibbonGfxData[ribbonId].tileNumOffset * 16) + GetSpriteTileStartByTag(GFXTAG_RIBBON_ICONS_BIG); + menu->bigRibbonSprite->oam.paletteNum = IndexOfSpritePaletteTag(sRibbonGfxData[ribbonId].palNumOffset + PALTAG_RIBBON_ICONS_1); + + // Start zoom in animation + StartSpriteAffineAnim(menu->bigRibbonSprite, RIBBONANIM_ZOOM_IN); + menu->bigRibbonSprite->invisible = FALSE; + menu->bigRibbonSprite->sInvisibleWhenDone = FALSE; + menu->bigRibbonSprite->callback = SpriteCB_WaitForRibbonAnimation; +} + +// Start animation to zoom out of selected ribbon +static void ZoomOutSelectedRibbon(struct Pokenav_RibbonsSummaryMenu *menu) +{ + menu->bigRibbonSprite->sInvisibleWhenDone = TRUE; + StartSpriteAffineAnim(menu->bigRibbonSprite, RIBBONANIM_ZOOM_OUT); + menu->bigRibbonSprite->callback = SpriteCB_WaitForRibbonAnimation; +} + +static bool32 IsRibbonAnimating(struct Pokenav_RibbonsSummaryMenu *menu) +{ + return (menu->bigRibbonSprite->callback != SpriteCallbackDummy); +} + +static void SpriteCB_WaitForRibbonAnimation(struct Sprite *sprite) +{ + if (sprite->affineAnimEnded) + { + sprite->invisible = sprite->sInvisibleWhenDone; + sprite->callback = SpriteCallbackDummy; + } +} -- cgit v1.2.3