diff options
author | GriffinR <griffin.g.richards@gmail.com> | 2021-11-12 17:13:50 -0500 |
---|---|---|
committer | GriffinR <griffin.g.richards@gmail.com> | 2021-11-12 17:13:50 -0500 |
commit | ffe2970e30f64f46a7539ac69d61ab4ea353a92c (patch) | |
tree | c48cd6c4063694006a372aa86573307c32e77d2f /src/pokenav_menu_handler_gfx.c | |
parent | baeacbe2f10ef69468d3bdb223d8ca74c963e9d6 (diff) |
Rename pokenav menu handler files
Diffstat (limited to 'src/pokenav_menu_handler_gfx.c')
-rw-r--r-- | src/pokenav_menu_handler_gfx.c | 1371 |
1 files changed, 1371 insertions, 0 deletions
diff --git a/src/pokenav_menu_handler_gfx.c b/src/pokenav_menu_handler_gfx.c new file mode 100644 index 000000000..1738142ac --- /dev/null +++ b/src/pokenav_menu_handler_gfx.c @@ -0,0 +1,1371 @@ +#include "global.h" +#include "malloc.h" +#include "decompress.h" +#include "bg.h" +#include "palette.h" +#include "trig.h" +#include "gpu_regs.h" +#include "menu.h" +#include "window.h" +#include "pokenav.h" +#include "graphics.h" +#include "sound.h" +#include "gym_leader_rematch.h" +#include "window.h" +#include "strings.h" +#include "scanline_effect.h" +#include "constants/songs.h" +#include "constants/rgb.h" + +#define GFXTAG_BLUE_LIGHT 1 +#define GFXTAG_OPTIONS 3 + +#define PALTAG_BLUE_LIGHT 3 +#define PALTAG_OPTIONS_DEFAULT 4 // Includes green for Smart/Region Map and yellow for Tough +#define PALTAG_OPTIONS_BLUE 5 +#define PALTAG_OPTIONS_PINK 6 +#define PALTAG_OPTIONS_BEIGE 7 +#define PALTAG_OPTIONS_RED 8 + +#define PALTAG_OPTIONS_START PALTAG_OPTIONS_DEFAULT + +#define NUM_OPTION_SUBSPRITES 4 + +#define OPTION_DEFAULT_X 140 +#define OPTION_SELECTED_X 130 +#define OPTION_EXIT_X (DISPLAY_WIDTH + 16) + +struct Pokenav_MenuGfx +{ + bool32 (*isTaskActiveCB)(void); + u32 loopedTaskId; + u16 optionDescWindowId; + u8 bg3ScrollTaskId; + u8 cursorPos; + u8 numIconsBlending; + bool8 pokenavAlreadyOpen; + bool32 iconVisible[MAX_POKENAV_MENUITEMS]; + struct Sprite * blueLightSprite; + struct Sprite * iconSprites[MAX_POKENAV_MENUITEMS][NUM_OPTION_SUBSPRITES]; + u8 bg1TilemapBuffer[BG_SCREEN_SIZE]; +}; + +static struct Pokenav_MenuGfx * OpenPokenavMenu(void); +static bool32 GetCurrentLoopedTaskActive(void); +static u32 LoopedTask_OpenMenu(s32); +static u32 LoopedTask_MoveMenuCursor(s32); +static u32 LoopedTask_OpenConditionMenu(s32); +static u32 LoopedTask_ReturnToMainMenu(s32); +static u32 LoopedTask_OpenConditionSearchMenu(s32); +static u32 LoopedTask_ReturnToConditionMenu(s32); +static u32 LoopedTask_SelectRibbonsNoWinners(s32); +static u32 LoopedTask_ReShowDescription(s32); +static u32 LoopedTask_OpenPokenavFeature(s32); +static void LoadPokenavOptionPalettes(void); +static void FreeAndDestroyMainMenuSprites(void); +static void CreateMenuOptionSprites(void); +static void DestroyMenuOptionSprites(void); +static void DrawCurrentMenuOptionLabels(void); +static void DrawOptionLabelGfx(const u16 *const *, s32, s32); +static void StartOptionAnimations_Enter(void); +static void StartOptionAnimations_CursorMoved(void); +static void StartOptionAnimations_Exit(void); +static void StartOptionSlide(struct Sprite **, s32, s32, s32); +static void StartOptionZoom(struct Sprite **); +static bool32 AreMenuOptionSpritesMoving(void); +static void SetOptionInvisibility(struct Sprite **, bool32); +static void SpriteCB_OptionSlide(struct Sprite *); +static void SpriteCB_OptionZoom(struct Sprite *); +static void Task_OptionBlend(u8); +static void CreateMatchCallBlueLightSprite(void); +static void SpriteCB_BlinkingBlueLight(struct Sprite *); +static void DestroyRematchBlueLightSprite(void); +static void AddOptionDescriptionWindow(void); +static void PrintCurrentOptionDescription(void); +static void PrintNoRibbonWinners(void); +static bool32 IsDma3ManagerBusyWithBgCopy_(void); +static void CreateMovingBgDotsTask(void); +static void DestroyMovingDotsBgTask(void); +static void Task_MoveBgDots(u8); +static void CreateBgDotPurplePalTask(void); +static void ChangeBgDotsColorToPurple(void); +static void CreateBgDotLightBluePalTask(void); +static bool32 IsTaskActive_UpdateBgDotsPalette(void); +static void Task_UpdateBgDotsPalette(u8); +static void SetupPokenavMenuScanlineEffects(void); +static void DestroyMenuOptionGlowTask(void); +static void ResetBldCnt(void); +static void InitMenuOptionGlow(void); +static void Task_CurrentMenuOptionGlow(u8); +static void SetMenuOptionGlow(void); + +static const u16 sPokenavBgDotsPal[] = INCBIN_U16("graphics/pokenav/bg_dots.gbapal"); +static const u32 sPokenavBgDotsTiles[] = INCBIN_U32("graphics/pokenav/bg_dots.4bpp.lz"); +static const u32 sPokenavBgDotsTilemap[] = INCBIN_U32("graphics/pokenav/bg_dots.bin.lz"); +static const u16 sPokenavDeviceBgPal[] = INCBIN_U16("graphics/pokenav/device_outline.gbapal"); +static const u32 sPokenavDeviceBgTiles[] = INCBIN_U32("graphics/pokenav/device_outline.4bpp.lz"); +static const u32 sPokenavDeviceBgTilemap[] = INCBIN_U32("graphics/pokenav/device_outline_map.bin.lz"); +static const u16 sMatchCallBlueLightPal[] = INCBIN_U16("graphics/pokenav/blue_light.gbapal"); +static const u32 sMatchCallBlueLightTiles[] = INCBIN_U32("graphics/pokenav/blue_light.4bpp.lz"); + +static const struct BgTemplate sPokenavMainMenuBgTemplates[] = { + { + .bg = 1, + .charBaseIndex = 1, + .mapBaseIndex = 15, + .screenSize = 0, + .paletteMode = 0, + .priority = 1, + .baseTile = 0x000 + }, { + .bg = 2, + .charBaseIndex = 2, + .mapBaseIndex = 23, + .screenSize = 0, + .paletteMode = 0, + .priority = 2, + .baseTile = 0x000 + }, { + .bg = 3, + .charBaseIndex = 3, + .mapBaseIndex = 31, + .screenSize = 0, + .paletteMode = 0, + .priority = 3, + .baseTile = 0x000 + } +}; + +static const LoopedTask sMenuHandlerLoopTaskFuncs[] = +{ + [POKENAV_MENU_FUNC_NONE] = NULL, + [POKENAV_MENU_FUNC_MOVE_CURSOR] = LoopedTask_MoveMenuCursor, + [POKENAV_MENU_FUNC_OPEN_CONDITION] = LoopedTask_OpenConditionMenu, + [POKENAV_MENU_FUNC_RETURN_TO_MAIN] = LoopedTask_ReturnToMainMenu, + [POKENAV_MENU_FUNC_OPEN_CONDITION_SEARCH] = LoopedTask_OpenConditionSearchMenu, + [POKENAV_MENU_FUNC_RETURN_TO_CONDITION] = LoopedTask_ReturnToConditionMenu, + [POKENAV_MENU_FUNC_NO_RIBBON_WINNERS] = LoopedTask_SelectRibbonsNoWinners, + [POKENAV_MENU_FUNC_RESHOW_DESCRIPTION] = LoopedTask_ReShowDescription, + [POKENAV_MENU_FUNC_OPEN_FEATURE] = LoopedTask_OpenPokenavFeature +}; + +static const struct CompressedSpriteSheet sPokenavOptionsSpriteSheets[] = +{ + { + .data = gPokenavOptions_Gfx, + .size = 0x3400, + .tag = GFXTAG_OPTIONS + }, + { + .data = sMatchCallBlueLightTiles, + .size = 0x0100, + .tag = GFXTAG_BLUE_LIGHT + } +}; + +static const struct SpritePalette sPokenavOptionsSpritePalettes[] = +{ + {&gPokenavOptions_Pal[0x00], PALTAG_OPTIONS_DEFAULT}, + {&gPokenavOptions_Pal[0x10], PALTAG_OPTIONS_BLUE}, + {&gPokenavOptions_Pal[0x20], PALTAG_OPTIONS_PINK}, + {&gPokenavOptions_Pal[0x30], PALTAG_OPTIONS_BEIGE}, + {&gPokenavOptions_Pal[0x40], PALTAG_OPTIONS_RED}, + {sMatchCallBlueLightPal, PALTAG_BLUE_LIGHT}, + {} +}; + +// Tile number, palette tag offset +static const u16 sOptionsLabelGfx_RegionMap[] = {0x000, PALTAG_OPTIONS_DEFAULT - PALTAG_OPTIONS_START}; +static const u16 sOptionsLabelGfx_Condition[] = {0x020, PALTAG_OPTIONS_BLUE - PALTAG_OPTIONS_START}; +static const u16 sOptionsLabelGfx_MatchCall[] = {0x040, PALTAG_OPTIONS_RED - PALTAG_OPTIONS_START}; +static const u16 sOptionsLabelGfx_Ribbons[] = {0x060, PALTAG_OPTIONS_PINK - PALTAG_OPTIONS_START}; +static const u16 sOptionsLabelGfx_SwitchOff[] = {0x080, PALTAG_OPTIONS_BEIGE - PALTAG_OPTIONS_START}; +static const u16 sOptionsLabelGfx_Party[] = {0x0A0, PALTAG_OPTIONS_BLUE - PALTAG_OPTIONS_START}; +static const u16 sOptionsLabelGfx_Search[] = {0x0C0, PALTAG_OPTIONS_BLUE - PALTAG_OPTIONS_START}; +static const u16 sOptionsLabelGfx_Cool[] = {0x0E0, PALTAG_OPTIONS_RED - PALTAG_OPTIONS_START}; +static const u16 sOptionsLabelGfx_Beauty[] = {0x100, PALTAG_OPTIONS_BLUE - PALTAG_OPTIONS_START}; +static const u16 sOptionsLabelGfx_Cute[] = {0x120, PALTAG_OPTIONS_PINK - PALTAG_OPTIONS_START}; +static const u16 sOptionsLabelGfx_Smart[] = {0x140, PALTAG_OPTIONS_DEFAULT - PALTAG_OPTIONS_START}; +static const u16 sOptionsLabelGfx_Tough[] = {0x160, PALTAG_OPTIONS_DEFAULT - PALTAG_OPTIONS_START}; +static const u16 sOptionsLabelGfx_Cancel[] = {0x180, PALTAG_OPTIONS_BEIGE - PALTAG_OPTIONS_START}; + +struct +{ + u16 yStart; + u16 deltaY; + const u16 *gfx[MAX_POKENAV_MENUITEMS]; +} static const sPokenavMenuOptionLabelGfx[POKENAV_MENU_TYPE_COUNT] = +{ + [POKENAV_MENU_TYPE_DEFAULT] = + { + .yStart = 42, + .deltaY = 20, + .gfx = { + sOptionsLabelGfx_RegionMap, + sOptionsLabelGfx_Condition, + sOptionsLabelGfx_SwitchOff + } + }, + [POKENAV_MENU_TYPE_UNLOCK_MC] = + { + .yStart = 42, + .deltaY = 20, + .gfx = { + sOptionsLabelGfx_RegionMap, + sOptionsLabelGfx_Condition, + sOptionsLabelGfx_MatchCall, + sOptionsLabelGfx_SwitchOff + } + }, + [POKENAV_MENU_TYPE_UNLOCK_MC_RIBBONS] = + { + .yStart = 42, + .deltaY = 20, + .gfx = { + sOptionsLabelGfx_RegionMap, + sOptionsLabelGfx_Condition, + sOptionsLabelGfx_MatchCall, + sOptionsLabelGfx_Ribbons, + sOptionsLabelGfx_SwitchOff + } + }, + [POKENAV_MENU_TYPE_CONDITION] = + { + .yStart = 56, + .deltaY = 20, + .gfx = { + sOptionsLabelGfx_Party, + sOptionsLabelGfx_Search, + sOptionsLabelGfx_Cancel + } + }, + [POKENAV_MENU_TYPE_CONDITION_SEARCH] = + { + .yStart = 40, + .deltaY = 16, + .gfx = { + sOptionsLabelGfx_Cool, + sOptionsLabelGfx_Beauty, + sOptionsLabelGfx_Cute, + sOptionsLabelGfx_Smart, + sOptionsLabelGfx_Tough, + sOptionsLabelGfx_Cancel + } + }, +}; + +static const struct WindowTemplate sOptionDescWindowTemplate = +{ + .bg = 1, + .tilemapLeft = 3, + .tilemapTop = 17, + .width = 24, + .height = 2, + .paletteNum = 1, + .baseBlock = 8 +}; + +static const u8 *const sPageDescriptions[] = +{ + [POKENAV_MENUITEM_MAP] = gText_CheckMapOfHoenn, + [POKENAV_MENUITEM_CONDITION] = gText_CheckPokemonInDetail, + [POKENAV_MENUITEM_MATCH_CALL] = gText_CallRegisteredTrainer, + [POKENAV_MENUITEM_RIBBONS] = gText_CheckObtainedRibbons, + [POKENAV_MENUITEM_SWITCH_OFF] = gText_PutAwayPokenav, + [POKENAV_MENUITEM_CONDITION_PARTY] = gText_CheckPartyPokemonInDetail, + [POKENAV_MENUITEM_CONDITION_SEARCH] = gText_CheckAllPokemonInDetail, + [POKENAV_MENUITEM_CONDITION_CANCEL] = gText_ReturnToPokenavMenu, + [POKENAV_MENUITEM_CONDITION_SEARCH_COOL] = gText_FindCoolPokemon, + [POKENAV_MENUITEM_CONDITION_SEARCH_BEAUTY] = gText_FindBeautifulPokemon, + [POKENAV_MENUITEM_CONDITION_SEARCH_CUTE] = gText_FindCutePokemon, + [POKENAV_MENUITEM_CONDITION_SEARCH_SMART] = gText_FindSmartPokemon, + [POKENAV_MENUITEM_CONDITION_SEARCH_TOUGH] = gText_FindToughPokemon, + [POKENAV_MENUITEM_CONDITION_SEARCH_CANCEL] = gText_ReturnToConditionMenu +}; + +static const u8 sOptionDescTextColors[] = {TEXT_COLOR_GREEN, TEXT_COLOR_BLUE, TEXT_COLOR_LIGHT_GREEN}; +static const u8 sOptionDescTextColors2[] = {TEXT_COLOR_GREEN, TEXT_COLOR_BLUE, TEXT_COLOR_LIGHT_GREEN}; + +static const struct OamData sOamData_MenuOption = +{ + .y = 0, + .affineMode = ST_OAM_AFFINE_OFF, + .objMode = ST_OAM_OBJ_NORMAL, + .bpp = ST_OAM_4BPP, + .shape = SPRITE_SHAPE(32x16), + .x = 0, + .size = SPRITE_SIZE(32x16), + .tileNum = 0, + .priority = 2, + .paletteNum = 0, +}; + +static const union AffineAnimCmd sAffineAnim_MenuOption_Normal[] = +{ + AFFINEANIMCMD_FRAME(0x100, 0x100, 0, 0), + AFFINEANIMCMD_END, +}; + +static const union AffineAnimCmd sAffineAnim_MenuOption_Zoom[] = +{ + AFFINEANIMCMD_FRAME(0x100, 0x100, 0, 0), + AFFINEANIMCMD_FRAME(0x10, 0x10, 0, 0x12), + AFFINEANIMCMD_END, +}; + +static const union AffineAnimCmd *const sAffineAnims_MenuOption[] = +{ + sAffineAnim_MenuOption_Normal, + sAffineAnim_MenuOption_Zoom +}; + +static const struct SpriteTemplate sMenuOptionSpriteTemplate = +{ + .tileTag = GFXTAG_OPTIONS, + .paletteTag = PALTAG_OPTIONS_START, + .oam = &sOamData_MenuOption, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = sAffineAnims_MenuOption, + .callback = SpriteCallbackDummy, +}; + +static const struct OamData sBlueLightOamData = +{ + .y = 0, + .affineMode = ST_OAM_AFFINE_OFF, + .objMode = ST_OAM_OBJ_NORMAL, + .bpp = ST_OAM_4BPP, + .shape = SPRITE_SHAPE(32x16), + .x = 0, + .size = SPRITE_SIZE(32x16), + .tileNum = 0, + .priority = 2, + .paletteNum = 0, +}; + +static const struct SpriteTemplate sMatchCallBlueLightSpriteTemplate = +{ + .tileTag = GFXTAG_BLUE_LIGHT, + .paletteTag = PALTAG_BLUE_LIGHT, + .oam = &sBlueLightOamData, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCallbackDummy, +}; + +static const struct ScanlineEffectParams sPokenavMainMenuScanlineEffectParams = +{ + ®_WIN0H, + ((DMA_ENABLE | DMA_START_HBLANK | DMA_REPEAT | DMA_DEST_RELOAD) << 16) | 1, + 1, + 0 +}; + +static bool32 AreAnyTrainerRematchesNearby(void) +{ + s32 i; + + for (i = 0; i < REMATCH_TABLE_ENTRIES; i++) + { + if (GetMatchTableMapSectionId(i) == gMapHeader.regionMapSectionId + && IsRematchEntryRegistered(i) + && gSaveBlock1Ptr->trainerRematches[i]) + return TRUE; + } + + return FALSE; +} + +bool32 OpenPokenavMenuInitial(void) +{ + struct Pokenav_MenuGfx * gfx = OpenPokenavMenu(); + + if (gfx == NULL) + return FALSE; + + gfx->pokenavAlreadyOpen = FALSE; + return TRUE; +} + +bool32 OpenPokenavMenuNotInitial(void) +{ + struct Pokenav_MenuGfx * gfx = OpenPokenavMenu(); + + if (gfx == NULL) + return FALSE; + + gfx->pokenavAlreadyOpen = TRUE; + return TRUE; +} + +static struct Pokenav_MenuGfx * OpenPokenavMenu(void) +{ + struct Pokenav_MenuGfx * gfx = AllocSubstruct(POKENAV_SUBSTRUCT_MENU_GFX, sizeof(struct Pokenav_MenuGfx)); + + if (gfx != NULL) + { + gfx->numIconsBlending = 0; + gfx->loopedTaskId = CreateLoopedTask(LoopedTask_OpenMenu, 1); + gfx->isTaskActiveCB = GetCurrentLoopedTaskActive; + } + + return gfx; +} + +void CreateMenuHandlerLoopedTask(s32 ltIdx) +{ + struct Pokenav_MenuGfx * gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MENU_GFX); + gfx->loopedTaskId = CreateLoopedTask(sMenuHandlerLoopTaskFuncs[ltIdx], 1); + gfx->isTaskActiveCB = GetCurrentLoopedTaskActive; +} + +bool32 IsMenuHandlerLoopedTaskActive(void) +{ + struct Pokenav_MenuGfx * gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MENU_GFX); + return gfx->isTaskActiveCB(); +} + +void FreeMenuHandlerSubstruct2(void) +{ + struct Pokenav_MenuGfx * gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MENU_GFX); + + DestroyMovingDotsBgTask(); + RemoveWindow(gfx->optionDescWindowId); + FreeAndDestroyMainMenuSprites(); + DestroyMenuOptionGlowTask(); + FreePokenavSubstruct(POKENAV_SUBSTRUCT_MENU_GFX); +} + +static bool32 GetCurrentLoopedTaskActive(void) +{ + struct Pokenav_MenuGfx * gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MENU_GFX); + + return IsLoopedTaskActive(gfx->loopedTaskId); +} + +static u32 LoopedTask_OpenMenu(s32 state) +{ + struct Pokenav_MenuGfx * gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MENU_GFX); + + switch (state) + { + case 0: + InitBgTemplates(sPokenavMainMenuBgTemplates, ARRAY_COUNT(sPokenavMainMenuBgTemplates)); + DecompressAndCopyTileDataToVram(1, gPokenavMessageBox_Gfx, 0, 0, 0); + SetBgTilemapBuffer(1, gfx->bg1TilemapBuffer); + CopyToBgTilemapBuffer(1, gPokenavMessageBox_Tilemap, 0, 0); + CopyBgTilemapBufferToVram(1); + CopyPaletteIntoBufferUnfaded(gPokenavMessageBox_Pal, 0x10, 0x20); + ChangeBgX(1, 0, BG_COORD_SET); + ChangeBgY(1, 0, BG_COORD_SET); + ChangeBgX(2, 0, BG_COORD_SET); + ChangeBgY(2, 0, BG_COORD_SET); + ChangeBgX(3, 0, BG_COORD_SET); + ChangeBgY(3, 0, BG_COORD_SET); + return LT_INC_AND_PAUSE; + case 1: + if (FreeTempTileDataBuffersIfPossible()) + return LT_PAUSE; + DecompressAndCopyTileDataToVram(2, sPokenavDeviceBgTiles, 0, 0, 0); + DecompressAndCopyTileDataToVram(2, sPokenavDeviceBgTilemap, 0, 0, 1); + CopyPaletteIntoBufferUnfaded(sPokenavDeviceBgPal, 0x20, 0x20); + return LT_INC_AND_PAUSE; + case 2: + if (FreeTempTileDataBuffersIfPossible()) + return LT_PAUSE; + DecompressAndCopyTileDataToVram(3, sPokenavBgDotsTiles, 0, 0, 0); + DecompressAndCopyTileDataToVram(3, sPokenavBgDotsTilemap, 0, 0, 1); + CopyPaletteIntoBufferUnfaded(sPokenavBgDotsPal, 0x30, 0x20); + if (GetPokenavMenuType() == POKENAV_MENU_TYPE_CONDITION || GetPokenavMenuType() == POKENAV_MENU_TYPE_CONDITION_SEARCH) + ChangeBgDotsColorToPurple(); + return LT_INC_AND_PAUSE; + case 3: + if (FreeTempTileDataBuffersIfPossible()) + return LT_PAUSE; + AddOptionDescriptionWindow(); + CreateMovingBgDotsTask(); + return LT_INC_AND_CONTINUE; + case 4: + LoadPokenavOptionPalettes(); + return LT_INC_AND_CONTINUE; + case 5: + PrintCurrentOptionDescription(); + CreateMenuOptionSprites(); + CreateMatchCallBlueLightSprite(); + DrawCurrentMenuOptionLabels(); + return LT_INC_AND_PAUSE; + case 6: + if (IsDma3ManagerBusyWithBgCopy_()) + return LT_PAUSE; + return LT_INC_AND_CONTINUE; + case 7: + ShowBg(1); + ShowBg(2); + ShowBg(3); + if (gfx->pokenavAlreadyOpen) + PokenavFadeScreen(1); + else + { + PlaySE(SE_POKENAV_ON); + PokenavFadeScreen(3); + } + switch (GetPokenavMenuType()) + { + case POKENAV_MENU_TYPE_CONDITION_SEARCH: + LoadLeftHeaderGfxForIndex(7); + // fallthrough + case POKENAV_MENU_TYPE_CONDITION: + LoadLeftHeaderGfxForIndex(1); + break; + default: + LoadLeftHeaderGfxForIndex(0); + break; + } + return LT_INC_AND_PAUSE; + case 8: + if (IsPaletteFadeActive()) + return LT_PAUSE; + switch (GetPokenavMenuType()) + { + case POKENAV_MENU_TYPE_CONDITION_SEARCH: + ShowLeftHeaderGfx(7, FALSE, FALSE); + // fallthrough + case POKENAV_MENU_TYPE_CONDITION: + ShowLeftHeaderGfx(1, FALSE, FALSE); + break; + default: + ShowLeftHeaderGfx(0, FALSE, FALSE); + break; + } + StartOptionAnimations_Enter(); + SetupPokenavMenuScanlineEffects(); + return LT_INC_AND_CONTINUE; + case 9: + if (AreMenuOptionSpritesMoving()) + return LT_PAUSE; + if (AreLeftHeaderSpritesMoving()) + return LT_PAUSE; + break; + } + return LT_FINISH; +} + +static u32 LoopedTask_MoveMenuCursor(s32 state) +{ + switch (state) + { + case 0: + SetMenuOptionGlow(); + StartOptionAnimations_CursorMoved(); + PrintCurrentOptionDescription(); + PlaySE(SE_SELECT); + return LT_INC_AND_PAUSE; + case 1: + if (AreMenuOptionSpritesMoving()) + return LT_PAUSE; + if (IsDma3ManagerBusyWithBgCopy_()) + return LT_PAUSE; + break; + } + return LT_FINISH; +} + +static u32 LoopedTask_OpenConditionMenu(s32 state) +{ + switch (state) + { + case 0: + ResetBldCnt(); + StartOptionAnimations_Exit(); + HideMainOrSubMenuLeftHeader(POKENAV_GFX_MAIN_MENU, 0); + PlaySE(SE_SELECT); + return LT_INC_AND_PAUSE; + case 1: + if (AreMenuOptionSpritesMoving()) + return LT_PAUSE; + if (AreLeftHeaderSpritesMoving()) + return LT_PAUSE; + DrawCurrentMenuOptionLabels(); + LoadLeftHeaderGfxForIndex(1); + return LT_INC_AND_PAUSE; + case 2: + StartOptionAnimations_Enter(); + ShowLeftHeaderGfx(1, FALSE, FALSE); + CreateBgDotPurplePalTask(); + PrintCurrentOptionDescription(); + return LT_INC_AND_PAUSE; + case 3: + if (AreMenuOptionSpritesMoving()) + return LT_PAUSE; + if (AreLeftHeaderSpritesMoving()) + return LT_PAUSE; + if (IsTaskActive_UpdateBgDotsPalette()) + return LT_PAUSE; + if (IsDma3ManagerBusyWithBgCopy_()) + return LT_PAUSE; + InitMenuOptionGlow(); + break; + } + return LT_FINISH; +} + +static u32 LoopedTask_ReturnToMainMenu(s32 state) +{ + switch (state) + { + case 0: + ResetBldCnt(); + StartOptionAnimations_Exit(); + HideMainOrSubMenuLeftHeader(POKENAV_GFX_CONDITION_MENU, 0); + return LT_INC_AND_PAUSE; + case 1: + if (AreMenuOptionSpritesMoving()) + return LT_PAUSE; + if (AreLeftHeaderSpritesMoving()) + return LT_PAUSE; + DrawCurrentMenuOptionLabels(); + LoadLeftHeaderGfxForIndex(0); + return LT_INC_AND_PAUSE; + case 2: + StartOptionAnimations_Enter(); + ShowLeftHeaderGfx(0, FALSE, FALSE); + CreateBgDotLightBluePalTask(); + PrintCurrentOptionDescription(); + return LT_INC_AND_PAUSE; + case 3: + if (AreMenuOptionSpritesMoving()) + return LT_PAUSE; + if (AreLeftHeaderSpritesMoving()) + return LT_PAUSE; + if (IsTaskActive_UpdateBgDotsPalette()) + return LT_PAUSE; + if (IsDma3ManagerBusyWithBgCopy_()) + return LT_PAUSE; + InitMenuOptionGlow(); + break; + } + return LT_FINISH; +} + +static u32 LoopedTask_OpenConditionSearchMenu(s32 state) +{ + switch (state) + { + case 0: + ResetBldCnt(); + StartOptionAnimations_Exit(); + PlaySE(SE_SELECT); + return LT_INC_AND_PAUSE; + case 1: + if (AreMenuOptionSpritesMoving()) + return LT_PAUSE; + LoadLeftHeaderGfxForIndex(7); + DrawCurrentMenuOptionLabels(); + return LT_INC_AND_PAUSE; + case 2: + StartOptionAnimations_Enter(); + ShowLeftHeaderGfx(7, FALSE, FALSE); + PrintCurrentOptionDescription(); + return LT_INC_AND_PAUSE; + case 3: + if (AreMenuOptionSpritesMoving()) + return LT_PAUSE; + if (AreLeftHeaderSpritesMoving()) + return LT_PAUSE; + if (IsTaskActive_UpdateBgDotsPalette()) + return LT_PAUSE; + InitMenuOptionGlow(); + break; + } + return LT_FINISH; +} + +static u32 LoopedTask_ReturnToConditionMenu(s32 state) +{ + switch (state) + { + case 0: + ResetBldCnt(); + StartOptionAnimations_Exit(); + HideMainOrSubMenuLeftHeader(POKENAV_GFX_SEARCH_MENU, 0); + return LT_INC_AND_PAUSE; + case 1: + if (AreMenuOptionSpritesMoving()) + return LT_PAUSE; + if (AreLeftHeaderSpritesMoving()) + return LT_PAUSE; + DrawCurrentMenuOptionLabels(); + return LT_INC_AND_PAUSE; + case 2: + StartOptionAnimations_Enter(); + PrintCurrentOptionDescription(); + return LT_INC_AND_PAUSE; + case 3: + if (AreMenuOptionSpritesMoving()) + return LT_PAUSE; + if (IsTaskActive_UpdateBgDotsPalette()) + return LT_PAUSE; + InitMenuOptionGlow(); + break; + } + return LT_FINISH; +} + +static u32 LoopedTask_SelectRibbonsNoWinners(s32 state) +{ + switch (state) + { + case 0: + PlaySE(SE_FAILURE); + PrintNoRibbonWinners(); + return LT_INC_AND_PAUSE; + case 1: + if (IsDma3ManagerBusyWithBgCopy()) + return LT_PAUSE; + break; + } + return LT_FINISH; +} + +// For redisplaying the Ribbons description to replace the No Ribbon Winners message +static u32 LoopedTask_ReShowDescription(s32 state) +{ + switch (state) + { + case 0: + PlaySE(SE_SELECT); + PrintCurrentOptionDescription(); + return LT_INC_AND_PAUSE; + case 1: + if (IsDma3ManagerBusyWithBgCopy()) + return LT_PAUSE; + break; + } + return LT_FINISH; +} + +// For selecting a feature option from a menu, e.g. the Map, Match Call, Beauty search, etc. +static u32 LoopedTask_OpenPokenavFeature(s32 state) +{ + switch (state) + { + case 0: + PrintHelpBarText(GetHelpBarTextId()); + return LT_INC_AND_PAUSE; + case 1: + if (WaitForHelpBar()) + return LT_PAUSE; + SlideMenuHeaderUp(); + ResetBldCnt(); + StartOptionAnimations_Exit(); + switch (GetPokenavMenuType()) + { + case POKENAV_MENU_TYPE_CONDITION_SEARCH: + HideMainOrSubMenuLeftHeader(POKENAV_GFX_SEARCH_MENU, FALSE); + // fallthrough + case POKENAV_MENU_TYPE_CONDITION: + HideMainOrSubMenuLeftHeader(POKENAV_GFX_CONDITION_MENU, FALSE); + break; + default: + HideMainOrSubMenuLeftHeader(POKENAV_GFX_MAIN_MENU, FALSE); + break; + } + PlaySE(SE_SELECT); + return LT_INC_AND_PAUSE; + case 2: + if (AreMenuOptionSpritesMoving()) + return LT_PAUSE; + if (AreLeftHeaderSpritesMoving()) + return LT_PAUSE; + PokenavFadeScreen(0); + return LT_INC_AND_PAUSE; + case 3: + if (IsPaletteFadeActive()) + return LT_PAUSE; + break; + } + return LT_FINISH; +} + +static void LoadPokenavOptionPalettes(void) +{ + s32 i; + + for (i = 0; i < ARRAY_COUNT(sPokenavOptionsSpriteSheets); i++) + LoadCompressedSpriteSheet(&sPokenavOptionsSpriteSheets[i]); + Pokenav_AllocAndLoadPalettes(sPokenavOptionsSpritePalettes); +} + +static void FreeAndDestroyMainMenuSprites(void) +{ + FreeSpriteTilesByTag(GFXTAG_OPTIONS); + FreeSpriteTilesByTag(GFXTAG_BLUE_LIGHT); + FreeSpritePaletteByTag(PALTAG_OPTIONS_DEFAULT); + FreeSpritePaletteByTag(PALTAG_OPTIONS_BLUE); + FreeSpritePaletteByTag(PALTAG_OPTIONS_PINK); + FreeSpritePaletteByTag(PALTAG_OPTIONS_BEIGE); + FreeSpritePaletteByTag(PALTAG_OPTIONS_RED); + FreeSpritePaletteByTag(PALTAG_BLUE_LIGHT); + DestroyMenuOptionSprites(); + DestroyRematchBlueLightSprite(); +} + +static void CreateMenuOptionSprites(void) +{ + s32 i, j; + struct Pokenav_MenuGfx * gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MENU_GFX); + + for (i = 0; i < MAX_POKENAV_MENUITEMS; i++) + { + for (j = 0; j < NUM_OPTION_SUBSPRITES; j++) + { + u8 spriteId = CreateSprite(&sMenuOptionSpriteTemplate, 0x8c, 20 * i + 40, 3); + gfx->iconSprites[i][j] = &gSprites[spriteId]; + gSprites[spriteId].x2 = 32 * j; + } + } +} + +static void DestroyMenuOptionSprites(void) +{ + s32 i, j; + struct Pokenav_MenuGfx * gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MENU_GFX); + + for (i = 0; i < MAX_POKENAV_MENUITEMS; i++) + { + for (j = 0; j < NUM_OPTION_SUBSPRITES; j++) + { + FreeSpriteOamMatrix(gfx->iconSprites[i][j]); + DestroySprite(gfx->iconSprites[i][j]); + } + } +} + +static void DrawCurrentMenuOptionLabels(void) +{ + s32 menuType = GetPokenavMenuType(); + DrawOptionLabelGfx(sPokenavMenuOptionLabelGfx[menuType].gfx, sPokenavMenuOptionLabelGfx[menuType].yStart, sPokenavMenuOptionLabelGfx[menuType].deltaY); +} + +static void DrawOptionLabelGfx(const u16 *const *optionGfx, s32 yPos, s32 deltaY) +{ + s32 i, j; + struct Pokenav_MenuGfx * gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MENU_GFX); + s32 baseTile = GetSpriteTileStartByTag(GFXTAG_OPTIONS); + + for (i = 0; i < MAX_POKENAV_MENUITEMS; i++) + { + if (*optionGfx != NULL) + { + for (j = 0; j < NUM_OPTION_SUBSPRITES; j++) + { + gfx->iconSprites[i][j]->oam.tileNum = (*optionGfx)[0] + baseTile + 8 * j; + gfx->iconSprites[i][j]->oam.paletteNum = IndexOfSpritePaletteTag((*optionGfx)[1] + PALTAG_OPTIONS_START); + gfx->iconSprites[i][j]->invisible = TRUE; + gfx->iconSprites[i][j]->y = yPos; + gfx->iconSprites[i][j]->x = OPTION_DEFAULT_X; + gfx->iconSprites[i][j]->x2 = 32 * j; + } + gfx->iconVisible[i] = TRUE; + } + else + { + for (j = 0; j < NUM_OPTION_SUBSPRITES; j++) + gfx->iconSprites[i][j]->invisible = TRUE; + + gfx->iconVisible[i] = FALSE; + } + optionGfx++; + yPos += deltaY; + } +} + +static void StartOptionAnimations_Enter(void) +{ + s32 i; + struct Pokenav_MenuGfx *gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MENU_GFX); + s32 cursorPos = GetPokenavCursorPos(); + s32 iconCount = 0; + s32 x; + + for (i = 0; i < MAX_POKENAV_MENUITEMS; i++) + { + if (gfx->iconVisible[i]) + { + if (iconCount++ == cursorPos) + { + x = OPTION_SELECTED_X; + gfx->cursorPos = i; + } + else + { + // Not selected, set default position + x = OPTION_DEFAULT_X; + } + + // Slide new options in + StartOptionSlide(gfx->iconSprites[i], OPTION_EXIT_X, x, 12); + SetOptionInvisibility(gfx->iconSprites[i], FALSE); + } + else + { + SetOptionInvisibility(gfx->iconSprites[i], TRUE); + } + } +} + +static void StartOptionAnimations_CursorMoved(void) +{ + s32 i; + struct Pokenav_MenuGfx *gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MENU_GFX); + s32 prevPos = GetPokenavCursorPos(); + s32 newPos; + + // Get the index of the next visible option + for (i = 0, newPos = 0; i < MAX_POKENAV_MENUITEMS; i++) + { + if (gfx->iconVisible[i]) + { + if (newPos == prevPos) + { + newPos = i; + break; + } + newPos++; + } + } + + // The selected option slides out a bit and the previously + // selected option slides back to its original position. + StartOptionSlide(gfx->iconSprites[gfx->cursorPos], OPTION_SELECTED_X, OPTION_DEFAULT_X, 4); + StartOptionSlide(gfx->iconSprites[newPos], OPTION_DEFAULT_X, OPTION_SELECTED_X, 4); + gfx->cursorPos = newPos; +} + +static void StartOptionAnimations_Exit(void) +{ + s32 i; + struct Pokenav_MenuGfx *gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MENU_GFX); + + for (i = 0; i < MAX_POKENAV_MENUITEMS; i++) + { + if (gfx->iconVisible[i]) + { + // Unselected options slide out, + // selected option zooms in + if (gfx->cursorPos != i) + StartOptionSlide(gfx->iconSprites[i], OPTION_DEFAULT_X, OPTION_EXIT_X, 8); + else + StartOptionZoom(gfx->iconSprites[i]); + } + } +} + +static bool32 AreMenuOptionSpritesMoving(void) +{ + s32 i; + struct Pokenav_MenuGfx *gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MENU_GFX); + + for (i = 0; i < MAX_POKENAV_MENUITEMS; i++) + { + if (gfx->iconSprites[i][0]->callback != SpriteCallbackDummy) + return TRUE; + } + + if (gfx->numIconsBlending != 0) + return TRUE; + + return FALSE; +} + +#define sSlideTime data[0] +#define sSlideAccel data[1] +#define sSlideSpeed data[2] +#define sSlideEndX data[7] + +static void StartOptionSlide(struct Sprite ** sprites, s32 startX, s32 endX, s32 time) +{ + s32 i; + + for (i = 0; i < NUM_OPTION_SUBSPRITES; i++) + { + (*sprites)->x = startX; + (*sprites)->sSlideTime = time; + (*sprites)->sSlideAccel = 16 * (endX - startX) / time; + (*sprites)->sSlideSpeed = 16 * startX; + (*sprites)->sSlideEndX = endX; + (*sprites)->callback = SpriteCB_OptionSlide; + sprites++; + } +} + +#define sZoomDelay data[0] +#define sZoomSetAffine data[1] +#define sZoomSpeed data[2] +#define sZoomSubspriteId data[7] + +#define tBlendDelay data[0] +#define tBlendState data[1] +#define tBlendTarget1 data[2] +#define tBlendTarget2 data[3] +#define tBlendCounter data[4] + +// When an option is selected it zooms in and blends away as part +// of the transition to the next screen. +static void StartOptionZoom(struct Sprite ** sprites) +{ + s32 i; + struct Pokenav_MenuGfx * gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MENU_GFX); + u8 taskId; + + for (i = 0; i < NUM_OPTION_SUBSPRITES; i++) + { + (*sprites)->oam.objMode = ST_OAM_OBJ_BLEND; + (*sprites)->oam.affineMode = ST_OAM_AFFINE_DOUBLE; + (*sprites)->callback = SpriteCB_OptionZoom; + (*sprites)->sZoomDelay = 8; + (*sprites)->sZoomSetAffine = FALSE; + (*sprites)->sZoomSubspriteId = i; + InitSpriteAffineAnim(sprites[0]); + StartSpriteAffineAnim(sprites[0], 0); + sprites++; + } + + SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(16, 0)); + taskId = CreateTask(Task_OptionBlend, 3); + gTasks[taskId].tBlendDelay = 8; + gfx->numIconsBlending++; +} + +static void SetOptionInvisibility(struct Sprite ** sprites, bool32 invisible) +{ + s32 i; + + for (i = 0; i < NUM_OPTION_SUBSPRITES; i++) + { + (*sprites)->invisible = invisible; + sprites++; + } +} + +static void SpriteCB_OptionSlide(struct Sprite * sprite) +{ + sprite->sSlideTime--; + if (sprite->sSlideTime != -1) + { + sprite->sSlideSpeed += sprite->sSlideAccel; + sprite->x = sprite->sSlideSpeed >> 4; + } + else + { + sprite->x = sprite->sSlideEndX; + sprite->callback = SpriteCallbackDummy; + } +} + +#undef sSlideTime +#undef sSlideAccel +#undef sSlideSpeed +#undef sSlideEndX + +static void SpriteCB_OptionZoom(struct Sprite * sprite) +{ + s32 temp; + s32 x; + if (sprite->sZoomDelay == 0) + { + if (!sprite->sZoomSetAffine) + { + StartSpriteAffineAnim(sprite, 1); + sprite->sZoomSetAffine++; + sprite->sZoomSpeed = 0x100; + sprite->x += sprite->x2; + sprite->x2 = 0; + } + else + { + sprite->sZoomSpeed += 16; + temp = sprite->sZoomSpeed; + x = temp >> 3; + x = (x - 32) / 2; + + // Each subsprite needs to zoom to a different degree/direction + switch (sprite->sZoomSubspriteId) + { + case 0: + sprite->x2 = -x * 3; + break; + case 1: + sprite->x2 = -x; + break; + case 2: + sprite->x2 = x; + break; + case 3: + sprite->x2 = x * 3; + break; + } + if (sprite->affineAnimEnded) + { + sprite->invisible = TRUE; + FreeOamMatrix(sprite->oam.matrixNum); + CalcCenterToCornerVec(sprite, sprite->oam.shape, sprite->oam.size, ST_OAM_AFFINE_OFF); + sprite->oam.affineMode = ST_OAM_AFFINE_OFF; + sprite->oam.objMode = ST_OAM_OBJ_NORMAL; + sprite->callback = SpriteCallbackDummy; + } + } + } + else + { + sprite->sZoomDelay--; + } +} + +#undef sZoomDelay +#undef sZoomSetAffine +#undef sZoomSpeed +#undef sZoomSubspriteId + +static void Task_OptionBlend(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + + if (tBlendDelay == 0) + { + switch (tBlendState) + { + case 0: + tBlendTarget1 = 16; + tBlendTarget2 = 0; + SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_EFFECT_NONE | BLDCNT_TGT2_ALL); + SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(16, 0)); + tBlendState++; + break; + case 1: + if (tBlendCounter & 1) + { + tBlendTarget1 -= 3; + if (tBlendTarget1 < 0) + tBlendTarget1 = 0; + } + else + { + tBlendTarget2 += 3; + if (tBlendTarget2 > 16) + tBlendTarget2 = 16; + } + SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(tBlendTarget1, tBlendTarget2)); + tBlendCounter++; + if (tBlendCounter == 12) + { + ((struct Pokenav_MenuGfx *)GetSubstructPtr(POKENAV_SUBSTRUCT_MENU_GFX))->numIconsBlending--; + SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(0, 16)); + DestroyTask(taskId); + } + break; + } + } + else + { + tBlendDelay--; + } +} + +#undef tBlendDelay +#undef tBlendState +#undef tBlendTarget1 +#undef tBlendTarget2 +#undef tBlendCounter + +// Blue light that blinks if there are available rematches nearby +static void CreateMatchCallBlueLightSprite(void) +{ + struct Pokenav_MenuGfx * gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MENU_GFX); + u8 spriteId = CreateSprite(&sMatchCallBlueLightSpriteTemplate, 0x10, 0x60, 4); + gfx->blueLightSprite = &gSprites[spriteId]; + if (AreAnyTrainerRematchesNearby()) + gfx->blueLightSprite->callback = SpriteCB_BlinkingBlueLight; + else + gfx->blueLightSprite->invisible = TRUE; +} + +static void DestroyRematchBlueLightSprite(void) +{ + struct Pokenav_MenuGfx *gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MENU_GFX); + DestroySprite(gfx->blueLightSprite); +} + +static void SpriteCB_BlinkingBlueLight(struct Sprite * sprite) +{ + sprite->data[0]++; + if (sprite->data[0] > 8) + { + sprite->data[0] = 0; + sprite->invisible ^= 1; + } +} + +static void AddOptionDescriptionWindow(void) +{ + struct Pokenav_MenuGfx * gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MENU_GFX); + + gfx->optionDescWindowId = AddWindow(&sOptionDescWindowTemplate); + PutWindowTilemap(gfx->optionDescWindowId); + FillWindowPixelBuffer(gfx->optionDescWindowId, PIXEL_FILL(6)); + CopyWindowToVram(gfx->optionDescWindowId, COPYWIN_FULL); +} + +static void PrintCurrentOptionDescription(void) +{ + struct Pokenav_MenuGfx * gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MENU_GFX); + int menuItem = GetCurrentMenuItemId(); + const u8 * desc = sPageDescriptions[menuItem]; + u32 width = GetStringWidth(FONT_NORMAL, desc, -1); + FillWindowPixelBuffer(gfx->optionDescWindowId, PIXEL_FILL(6)); + AddTextPrinterParameterized3(gfx->optionDescWindowId, FONT_NORMAL, (192 - width) / 2, 1, sOptionDescTextColors, 0, desc); +} + +// Printed when Ribbons is selected if no PC/party mons have ribbons +// Can occur by obtaining a mon with a ribbon and then releasing all ribbon winners +static void PrintNoRibbonWinners(void) +{ + struct Pokenav_MenuGfx * gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MENU_GFX); + const u8 * s = gText_NoRibbonWinners; + u32 width = GetStringWidth(FONT_NORMAL, s, -1); + FillWindowPixelBuffer(gfx->optionDescWindowId, PIXEL_FILL(6)); + AddTextPrinterParameterized3(gfx->optionDescWindowId, FONT_NORMAL, (192 - width) / 2, 1, sOptionDescTextColors2, 0, s); +} + +static bool32 IsDma3ManagerBusyWithBgCopy_(void) +{ + return IsDma3ManagerBusyWithBgCopy(); +} + +static void CreateMovingBgDotsTask(void) +{ + struct Pokenav_MenuGfx * gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MENU_GFX); + gfx->bg3ScrollTaskId = CreateTask(Task_MoveBgDots, 2); +} + +static void DestroyMovingDotsBgTask(void) +{ + struct Pokenav_MenuGfx * gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MENU_GFX); + DestroyTask(gfx->bg3ScrollTaskId); +} + +static void Task_MoveBgDots(u8 taskId) +{ + ChangeBgX(3, 0x80, BG_COORD_ADD); +} + +static void CreateBgDotPurplePalTask(void) +{ + u8 taskId = CreateTask(Task_UpdateBgDotsPalette, 3); + SetWordTaskArg(taskId, 1, (uintptr_t)(sPokenavBgDotsPal + 1)); + SetWordTaskArg(taskId, 3, (uintptr_t)(sPokenavBgDotsPal + 7)); +} + +static void ChangeBgDotsColorToPurple(void) +{ + CopyPaletteIntoBufferUnfaded(sPokenavBgDotsPal + 7, 0x31, 4); +} + +static void CreateBgDotLightBluePalTask(void) +{ + u8 taskId = CreateTask(Task_UpdateBgDotsPalette, 3); + SetWordTaskArg(taskId, 1, (uintptr_t)(sPokenavBgDotsPal + 7)); + SetWordTaskArg(taskId, 3, (uintptr_t)(sPokenavBgDotsPal + 1)); +} + +static bool32 IsTaskActive_UpdateBgDotsPalette(void) +{ + return FuncIsActiveTask(Task_UpdateBgDotsPalette); +} + +static void Task_UpdateBgDotsPalette(u8 taskId) +{ + u16 sp8[2]; + s16 * data = gTasks[taskId].data; + const u16 * pal1 = (const u16 *)GetWordTaskArg(taskId, 1); + const u16 * pal2 = (const u16 *)GetWordTaskArg(taskId, 3); + + PokenavCopyPalette(pal1, pal2, 2, 12, ++data[0], sp8); + LoadPalette(sp8, 0x31, 4); + if (data[0] == 12) + DestroyTask(taskId); +} + +static void VBlankCB_PokenavMainMenu(void) +{ + TransferPlttBuffer(); + LoadOam(); + ProcessSpriteCopyRequests(); + ScanlineEffect_InitHBlankDmaTransfer(); +} + +static void SetupPokenavMenuScanlineEffects(void) +{ + SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_OBJ | BLDCNT_EFFECT_LIGHTEN); + SetGpuReg(REG_OFFSET_BLDY, 0); + SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_WIN0_ON); + SetGpuRegBits(REG_OFFSET_WININ, WININ_WIN0_ALL); + SetGpuRegBits(REG_OFFSET_WINOUT, WINOUT_WIN01_BG_ALL | WINOUT_WIN01_OBJ); + SetGpuRegBits(REG_OFFSET_WIN0V, DISPLAY_HEIGHT); + ScanlineEffect_Stop(); + SetMenuOptionGlow(); + ScanlineEffect_SetParams(sPokenavMainMenuScanlineEffectParams); + SetVBlankCallback_(VBlankCB_PokenavMainMenu); + CreateTask(Task_CurrentMenuOptionGlow, 3); +} + +static void DestroyMenuOptionGlowTask(void) +{ + SetGpuReg(REG_OFFSET_BLDCNT, 0); + ClearGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_WIN0_ON); + ScanlineEffect_Stop(); + DestroyTask(FindTaskIdByFunc(Task_CurrentMenuOptionGlow)); + SetPokenavVBlankCallback(); +} + +static void ResetBldCnt(void) +{ + SetGpuReg(REG_OFFSET_BLDCNT, 0); +} + +static void InitMenuOptionGlow(void) +{ + SetMenuOptionGlow(); + SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_OBJ | BLDCNT_EFFECT_LIGHTEN); +} + +static void Task_CurrentMenuOptionGlow(u8 taskId) +{ + s16 * data = gTasks[taskId].data; + data[0]++; + if (data[0] > 0) + { + data[0] = 0; + data[1] += 3; + data[1] &= 0x7F; + SetGpuReg(REG_OFFSET_BLDY, gSineTable[data[1]] >> 5); + } +} + +static void SetMenuOptionGlow(void) +{ + int menuType = GetPokenavMenuType(); + int cursorPos = GetPokenavCursorPos(); + int r4 = sPokenavMenuOptionLabelGfx[menuType].deltaY * cursorPos + sPokenavMenuOptionLabelGfx[menuType].yStart - 8; + CpuFill16(0, gScanlineEffectRegBuffers[0], DISPLAY_HEIGHT * 2); + CpuFill16(0, gScanlineEffectRegBuffers[1], DISPLAY_HEIGHT * 2); + CpuFill16(RGB(16, 23, 28), &gScanlineEffectRegBuffers[0][r4], 0x20); + CpuFill16(RGB(16, 23, 28), &gScanlineEffectRegBuffers[1][r4], 0x20); +} + +void ResetBldCnt_(void) +{ + ResetBldCnt(); +} |