#include "global.h" #include "pokenav.h" #include "constants/songs.h" #include "sound.h" #include "constants/rgb.h" #include "palette.h" #include "bg.h" #include "window.h" #include "strings.h" #include "graphics.h" #include "decompress.h" #include "gpu_regs.h" #include "menu.h" #include "dma3.h" struct Pokenav_MainMenu { void (*loopTask)(u32); u32 (*isLoopTaskActiveFunc)(void); u32 unused; u32 currentTaskId; u32 helpBarWindowId; u32 palettes; struct Sprite *spinningPokenav; struct Sprite *leftHeaderSprites[2]; struct Sprite *submenuLeftHeaderSprites[2]; u8 tilemapBuffer[BG_SCREEN_SIZE]; }; // This struct uses a 32bit tag, and doesn't have a size field. // Needed to match LoadLeftHeaderGfxForSubMenu. struct CompressedSpriteSheetNoSize { const u32 *data; // LZ77 compressed palette data u32 tag; }; static void CleanupPokenavMainMenuResources(void); static void LoadLeftHeaderGfxForSubMenu(u32); static void LoadLeftHeaderGfxForMenu(u32); static void HideLeftHeaderSubmenuSprites(bool32); static void HideLeftHeaderSprites(bool32); static void ShowLeftHeaderSprites(u32, bool32); static void ShowLeftHeaderSubmenuSprites(u32, bool32); static void MoveLeftHeader(struct Sprite *, s32, s32, s32); static void SpriteCB_MoveLeftHeader(struct Sprite *); static void InitPokenavMainMenuResources(void); static void CreateLeftHeaderSprites(void); static void InitHelpBar(void); static u32 LoopedTask_SlideMenuHeaderUp(s32); static u32 LoopedTask_SlideMenuHeaderDown(s32); static void DrawHelpBar(u32); static void SpriteCB_SpinningPokenav(struct Sprite*); static u32 LoopedTask_InitPokenavMenu(s32); static const u16 sSpinningPokenav_Pal[] = INCBIN_U16("graphics/pokenav/nav_icon.gbapal"); static const u32 sSpinningPokenav_Gfx[] = INCBIN_U32("graphics/pokenav/nav_icon.4bpp.lz"); static const u32 sBlueLightCopy[] = INCBIN_U32("graphics/pokenav/blue_light.4bpp.lz"); // Unused copy of sMatchCallBlueLightTiles const struct BgTemplate gPokenavMainMenuBgTemplates[] = { { .bg = 0, .charBaseIndex = 0, .mapBaseIndex = 5, .screenSize = 0, .paletteMode = 0, .priority = 0, .baseTile = 0, } }; static const struct WindowTemplate sHelpBarWindowTemplate[] = { { .bg = 0, .tilemapLeft = 1, .tilemapTop = 22, .width = 16, .height = 2, .paletteNum = 0, .baseBlock = 0x36, }, DUMMY_WIN_TEMPLATE }; static const u8 *const sHelpBarTexts[HELPBAR_COUNT] = { [HELPBAR_NONE] = gText_Pokenav_ClearButtonList, [HELPBAR_MAP_ZOOMED_OUT] = gText_PokenavMap_ZoomedOutButtons, [HELPBAR_MAP_ZOOMED_IN] = gText_PokenavMap_ZoomedInButtons, [HELPBAR_CONDITION_MON_LIST] = gText_PokenavCondition_MonListButtons, [HELPBAR_CONDITION_MON_STATUS] = gText_PokenavCondition_MonStatusButtons, [HELPBAR_CONDITION_MARKINGS] = gText_PokenavCondition_MarkingButtons, [HELPBAR_MC_TRAINER_LIST] = gText_PokenavMatchCall_TrainerListButtons, [HELPBAR_MC_CALL_MENU] = gText_PokenavMatchCall_CallMenuButtons, [HELPBAR_MC_CHECK_PAGE] = gText_PokenavMatchCall_CheckTrainerButtons, [HELPBAR_RIBBONS_MON_LIST] = gText_PokenavRibbons_MonListButtons, [HELPBAR_RIBBONS_LIST] = gText_PokenavRibbons_RibbonListButtons, [HELPBAR_RIBBONS_CHECK] = gText_PokenavRibbons_RibbonCheckButtons, }; static const u8 sHelpBarTextColors[3] = { TEXT_COLOR_RED, TEXT_COLOR_WHITE, TEXT_COLOR_DARK_GRAY }; static const struct CompressedSpriteSheet gSpinningPokenavSpriteSheet[] = { { .data = sSpinningPokenav_Gfx, .size = 0x1000, .tag = 0, } }; static const struct SpritePalette gSpinningNavgearPalettes[] = { { .data = sSpinningPokenav_Pal, .tag = 0, }, {} }; static const struct CompressedSpriteSheet sMenuLeftHeaderSpriteSheet = { .data = gPokenavLeftHeaderHoennMap_Gfx, // Hoenn map is the first of the headers listed .size = 0xC00, .tag = 2 }; static const struct CompressedSpriteSheet sMenuLeftHeaderSpriteSheets[] = { [POKENAV_GFX_MAIN_MENU] = { .data = gPokenavLeftHeaderMainMenu_Gfx, .size = 0x20, .tag = 3 }, [POKENAV_GFX_CONDITION_MENU] = { .data = gPokenavLeftHeaderCondition_Gfx, .size = 0x20, .tag = 1 }, [POKENAV_GFX_RIBBONS_MENU] = { .data = gPokenavLeftHeaderRibbons_Gfx, .size = 0x20, .tag = 2 }, [POKENAV_GFX_MATCH_CALL_MENU] = { .data = gPokenavLeftHeaderMatchCall_Gfx, .size = 0x20, .tag = 4 }, [POKENAV_GFX_MAP_MENU_ZOOMED_OUT] = { .data = gPokenavLeftHeaderHoennMap_Gfx, .size = 0x20, .tag = 0 }, [POKENAV_GFX_MAP_MENU_ZOOMED_IN] = { .data = gPokenavLeftHeaderHoennMap_Gfx, .size = 0x40, .tag = 0 } }; static const struct CompressedSpriteSheetNoSize sPokenavSubMenuLeftHeaderSpriteSheets[] = { [POKENAV_GFX_PARTY_MENU - POKENAV_GFX_SUBMENUS_START] = { .data = gPokenavLeftHeaderParty_Gfx, .tag = 1 }, [POKENAV_GFX_SEARCH_MENU - POKENAV_GFX_SUBMENUS_START] = { .data = gPokenavLeftHeaderSearch_Gfx, .tag = 1 }, [POKENAV_GFX_COOL_MENU - POKENAV_GFX_SUBMENUS_START] = { .data = gPokenavLeftHeaderCool_Gfx, .tag = 4 }, [POKENAV_GFX_BEAUTY_MENU - POKENAV_GFX_SUBMENUS_START] = { .data = gPokenavLeftHeaderBeauty_Gfx, .tag = 1 }, [POKENAV_GFX_CUTE_MENU - POKENAV_GFX_SUBMENUS_START] = { .data = gPokenavLeftHeaderCute_Gfx, .tag = 2 }, [POKENAV_GFX_SMART_MENU - POKENAV_GFX_SUBMENUS_START] = { .data = gPokenavLeftHeaderSmart_Gfx, .tag = 0 }, [POKENAV_GFX_TOUGH_MENU - POKENAV_GFX_SUBMENUS_START] = { .data = gPokenavLeftHeaderTough_Gfx, .tag = 0 } }; static const struct OamData sSpinningPokenavSpriteOam = { .y = 0, .affineMode = ST_OAM_AFFINE_OFF, .objMode = ST_OAM_OBJ_NORMAL, .bpp = ST_OAM_4BPP, .shape = SPRITE_SHAPE(32x32), .x = 0, .size = SPRITE_SIZE(32x32), .tileNum = 0, .priority = 0, .paletteNum = 0, }; static const union AnimCmd sSpinningPokenavAnims[] = { ANIMCMD_FRAME(0, 8), ANIMCMD_FRAME(16, 8), ANIMCMD_FRAME(32, 8), ANIMCMD_FRAME(48, 8), ANIMCMD_FRAME(64, 8), ANIMCMD_FRAME(80, 8), ANIMCMD_FRAME(96, 8), ANIMCMD_FRAME(112, 8), ANIMCMD_JUMP(0) }; static const union AnimCmd *const sSpinningPokenavAnimTable[] = { sSpinningPokenavAnims }; static const struct SpriteTemplate sSpinningPokenavSpriteTemplate = { .tileTag = 0, .paletteTag = 0, .oam = &sSpinningPokenavSpriteOam, .anims = sSpinningPokenavAnimTable, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCB_SpinningPokenav }; static const struct OamData sOamData_LeftHeader = { .y = 0, .affineMode = ST_OAM_AFFINE_OFF, .objMode = ST_OAM_OBJ_NORMAL, .bpp = ST_OAM_4BPP, .shape = SPRITE_SHAPE(64x32), .x = 0, .size = SPRITE_SIZE(64x32), .tileNum = 0, .priority = 1, .paletteNum = 0, }; static const struct OamData sOamData_SubmenuLeftHeader = { .y = 0, .affineMode = ST_OAM_AFFINE_OFF, .objMode = ST_OAM_OBJ_NORMAL, .bpp = ST_OAM_4BPP, .shape = SPRITE_SHAPE(32x16), .x = 0, .matrixNum = 0, .size = SPRITE_SIZE(32x16), .tileNum = 0, .priority = 1, .paletteNum = 0, }; static const struct SpriteTemplate sLeftHeaderSpriteTemplate = { .tileTag = 2, .paletteTag = 1, .oam = &sOamData_LeftHeader, .anims = gDummySpriteAnimTable, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCallbackDummy }; static const struct SpriteTemplate sSubmenuLeftHeaderSpriteTemplate = { .tileTag = 2, .paletteTag = 2, .oam = &sOamData_SubmenuLeftHeader, .anims = gDummySpriteAnimTable, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCallbackDummy }; bool32 InitPokenavMainMenu(void) { struct Pokenav_MainMenu *menu; menu = AllocSubstruct(POKENAV_SUBSTRUCT_MAIN_MENU, sizeof(struct Pokenav_MainMenu)); if (menu == NULL) return FALSE; ResetSpriteData(); FreeAllSpritePalettes(); menu->currentTaskId = CreateLoopedTask(LoopedTask_InitPokenavMenu, 1); return TRUE; } u32 PokenavMainMenuLoopedTaskIsActive(void) { struct Pokenav_MainMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_MAIN_MENU); return IsLoopedTaskActive(menu->currentTaskId); } void ShutdownPokenav(void) { PlaySE(SE_POKENAV_OFF); ResetBldCnt_(); BeginNormalPaletteFade(PALETTES_ALL, -1, 0, 16, RGB_BLACK); } bool32 WaitForPokenavShutdownFade(void) { if (!gPaletteFade.active) { FreeMenuHandlerSubstruct2(); CleanupPokenavMainMenuResources(); FreeAllWindowBuffers(); return FALSE; } return TRUE; } static u32 LoopedTask_InitPokenavMenu(s32 state) { struct Pokenav_MainMenu *menu; switch (state) { case 0: SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON | DISPCNT_OBJ_1D_MAP); FreeAllWindowBuffers(); ResetBgsAndClearDma3BusyFlags(0); InitBgsFromTemplates(0, gPokenavMainMenuBgTemplates, ARRAY_COUNT(gPokenavMainMenuBgTemplates)); ResetBgPositions(); ResetTempTileDataBuffers(); return LT_INC_AND_CONTINUE; case 1: menu = GetSubstructPtr(POKENAV_SUBSTRUCT_MAIN_MENU); DecompressAndCopyTileDataToVram(0, &gPokenavHeader_Gfx, 0, 0, 0); SetBgTilemapBuffer(0, menu->tilemapBuffer); CopyToBgTilemapBuffer(0, &gPokenavHeader_Tilemap, 0, 0); CopyPaletteIntoBufferUnfaded(gPokenavHeader_Pal, 0, 0x20); CopyBgTilemapBufferToVram(0); return LT_INC_AND_PAUSE; case 2: if (FreeTempTileDataBuffersIfPossible()) return LT_PAUSE; InitHelpBar(); return LT_INC_AND_PAUSE; case 3: if (IsDma3ManagerBusyWithBgCopy()) return LT_PAUSE; InitPokenavMainMenuResources(); CreateLeftHeaderSprites(); ShowBg(0); return LT_FINISH; default: return LT_FINISH; } } void SetActiveMenuLoopTasks(void *createLoopTask, void *isLoopTaskActive) // Fix types later. { struct Pokenav_MainMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_MAIN_MENU); menu->loopTask = createLoopTask; menu->isLoopTaskActiveFunc = isLoopTaskActive; menu->unused = 0; } void RunMainMenuLoopedTask(u32 state) { struct Pokenav_MainMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_MAIN_MENU); menu->unused = 0; menu->loopTask(state); } u32 IsActiveMenuLoopTaskActive(void) { struct Pokenav_MainMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_MAIN_MENU); return menu->isLoopTaskActiveFunc(); } void SlideMenuHeaderUp(void) { struct Pokenav_MainMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_MAIN_MENU); menu->currentTaskId = CreateLoopedTask(LoopedTask_SlideMenuHeaderUp, 4); } void SlideMenuHeaderDown(void) { struct Pokenav_MainMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_MAIN_MENU); menu->currentTaskId = CreateLoopedTask(LoopedTask_SlideMenuHeaderDown, 4); } bool32 MainMenuLoopedTaskIsBusy(void) { struct Pokenav_MainMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_MAIN_MENU); return IsLoopedTaskActive(menu->currentTaskId); } static u32 LoopedTask_SlideMenuHeaderUp(s32 state) { switch (state) { default: return LT_FINISH; case 1: return LT_INC_AND_PAUSE; case 0: return LT_INC_AND_PAUSE; case 2: if (ChangeBgY(0, 384, BG_COORD_ADD) >= 0x2000u) { ChangeBgY(0, 0x2000, BG_COORD_SET); return LT_FINISH; } return LT_PAUSE; } } static u32 LoopedTask_SlideMenuHeaderDown(s32 state) { if (ChangeBgY(0, 384, BG_COORD_SUB) <= 0) { ChangeBgY(0, 0, BG_COORD_SET); return LT_FINISH; } return LT_PAUSE; } void CopyPaletteIntoBufferUnfaded(const u16 *palette, u32 bufferOffset, u32 size) { CpuCopy16(palette, gPlttBufferUnfaded + bufferOffset, size); } void Pokenav_AllocAndLoadPalettes(const struct SpritePalette *palettes) { const struct SpritePalette *current; u32 index; for (current = palettes; current->data != NULL; current++) { index = AllocSpritePalette(current->tag); if (index == 0xFF) { break; } else { index = (index * 16) + 0x100; CopyPaletteIntoBufferUnfaded(current->data, index, 0x20); } } } void PokenavFillPalette(u32 palIndex, u16 fillValue) { CpuFill16(fillValue, gPlttBufferFaded + 0x100 + (palIndex * 16), 16 * sizeof(u16)); } void PokenavCopyPalette(const u16 *src, const u16 *dest, int size, int a3, int a4, u16 *palette) { if (a4 == 0) { CpuCopy16(src, palette, size * 2); } else if (a4 >= a3) { CpuCopy16(dest, palette, size * 2); } else { int r, g, b; int r1, g1, b1; while (size--) { r = GET_R(*src); g = GET_G(*src); b = GET_B(*src); r1 = ((((GET_R(*dest) << 8) - (r << 8)) / a3) * a4) >> 8; g1 = ((((GET_G(*dest) << 8) - (g << 8)) / a3) * a4) >> 8; b1 = ((((GET_B(*dest) << 8) - (b << 8)) / a3) * a4) >> 8; r = (r + r1) & 0x1F; //_RGB(r + r1, g + g1, b + b1); doesn't match g = (g + g1) & 0x1F; b = (b + b1) & 0x1F; *palette = RGB2(r, g, b); src++, dest++; palette++; } } } void PokenavFadeScreen(s32 fadeType) { struct Pokenav_MainMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_MAIN_MENU); switch (fadeType) { case POKENAV_FADE_TO_BLACK: BeginNormalPaletteFade(menu->palettes, -2, 0, 16, RGB_BLACK); break; case POKENAV_FADE_FROM_BLACK: BeginNormalPaletteFade(menu->palettes, -2, 16, 0, RGB_BLACK); break; case POKENAV_FADE_TO_BLACK_ALL: BeginNormalPaletteFade(PALETTES_ALL, -2, 0, 16, RGB_BLACK); break; case POKENAV_FADE_FROM_BLACK_ALL: BeginNormalPaletteFade(PALETTES_ALL, -2, 16, 0, RGB_BLACK); break; } } bool32 IsPaletteFadeActive(void) { return gPaletteFade.active; } // Excludes the first obj and bg palettes void FadeToBlackExceptPrimary(void) { BlendPalettes(PALETTES_ALL & ~(1 << 16 | 1), 16, RGB_BLACK); } void InitBgTemplates(const struct BgTemplate *templates, int count) { int i; for (i = 0; i < count; i++) InitBgFromTemplate(templates++); } static void InitHelpBar(void) { struct Pokenav_MainMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_MAIN_MENU); InitWindows(&sHelpBarWindowTemplate[0]); menu->helpBarWindowId = 0; DrawHelpBar(menu->helpBarWindowId); PutWindowTilemap(menu->helpBarWindowId); CopyWindowToVram(menu->helpBarWindowId, COPYWIN_FULL); } void PrintHelpBarText(u32 textId) { struct Pokenav_MainMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_MAIN_MENU); DrawHelpBar(menu->helpBarWindowId); AddTextPrinterParameterized3(menu->helpBarWindowId, FONT_NORMAL, 0, 1, sHelpBarTextColors, 0, sHelpBarTexts[textId]); } bool32 WaitForHelpBar(void) { return IsDma3ManagerBusyWithBgCopy(); } static void DrawHelpBar(u32 windowId) { FillWindowPixelBuffer(windowId, PIXEL_FILL(4)); FillWindowPixelRect(windowId, PIXEL_FILL(5), 0, 0, 0x80, 1); } static void InitPokenavMainMenuResources(void) { s32 i; u8 spriteId; struct Pokenav_MainMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_MAIN_MENU); for (i = 0; i < ARRAY_COUNT(gSpinningPokenavSpriteSheet); i++) LoadCompressedSpriteSheet(&gSpinningPokenavSpriteSheet[i]); Pokenav_AllocAndLoadPalettes(gSpinningNavgearPalettes); menu->palettes = ~1 & ~(0x10000 << IndexOfSpritePaletteTag(0)); spriteId = CreateSprite(&sSpinningPokenavSpriteTemplate, 220, 12, 0); menu->spinningPokenav = &gSprites[spriteId]; } static void CleanupPokenavMainMenuResources(void) { struct Pokenav_MainMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_MAIN_MENU); DestroySprite(menu->spinningPokenav); FreeSpriteTilesByTag(0); FreeSpritePaletteByTag(0); } static void SpriteCB_SpinningPokenav(struct Sprite *sprite) { // If the background starts scrolling, follow it. sprite->y2 = (GetBgY(0) / 256u) * -1; } struct Sprite *GetSpinningPokenavSprite(void) { struct Pokenav_MainMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_MAIN_MENU); menu->spinningPokenav->callback = SpriteCallbackDummy; return menu->spinningPokenav; } void HideSpinningPokenavSprite(void) { struct Pokenav_MainMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_MAIN_MENU); // Move sprite so it's no longer visible menu->spinningPokenav->x = 220; menu->spinningPokenav->y = 12; menu->spinningPokenav->callback = SpriteCB_SpinningPokenav; menu->spinningPokenav->invisible = FALSE; menu->spinningPokenav->oam.priority = 0; menu->spinningPokenav->subpriority = 0; } static void CreateLeftHeaderSprites(void) { s32 i, spriteId; struct Pokenav_MainMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_MAIN_MENU); LoadCompressedSpriteSheet(&sMenuLeftHeaderSpriteSheet); AllocSpritePalette(1); AllocSpritePalette(2); for (i = 0; i < (s32)ARRAY_COUNT(menu->leftHeaderSprites); i++) { // Create main left header spriteId = CreateSprite(&sLeftHeaderSpriteTemplate, 0, 0, 1); menu->leftHeaderSprites[i] = &gSprites[spriteId]; menu->leftHeaderSprites[i]->invisible = TRUE; menu->leftHeaderSprites[i]->x2 = i * 64; // Create submenu left header spriteId = CreateSprite(&sSubmenuLeftHeaderSpriteTemplate, 0, 0, 2); menu->submenuLeftHeaderSprites[i] = &gSprites[spriteId]; menu->submenuLeftHeaderSprites[i]->invisible = TRUE; menu->submenuLeftHeaderSprites[i]->x2 = i * 32; menu->submenuLeftHeaderSprites[i]->y2 = 18; menu->submenuLeftHeaderSprites[i]->oam.tileNum += (i * 8) + 64; } } void LoadLeftHeaderGfxForIndex(u32 menuGfxId) { if (menuGfxId < POKENAV_GFX_SUBMENUS_START) LoadLeftHeaderGfxForMenu(menuGfxId); else LoadLeftHeaderGfxForSubMenu(menuGfxId - POKENAV_GFX_SUBMENUS_START); } void UpdateRegionMapRightHeaderTiles(u32 menuGfxId) { struct Pokenav_MainMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_MAIN_MENU); if (menuGfxId == POKENAV_GFX_MAP_MENU_ZOOMED_OUT) menu->leftHeaderSprites[1]->oam.tileNum = GetSpriteTileStartByTag(2) + 32; else menu->leftHeaderSprites[1]->oam.tileNum = GetSpriteTileStartByTag(2) + 64; } static void LoadLeftHeaderGfxForMenu(u32 menuGfxId) { struct Pokenav_MainMenu *menu; u32 size, tag; if (menuGfxId >= POKENAV_GFX_SUBMENUS_START) return; menu = GetSubstructPtr(POKENAV_SUBSTRUCT_MAIN_MENU); tag = sMenuLeftHeaderSpriteSheets[menuGfxId].tag; size = GetDecompressedDataSize(sMenuLeftHeaderSpriteSheets[menuGfxId].data); LoadPalette(&gPokenavLeftHeader_Pal[tag * 16], (IndexOfSpritePaletteTag(1) * 16) + 0x100, 0x20); LZ77UnCompWram(sMenuLeftHeaderSpriteSheets[menuGfxId].data, gDecompressionBuffer); RequestDma3Copy(gDecompressionBuffer, (void *)OBJ_VRAM0 + (GetSpriteTileStartByTag(2) * 32), size, 1); menu->leftHeaderSprites[1]->oam.tileNum = GetSpriteTileStartByTag(2) + sMenuLeftHeaderSpriteSheets[menuGfxId].size; if (menuGfxId == POKENAV_GFX_MAP_MENU_ZOOMED_OUT || menuGfxId == POKENAV_GFX_MAP_MENU_ZOOMED_IN) menu->leftHeaderSprites[1]->x2 = 56; else menu->leftHeaderSprites[1]->x2 = 64; } static void LoadLeftHeaderGfxForSubMenu(u32 menuGfxId) { u32 size, tag; if (menuGfxId >= POKENAV_GFX_MENUS_END - POKENAV_GFX_SUBMENUS_START) return; tag = sPokenavSubMenuLeftHeaderSpriteSheets[menuGfxId].tag; size = GetDecompressedDataSize(sPokenavSubMenuLeftHeaderSpriteSheets[menuGfxId].data); LoadPalette(&gPokenavLeftHeader_Pal[tag * 16], (IndexOfSpritePaletteTag(2) * 16) + 0x100, 0x20); LZ77UnCompWram(sPokenavSubMenuLeftHeaderSpriteSheets[menuGfxId].data, &gDecompressionBuffer[0x1000]); RequestDma3Copy(&gDecompressionBuffer[0x1000], (void *)OBJ_VRAM0 + 0x800 + (GetSpriteTileStartByTag(2) * 32), size, 1); } void ShowLeftHeaderGfx(u32 menuGfxId, bool32 isMain, bool32 isOnRightSide) { u32 tileTop; if (!isMain) tileTop = 0x30; else tileTop = 0x10; if (menuGfxId < POKENAV_GFX_SUBMENUS_START) ShowLeftHeaderSprites(tileTop, isOnRightSide); else ShowLeftHeaderSubmenuSprites(tileTop, isOnRightSide); } void HideMainOrSubMenuLeftHeader(u32 id, bool32 onRightSide) { if (id < POKENAV_GFX_PARTY_MENU) HideLeftHeaderSprites(onRightSide); else HideLeftHeaderSubmenuSprites(onRightSide); } void SetLeftHeaderSpritesInvisibility(void) { s32 i; struct Pokenav_MainMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_MAIN_MENU); for (i = 0; i < (s32)ARRAY_COUNT(menu->leftHeaderSprites); i++) { menu->leftHeaderSprites[i]->invisible = TRUE; menu->submenuLeftHeaderSprites[i]->invisible = TRUE; } } bool32 AreLeftHeaderSpritesMoving(void) { struct Pokenav_MainMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_MAIN_MENU); if (menu->leftHeaderSprites[0]->callback == SpriteCallbackDummy && menu->submenuLeftHeaderSprites[0]->callback == SpriteCallbackDummy) return FALSE; else return TRUE; } static void ShowLeftHeaderSprites(u32 startY, bool32 isOnRightSide) { s32 start, end, i; struct Pokenav_MainMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_MAIN_MENU); if (!isOnRightSide) start = -96, end = 32; else start = 256, end = 160; for (i = 0; i < (s32)ARRAY_COUNT(menu->leftHeaderSprites); i++) { menu->leftHeaderSprites[i]->y = startY; MoveLeftHeader(menu->leftHeaderSprites[i], start, end, 12); } } static void ShowLeftHeaderSubmenuSprites(u32 startY, bool32 isOnRightSide) { s32 start, end, i; struct Pokenav_MainMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_MAIN_MENU); if (!isOnRightSide) start = -96, end = 16; else start = 256, end = 192; for (i = 0; i < (s32)ARRAY_COUNT(menu->submenuLeftHeaderSprites); i++) { menu->submenuLeftHeaderSprites[i]->y = startY; MoveLeftHeader(menu->submenuLeftHeaderSprites[i], start, end, 12); } } static void HideLeftHeaderSprites(bool32 isOnRightSide) { s32 start, end, i; struct Pokenav_MainMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_MAIN_MENU); if (!isOnRightSide) start = 32, end = -96; else start = 192, end = 256; for (i = 0; i < (s32)ARRAY_COUNT(menu->leftHeaderSprites); i++) { MoveLeftHeader(menu->leftHeaderSprites[i], start, end, 12); } } static void HideLeftHeaderSubmenuSprites(bool32 isOnRightSide) { s32 start, end, i; struct Pokenav_MainMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_MAIN_MENU); if (!isOnRightSide) start = 16, end = -96; else start = 192, end = 256; for (i = 0; i < (s32)ARRAY_COUNT(menu->submenuLeftHeaderSprites); i++) { MoveLeftHeader(menu->submenuLeftHeaderSprites[i], start, end, 12); } } static void MoveLeftHeader(struct Sprite *sprite, s32 startX, s32 endX, s32 duration) { sprite->x = startX; sprite->data[0] = startX * 16; sprite->data[1] = (endX - startX) * 16 / duration; sprite->data[2] = duration; sprite->data[7] = endX; sprite->callback = SpriteCB_MoveLeftHeader; } static void SpriteCB_MoveLeftHeader(struct Sprite *sprite) { if (sprite->data[2] != 0) { sprite->data[2]--; sprite->data[0] += sprite->data[1]; sprite->x = sprite->data[0] >> 4; if (sprite->x < -16 || sprite->x > 256) sprite->invisible = TRUE; else sprite->invisible = FALSE; } else { sprite->x = sprite->data[7]; sprite->callback = SpriteCallbackDummy; } }