diff options
Diffstat (limited to 'src/pokenav_match_call_gfx.c')
-rwxr-xr-x | src/pokenav_match_call_gfx.c | 1301 |
1 files changed, 1301 insertions, 0 deletions
diff --git a/src/pokenav_match_call_gfx.c b/src/pokenav_match_call_gfx.c new file mode 100755 index 000000000..056ab2f1d --- /dev/null +++ b/src/pokenav_match_call_gfx.c @@ -0,0 +1,1301 @@ +#include "global.h" +#include "bg.h" +#include "data.h" +#include "decompress.h" +#include "dma3.h" +#include "international_string_util.h" +#include "main.h" +#include "match_call.h" +#include "menu.h" +#include "overworld.h" +#include "palette.h" +#include "pokenav.h" +#include "region_map.h" +#include "sound.h" +#include "sprite.h" +#include "string_util.h" +#include "strings.h" +#include "task.h" +#include "text.h" +#include "text_window.h" +#include "trig.h" +#include "window.h" +#include "constants/game_stat.h" +#include "constants/region_map_sections.h" +#include "constants/songs.h" + +#define GFXTAG_CURSOR 7 +#define GFXTAG_TRAINER_PIC 8 +#define PALTAG_CURSOR 12 +#define PALTAG_TRAINER_PIC 13 + +struct Pokenav_MatchCallGfx +{ + bool32 (*isTaskActiveCB)(void); + u32 loopTaskId; + u8 filler8[6]; + bool8 skipHangUpSE; + bool8 newRematchRequest; + u16 locWindowId; + u16 infoBoxWindowId; + u16 msgBoxWindowId; + s16 pageDelta; + u8 unused18; + u8 unused19; + u16 trainerPicPalOffset; + struct Sprite *optionsCursorSprite; + struct Sprite *trainerPicSprite; + u8 bgTilemapBuffer1[BG_SCREEN_SIZE]; + u8 unusedTilemapBuffer[BG_SCREEN_SIZE]; + u8 bgTilemapBuffer2[BG_SCREEN_SIZE]; + u8 *trainerPicGfxPtr; + u8 trainerPicGfx[0x800]; + u8 trainerPicPal[0x20]; +}; + +static bool32 GetCurrentLoopedTaskActive(void); +static u32 LoopedTask_OpenMatchCall(s32); +static void CreateMatchCallList(void); +static void DestroyMatchCallList(void); +static void FreeMatchCallSprites(void); +static void LoadCallWindowAndFade(struct Pokenav_MatchCallGfx *); +static void DrawMatchCallLeftColumnWindows(struct Pokenav_MatchCallGfx *); +static void UpdateMatchCallInfoBox(struct Pokenav_MatchCallGfx *); +static void PrintMatchCallLocation(struct Pokenav_MatchCallGfx *, int); +static void AllocMatchCallSprites(void); +static void SetPokeballIconsFlashing(bool32); +static void PrintMatchCallSelectionOptions(struct Pokenav_MatchCallGfx *); +static bool32 ShowOptionsCursor(struct Pokenav_MatchCallGfx *); +static void UpdateCursorGfxPos(struct Pokenav_MatchCallGfx *, int); +static bool32 IsDma3ManagerBusyWithBgCopy1(struct Pokenav_MatchCallGfx *); +static void UpdateWindowsReturnToTrainerList(struct Pokenav_MatchCallGfx *); +static void DrawMsgBoxForMatchCallMsg(struct Pokenav_MatchCallGfx *); +static bool32 IsDma3ManagerBusyWithBgCopy2(struct Pokenav_MatchCallGfx *); +static void PrintCallingDots(struct Pokenav_MatchCallGfx *); +static bool32 WaitForCallingDotsText(struct Pokenav_MatchCallGfx *); +static void PrintMatchCallMessage(struct Pokenav_MatchCallGfx *); +static bool32 WaitForMatchCallMessageText(struct Pokenav_MatchCallGfx *); +static void DrawMsgBoxForCloseByMsg(struct Pokenav_MatchCallGfx *); +static void PrintTrainerIsCloseBy(struct Pokenav_MatchCallGfx *); +static bool32 WaitForTrainerIsCloseByText(struct Pokenav_MatchCallGfx *); +static void EraseCallMessageBox(struct Pokenav_MatchCallGfx *); +static bool32 WaitForCallMessageBoxErase(struct Pokenav_MatchCallGfx *); +static void UpdateWindowsToShowCheckPage(struct Pokenav_MatchCallGfx *); +static void LoadCheckPageTrainerPic(struct Pokenav_MatchCallGfx *); +static bool32 WaitForTrainerPic(struct Pokenav_MatchCallGfx *); +static void TrainerPicSlideOffscreen(struct Pokenav_MatchCallGfx *); +static void Task_FlashPokeballIcons(u8); +static void TryDrawRematchPokeballIcon(u16, u32, u32); +static void PrintNumberRegisteredLabel(u16); +static void PrintNumberRegistered(u16); +static void PrintNumberOfBattlesLabel(u16); +static void PrintNumberOfBattles(u16); +static void PrintMatchCallInfoLabel(u16, const u8 *, int); +static void PrintMatchCallInfoNumber(u16, const u8 *, int); +static void CreateOptionsCursorSprite(struct Pokenav_MatchCallGfx *, int); +static void CloseMatchCallSelectOptionsWindow(struct Pokenav_MatchCallGfx *); +static struct Sprite *CreateTrainerPicSprite(void); +static void SpriteCB_TrainerPicSlideOnscreen(struct Sprite *); +static void SpriteCB_TrainerPicSlideOffscreen(struct Sprite *); +static void SpriteCB_OptionsCursor(struct Sprite *); +static u32 MatchCallListCursorDown(s32); +static u32 MatchCallListCursorUp(s32); +static u32 MatchCallListPageDown(s32); +static u32 MatchCallListPageUp(s32); +static u32 SelectMatchCallEntry(s32); +static u32 MoveMatchCallOptionsCursor(s32); +static u32 CancelMatchCallSelection(s32); +static u32 DoMatchCallMessage(s32); +static u32 DoTrainerCloseByMessage(s32); +static u32 CloseMatchCallMessage(s32); +static u32 ShowCheckPage(s32); +static u32 ShowCheckPageUp(s32); +static u32 ShowCheckPageDown(s32); +static u32 ExitCheckPage(s32); +static u32 ExitMatchCall(s32); + +static const u16 sMatchCallUI_Pal[] = INCBIN_U16("graphics/pokenav/match_call/ui.gbapal"); +static const u32 sMatchCallUI_Gfx[] = INCBIN_U32("graphics/pokenav/match_call/ui.4bpp.lz"); +static const u32 sMatchCallUI_Tilemap[] = INCBIN_U32("graphics/pokenav/match_call/ui.bin.lz"); +static const u16 sOptionsCursor_Pal[] = INCBIN_U16("graphics/pokenav/match_call/options_cursor.gbapal"); +static const u32 sOptionsCursor_Gfx[] = INCBIN_U32("graphics/pokenav/match_call/options_cursor.4bpp.lz"); +static const u16 sCallWindow_Pal[] = INCBIN_U16("graphics/pokenav/match_call/call_window.gbapal"); +static const u16 sListWindow_Pal[] = INCBIN_U16("graphics/pokenav/match_call/list_window.gbapal"); +static const u16 sPokeball_Pal[] = INCBIN_U16("graphics/pokenav/match_call/pokeball.gbapal"); +static const u32 sPokeball_Gfx[] = INCBIN_U32("graphics/pokenav/match_call/pokeball.4bpp.lz"); + +static const struct BgTemplate sMatchCallBgTemplates[3] = +{ + { + .bg = 1, + .charBaseIndex = 3, + .mapBaseIndex = 0x1F, + .screenSize = 0, + .paletteMode = 0, + .priority = 1, + .baseTile = 0 + }, + { + .bg = 2, + .charBaseIndex = 2, + .mapBaseIndex = 0x06, + .screenSize = 0, + .paletteMode = 0, + .priority = 2, + .baseTile = 0x80 + }, + { + .bg = 3, + .charBaseIndex = 1, + .mapBaseIndex = 0x07, + .screenSize = 0, + .paletteMode = 0, + .priority = 3, + .baseTile = 0 + } +}; + +static const LoopedTask sMatchCallLoopTaskFuncs[] = +{ + [POKENAV_MC_FUNC_NONE] = NULL, + [POKENAV_MC_FUNC_DOWN] = MatchCallListCursorDown, + [POKENAV_MC_FUNC_UP] = MatchCallListCursorUp, + [POKENAV_MC_FUNC_PG_DOWN] = MatchCallListPageDown, + [POKENAV_MC_FUNC_PG_UP] = MatchCallListPageUp, + [POKENAV_MC_FUNC_SELECT] = SelectMatchCallEntry, + [POKENAV_MC_FUNC_MOVE_OPTIONS_CURSOR] = MoveMatchCallOptionsCursor, + [POKENAV_MC_FUNC_CANCEL] = CancelMatchCallSelection, + [POKENAV_MC_FUNC_CALL_MSG] = DoMatchCallMessage, + [POKENAV_MC_FUNC_NEARBY_MSG] = DoTrainerCloseByMessage, + [POKENAV_MC_FUNC_EXIT_CALL] = CloseMatchCallMessage, + [POKENAV_MC_FUNC_SHOW_CHECK_PAGE] = ShowCheckPage, + [POKENAV_MC_FUNC_CHECK_PAGE_UP] = ShowCheckPageUp, + [POKENAV_MC_FUNC_CHECK_PAGE_DOWN] = ShowCheckPageDown, + [POKENAV_MC_FUNC_EXIT_CHECK_PAGE] = ExitCheckPage, + [POKENAV_MC_FUNC_EXIT] = ExitMatchCall +}; + +static const struct WindowTemplate sMatchCallLocationWindowTemplate = +{ + .bg = 2, + .tilemapLeft = 0, + .tilemapTop = 5, + .width = 11, + .height = 2, + .paletteNum = 2, + .baseBlock = 16 +}; + +static const struct WindowTemplate sMatchCallInfoBoxWindowTemplate = +{ + .bg = 2, + .tilemapLeft = 0, + .tilemapTop = 9, + .width = 11, + .height = 8, + .paletteNum = 2, + .baseBlock = 38 +}; + +static const u8 *const sMatchCallOptionTexts[MATCH_CALL_OPTION_COUNT] = +{ + [MATCH_CALL_OPTION_CALL] = gText_Call, + [MATCH_CALL_OPTION_CHECK] = gText_Check, + [MATCH_CALL_OPTION_CANCEL] = gText_Cancel6 +}; + +// The series of 5 dots that appear when someone is called with Match Call +static const u8 sText_CallingDots[] = _("·{PAUSE 4}·{PAUSE 4}·{PAUSE 4}·{PAUSE 4}·\p"); + +static const struct WindowTemplate sCallMsgBoxWindowTemplate = +{ + .bg = 1, + .tilemapLeft = 1, + .tilemapTop = 12, + .width = 28, + .height = 4, + .paletteNum = 1, + .baseBlock = 10 +}; + +static const struct CompressedSpriteSheet sOptionsCursorSpriteSheets[1] = +{ + {sOptionsCursor_Gfx, 0x40, GFXTAG_CURSOR} +}; + +static const struct SpritePalette sOptionsCursorSpritePalettes[2] = +{ + {sOptionsCursor_Pal, PALTAG_CURSOR} +}; + +static const struct OamData sOptionsCursorOamData = +{ + .y = 0, + .affineMode = ST_OAM_AFFINE_OFF, + .objMode = ST_OAM_OBJ_NORMAL, + .bpp = ST_OAM_4BPP, + .shape = SPRITE_SHAPE(8x16), + .x = 0, + .size = SPRITE_SIZE(8x16), + .tileNum = 0, + .priority = 1, + .paletteNum = 0, +}; + +static const struct SpriteTemplate sOptionsCursorSpriteTemplate = +{ + .tileTag = GFXTAG_CURSOR, + .paletteTag = PALTAG_CURSOR, + .oam = &sOptionsCursorOamData, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCB_OptionsCursor, +}; + +static const struct OamData sTrainerPicOamData = +{ + .y = 0, + .affineMode = ST_OAM_AFFINE_OFF, + .objMode = ST_OAM_OBJ_NORMAL, + .bpp = ST_OAM_4BPP, + .shape = SPRITE_SHAPE(64x64), + .x = 0, + .size = SPRITE_SIZE(64x64), + .tileNum = 0, + .priority = 1, + .paletteNum = 0, +}; + +static const struct SpriteTemplate sTrainerPicSpriteTemplate = +{ + .tileTag = GFXTAG_TRAINER_PIC, + .paletteTag = PALTAG_TRAINER_PIC, + .oam = &sTrainerPicOamData, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCallbackDummy, +}; + +bool32 OpenMatchCall(void) +{ + struct Pokenav_MatchCallGfx *gfx = AllocSubstruct(POKENAV_SUBSTRUCT_MATCH_CALL_OPEN, sizeof(struct Pokenav_MatchCallGfx)); + if (!gfx) + return FALSE; + + gfx->unused19 = 0; + gfx->loopTaskId = CreateLoopedTask(LoopedTask_OpenMatchCall, 1); + gfx->isTaskActiveCB = GetCurrentLoopedTaskActive; + return TRUE; +} + +void CreateMatchCallLoopedTask(s32 index) +{ + struct Pokenav_MatchCallGfx *gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MATCH_CALL_OPEN); + gfx->loopTaskId = CreateLoopedTask(sMatchCallLoopTaskFuncs[index], 1); + gfx->isTaskActiveCB = GetCurrentLoopedTaskActive; +} + +bool32 IsMatchCallLoopedTaskActive(void) +{ + struct Pokenav_MatchCallGfx *gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MATCH_CALL_OPEN); + return gfx->isTaskActiveCB(); +} + +void FreeMatchCallSubstruct2(void) +{ + struct Pokenav_MatchCallGfx *gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MATCH_CALL_OPEN); + FreeMatchCallSprites(); + DestroyMatchCallList(); + RemoveWindow(gfx->infoBoxWindowId); + RemoveWindow(gfx->locWindowId); + RemoveWindow(gfx->msgBoxWindowId); + FreePokenavSubstruct(POKENAV_SUBSTRUCT_MATCH_CALL_OPEN); +} + +static bool32 GetCurrentLoopedTaskActive(void) +{ + struct Pokenav_MatchCallGfx *gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MATCH_CALL_OPEN); + return IsLoopedTaskActive(gfx->loopTaskId); +} + +static u32 LoopedTask_OpenMatchCall(s32 state) +{ + struct Pokenav_MatchCallGfx *gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MATCH_CALL_OPEN); + switch (state) + { + case 0: + InitBgTemplates(sMatchCallBgTemplates, ARRAY_COUNT(sMatchCallBgTemplates)); + ChangeBgX(2, 0, BG_COORD_SET); + ChangeBgY(2, 0, BG_COORD_SET); + DecompressAndCopyTileDataToVram(2, sMatchCallUI_Gfx, 0, 0, 0); + SetBgTilemapBuffer(2, gfx->bgTilemapBuffer2); + CopyToBgTilemapBuffer(2, sMatchCallUI_Tilemap, 0, 0); + CopyBgTilemapBufferToVram(2); + CopyPaletteIntoBufferUnfaded(sMatchCallUI_Pal, 0x20, 0x20); + CopyBgTilemapBufferToVram(2); + return LT_INC_AND_PAUSE; + case 1: + if (FreeTempTileDataBuffersIfPossible()) + return LT_PAUSE; + + BgDmaFill(1, 0, 0, 1); + SetBgTilemapBuffer(1, gfx->bgTilemapBuffer1); + FillBgTilemapBufferRect_Palette0(1, 0x1000, 0, 0, 32, 20); + CopyPaletteIntoBufferUnfaded(sCallWindow_Pal, 0x10, 0x20); + CopyBgTilemapBufferToVram(1); + return LT_INC_AND_PAUSE; + case 2: + if (FreeTempTileDataBuffersIfPossible()) + return LT_PAUSE; + + LoadCallWindowAndFade(gfx); + DecompressAndCopyTileDataToVram(3, sPokeball_Gfx, 0, 0, 0); + CopyPaletteIntoBufferUnfaded(sListWindow_Pal, 0x30, 0x20); + CopyPaletteIntoBufferUnfaded(sPokeball_Pal, 0x50, 0x20); + return LT_INC_AND_PAUSE; + case 3: + if (FreeTempTileDataBuffersIfPossible() || !IsMatchCallListInitFinished()) + return LT_PAUSE; + + CreateMatchCallList(); + return LT_INC_AND_PAUSE; + case 4: + if (IsCreatePokenavListTaskActive()) + return LT_PAUSE; + + DrawMatchCallLeftColumnWindows(gfx); + return LT_INC_AND_PAUSE; + case 5: + UpdateMatchCallInfoBox(gfx); + PrintMatchCallLocation(gfx, 0); + return LT_INC_AND_PAUSE; + case 6: + ChangeBgX(1, 0, BG_COORD_SET); + ChangeBgY(1, 0, BG_COORD_SET); + ShowBg(2); + ShowBg(3); + ShowBg(1); + AllocMatchCallSprites(); + LoadLeftHeaderGfxForIndex(3); + ShowLeftHeaderGfx(POKENAV_GFX_MATCH_CALL_MENU, 1, 0); + PokenavFadeScreen(POKENAV_FADE_FROM_BLACK); + return LT_INC_AND_PAUSE; + case 7: + if (IsPaletteFadeActive() || AreLeftHeaderSpritesMoving()) + return LT_PAUSE; + + SetPokeballIconsFlashing(TRUE); + return LT_FINISH; + default: + return LT_FINISH; + } +} + +static u32 MatchCallListCursorDown(s32 state) +{ + struct Pokenav_MatchCallGfx *gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MATCH_CALL_OPEN); + switch (state) + { + case 0: + switch (PokenavList_MoveCursorDown()) + { + case 0: + break; + case 1: + PlaySE(SE_SELECT); + return LT_SET_STATE(2); + case 2: + PlaySE(SE_SELECT); + // fall through + default: + return LT_INC_AND_PAUSE; + } + break; + case 1: + if (PokenavList_IsMoveWindowTaskActive()) + return LT_PAUSE; + + PrintMatchCallLocation(gfx, 0); + return LT_INC_AND_PAUSE; + case 2: + PrintMatchCallLocation(gfx, 0); + return LT_INC_AND_PAUSE; + case 3: + if (IsDma3ManagerBusyWithBgCopy()) + return LT_PAUSE; + break; + } + return LT_FINISH; +} + +static u32 MatchCallListCursorUp(s32 state) +{ + struct Pokenav_MatchCallGfx *gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MATCH_CALL_OPEN); + switch (state) + { + case 0: + switch (PokenavList_MoveCursorUp()) + { + case 0: + break; + case 1: + PlaySE(SE_SELECT); + return LT_SET_STATE(2); + case 2: + PlaySE(SE_SELECT); + // fall through + default: + return LT_INC_AND_PAUSE; + } + break; + case 1: + if (PokenavList_IsMoveWindowTaskActive()) + return LT_PAUSE; + + PrintMatchCallLocation(gfx, 0); + return LT_INC_AND_PAUSE; + case 2: + PrintMatchCallLocation(gfx, 0); + return LT_INC_AND_PAUSE; + case 3: + if (IsDma3ManagerBusyWithBgCopy()) + return LT_PAUSE; + break; + } + return LT_FINISH; +} + +static u32 MatchCallListPageDown(s32 state) +{ + struct Pokenav_MatchCallGfx *gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MATCH_CALL_OPEN); + switch (state) + { + case 0: + switch (PokenavList_PageDown()) + { + case 0: + break; + case 1: + PlaySE(SE_SELECT); + return LT_SET_STATE(2); + case 2: + PlaySE(SE_SELECT); + // fall through + default: + return LT_INC_AND_PAUSE; + } + break; + case 1: + if (PokenavList_IsMoveWindowTaskActive()) + return LT_PAUSE; + + PrintMatchCallLocation(gfx, 0); + return LT_INC_AND_PAUSE; + case 2: + PrintMatchCallLocation(gfx, 0); + return LT_INC_AND_PAUSE; + case 3: + if (IsDma3ManagerBusyWithBgCopy()) + return LT_PAUSE; + break; + } + return LT_FINISH; +} + +static u32 MatchCallListPageUp(s32 state) +{ + struct Pokenav_MatchCallGfx *gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MATCH_CALL_OPEN); + switch (state) + { + case 0: + switch (PokenavList_PageUp()) + { + case 0: + break; + case 1: + PlaySE(SE_SELECT); + return LT_SET_STATE(2); + case 2: + PlaySE(SE_SELECT); + // fall through + default: + return LT_INC_AND_PAUSE; + } + break; + case 1: + if (PokenavList_IsMoveWindowTaskActive()) + return LT_PAUSE; + + PrintMatchCallLocation(gfx, 0); + return LT_INC_AND_PAUSE; + case 2: + PrintMatchCallLocation(gfx, 0); + return LT_INC_AND_PAUSE; + case 3: + if (IsDma3ManagerBusyWithBgCopy()) + return LT_PAUSE; + break; + } + return LT_FINISH; +} + +static u32 SelectMatchCallEntry(s32 state) +{ + struct Pokenav_MatchCallGfx *gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MATCH_CALL_OPEN); + switch (state) + { + case 0: + PlaySE(SE_SELECT); + PrintMatchCallSelectionOptions(gfx); + PrintHelpBarText(HELPBAR_MC_CALL_MENU); + return LT_INC_AND_PAUSE; + case 1: + if (ShowOptionsCursor(gfx)) + return LT_PAUSE; + break; + } + + return LT_FINISH; +} + +static u32 MoveMatchCallOptionsCursor(s32 state) +{ + struct Pokenav_MatchCallGfx *gfx; + u16 cursorPos; + + PlaySE(SE_SELECT); + gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MATCH_CALL_OPEN); + cursorPos = GetMatchCallOptionCursorPos(); + UpdateCursorGfxPos(gfx, cursorPos); + return LT_FINISH; +} + +static u32 CancelMatchCallSelection(s32 state) +{ + struct Pokenav_MatchCallGfx *gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MATCH_CALL_OPEN); + switch (state) + { + case 0: + PlaySE(SE_SELECT); + UpdateWindowsReturnToTrainerList(gfx); + PrintHelpBarText(HELPBAR_MC_TRAINER_LIST); + return LT_INC_AND_PAUSE; + case 1: + if (IsDma3ManagerBusyWithBgCopy1(gfx)) + return LT_PAUSE; + break; + } + + return LT_FINISH; +} + +static u32 DoMatchCallMessage(s32 state) +{ + struct Pokenav_MatchCallGfx *gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MATCH_CALL_OPEN); + switch (state) + { + case 0: + PokenavList_ToggleVerticalArrows(TRUE); + DrawMsgBoxForMatchCallMsg(gfx); + return LT_INC_AND_PAUSE; + case 1: + if (IsDma3ManagerBusyWithBgCopy2(gfx)) + return LT_PAUSE; + + PrintCallingDots(gfx); + PlaySE(SE_POKENAV_CALL); + gfx->skipHangUpSE = FALSE; + return LT_INC_AND_PAUSE; + case 2: + if (WaitForCallingDotsText(gfx)) + return LT_PAUSE; + + PrintMatchCallMessage(gfx); + return LT_INC_AND_PAUSE; + case 3: + if (WaitForMatchCallMessageText(gfx)) + return LT_PAUSE; + break; + } + + return LT_FINISH; +} + +static u32 DoTrainerCloseByMessage(s32 state) +{ + struct Pokenav_MatchCallGfx *gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MATCH_CALL_OPEN); + switch (state) + { + case 0: + PlaySE(SE_SELECT); + DrawMsgBoxForCloseByMsg(gfx); + PokenavList_ToggleVerticalArrows(TRUE); + gfx->skipHangUpSE = TRUE; + return LT_INC_AND_PAUSE; + case 1: + if (IsDma3ManagerBusyWithBgCopy2(gfx)) + return LT_PAUSE; + + PrintTrainerIsCloseBy(gfx); + return LT_INC_AND_PAUSE; + case 2: + if (WaitForTrainerIsCloseByText(gfx)) + return LT_PAUSE; + break; + } + + return LT_FINISH; +} + +static u32 CloseMatchCallMessage(s32 state) +{ + struct Pokenav_MatchCallGfx *gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MATCH_CALL_OPEN); + u32 result = LT_INC_AND_PAUSE; + + switch (state) + { + case 0: + if (!gfx->skipHangUpSE) + PlaySE(SE_POKENAV_HANG_UP); + + PlaySE(SE_SELECT); + break; + case 1: + EraseCallMessageBox(gfx); + break; + case 2: + if (WaitForCallMessageBoxErase(gfx)) + result = LT_PAUSE; + break; + case 3: + UpdateWindowsReturnToTrainerList(gfx); + break; + case 4: + if (IsDma3ManagerBusyWithBgCopy1(gfx)) + result = LT_PAUSE; + + PrintHelpBarText(HELPBAR_MC_TRAINER_LIST); + break; + case 5: + if (WaitForHelpBar()) + { + result = LT_PAUSE; + } + else + { + if (gfx->newRematchRequest) + { + // This call was a new rematch request, + // add the Pokéball icon to their entry + PokenavList_DrawCurrentItemIcon(); + result = LT_INC_AND_CONTINUE; + } + else + { + PokenavList_ToggleVerticalArrows(FALSE); + result = LT_FINISH; + } + } + break; + case 6: + if (IsDma3ManagerBusyWithBgCopy()) + { + result = LT_PAUSE; + } + else + { + PokenavList_ToggleVerticalArrows(FALSE); + result = LT_FINISH; + } + break; + } + + return result; +} + +static u32 ShowCheckPage(s32 state) +{ + struct Pokenav_MatchCallGfx *gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MATCH_CALL_OPEN); + switch (state) + { + case 0: + PlaySE(SE_SELECT); + PokenavList_EraseListForCheckPage(); + UpdateWindowsToShowCheckPage(gfx); + return LT_INC_AND_PAUSE; + case 1: + if (PokenavList_IsTaskActive() || IsDma3ManagerBusyWithBgCopy1(gfx)) + return LT_PAUSE; + + PrintHelpBarText(HELPBAR_MC_CHECK_PAGE); + return LT_INC_AND_PAUSE; + case 2: + PrintCheckPageInfo(0); + LoadCheckPageTrainerPic(gfx); + return LT_INC_AND_PAUSE; + case 3: + if (PokenavList_IsTaskActive() || WaitForTrainerPic(gfx) || WaitForHelpBar()) + return LT_PAUSE; + break; + } + + return LT_FINISH; +} + +static u32 ShowCheckPageDown(s32 state) +{ + int topId; + int delta; + struct Pokenav_MatchCallGfx *gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MATCH_CALL_OPEN); + switch (state) + { + case 0: + topId = PokenavList_GetTopIndex(); + delta = GetIndexDeltaOfNextCheckPageDown(topId); + if (delta) + { + PlaySE(SE_SELECT); + gfx->pageDelta = delta; + TrainerPicSlideOffscreen(gfx); + return LT_INC_AND_PAUSE; + } + break; + case 1: + if (WaitForTrainerPic(gfx)) + return LT_PAUSE; + + PrintMatchCallLocation(gfx, gfx->pageDelta); + return LT_INC_AND_PAUSE; + case 2: + PrintCheckPageInfo(gfx->pageDelta); + return LT_INC_AND_PAUSE; + case 3: + LoadCheckPageTrainerPic(gfx); + return LT_INC_AND_PAUSE; + case 4: + if (PokenavList_IsTaskActive() || WaitForTrainerPic(gfx)) + return LT_PAUSE; + break; + } + + return LT_FINISH; +} + +static u32 ExitCheckPage(s32 state) +{ + struct Pokenav_MatchCallGfx *gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MATCH_CALL_OPEN); + switch (state) + { + case 0: + PlaySE(SE_SELECT); + TrainerPicSlideOffscreen(gfx); + PokenavList_ReshowListFromCheckPage(); + return LT_INC_AND_PAUSE; + case 1: + if (PokenavList_IsTaskActive() || WaitForTrainerPic(gfx)) + return LT_PAUSE; + + PrintHelpBarText(HELPBAR_MC_TRAINER_LIST); + UpdateMatchCallInfoBox(gfx); + return LT_INC_AND_PAUSE; + case 2: + if (IsDma3ManagerBusyWithBgCopy()) + return LT_PAUSE; + break; + } + + return LT_FINISH; +} + +static u32 ShowCheckPageUp(s32 state) +{ + int topId; + int delta; + struct Pokenav_MatchCallGfx *gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MATCH_CALL_OPEN); + switch (state) + { + case 0: + topId = PokenavList_GetTopIndex(); + delta = GetIndexDeltaOfNextCheckPageUp(topId); + if (delta) + { + PlaySE(SE_SELECT); + gfx->pageDelta = delta; + TrainerPicSlideOffscreen(gfx); + return LT_INC_AND_PAUSE; + } + break; + case 1: + if (WaitForTrainerPic(gfx)) + return LT_PAUSE; + + PrintMatchCallLocation(gfx, gfx->pageDelta); + return LT_INC_AND_PAUSE; + case 2: + PrintCheckPageInfo(gfx->pageDelta); + return LT_INC_AND_PAUSE; + case 3: + LoadCheckPageTrainerPic(gfx); + return LT_INC_AND_PAUSE; + case 4: + if (PokenavList_IsTaskActive() || WaitForTrainerPic(gfx)) + return LT_PAUSE; + break; + } + + return LT_FINISH; +} + +static u32 ExitMatchCall(s32 state) +{ + switch (state) + { + case 0: + PlaySE(SE_SELECT); + SetPokeballIconsFlashing(FALSE); + PokenavFadeScreen(POKENAV_FADE_TO_BLACK); + SlideMenuHeaderDown(); + return LT_INC_AND_PAUSE; + case 1: + if (IsPaletteFadeActive() || MainMenuLoopedTaskIsBusy()) + return LT_PAUSE; + + SetLeftHeaderSpritesInvisibility(); + break; + } + + return LT_FINISH; +} + +static void CreateMatchCallList(void) +{ + struct PokenavListTemplate template; + template.list = (struct PokenavListItem *)GetMatchCallList(); + template.count = GetNumberRegistered(); + template.itemSize = sizeof(struct PokenavListItem); + template.startIndex = 0; + template.item_X = 13; + template.windowWidth = 16; + template.listTop = 1; + template.maxShowed = 8; + template.fillValue = 3; + template.fontId = FONT_NARROW; + template.bufferItemFunc = (PokenavListBufferItemFunc)BufferMatchCallNameAndDesc; + template.iconDrawFunc = TryDrawRematchPokeballIcon; + CreatePokenavList(&sMatchCallBgTemplates[2], &template, 2); + CreateTask(Task_FlashPokeballIcons, 7); +} + +static void DestroyMatchCallList(void) +{ + DestroyPokenavList(); + DestroyTask(FindTaskIdByFunc(Task_FlashPokeballIcons)); +} + +#define tSinIdx data[0] +#define tSinVal data[1] +#define tActive data[15] + +static void SetPokeballIconsFlashing(bool32 active) +{ + u8 taskId = FindTaskIdByFunc(Task_FlashPokeballIcons); + if (taskId != TASK_NONE) + gTasks[taskId].tActive = active; +} + +static void Task_FlashPokeballIcons(u8 taskId) +{ + s16 *data = gTasks[taskId].data; + if (tActive) + { + tSinIdx += 4; + tSinIdx &= 0x7F; + tSinVal = gSineTable[tSinIdx] >> 4; + PokenavCopyPalette(sPokeball_Pal, &sPokeball_Pal[0x10], 0x10, 0x10, tSinVal, &gPlttBufferUnfaded[0x50]); + if (!gPaletteFade.active) + CpuCopy32(&gPlttBufferUnfaded[0x50], &gPlttBufferFaded[0x50], 0x20); + } +} + +#undef tSinIdx +#undef tSinVal +#undef tActive + +enum { + POKEBALL_ICON_TOP = 0x5000, + POKEBALL_ICON_BOTTOM, + POKEBALL_ICON_EMPTY, +}; + +static void TryDrawRematchPokeballIcon(u16 windowId, u32 rematchId, u32 tileOffset) +{ + u8 bg = GetWindowAttribute(windowId, WINDOW_BG); + u16 *tilemap = GetBgTilemapBuffer(bg); + tilemap += tileOffset * 64 + 0x1D; + if (ShouldDrawRematchPokeballIcon(rematchId)) + { + tilemap[0] = POKEBALL_ICON_TOP; + tilemap[0x20] = POKEBALL_ICON_BOTTOM; + } + else + { + tilemap[0] = POKEBALL_ICON_EMPTY; + tilemap[0x20] = POKEBALL_ICON_EMPTY; + } +} + +void ClearRematchPokeballIcon(u16 windowId, u32 tileOffset) +{ + u8 bg = GetWindowAttribute(windowId, WINDOW_BG); + u16 *tilemap = GetBgTilemapBuffer(bg); + tilemap += tileOffset * 64 + 0x1D; + tilemap[0] = POKEBALL_ICON_EMPTY; + tilemap[0x20] = POKEBALL_ICON_EMPTY; +} + +static void DrawMatchCallLeftColumnWindows(struct Pokenav_MatchCallGfx *gfx) +{ + gfx->locWindowId = AddWindow(&sMatchCallLocationWindowTemplate); + gfx->infoBoxWindowId = AddWindow(&sMatchCallInfoBoxWindowTemplate); + FillWindowPixelBuffer(gfx->locWindowId, PIXEL_FILL(1)); + PutWindowTilemap(gfx->locWindowId); + FillWindowPixelBuffer(gfx->infoBoxWindowId, PIXEL_FILL(1)); + PutWindowTilemap(gfx->infoBoxWindowId); + CopyWindowToVram(gfx->locWindowId, COPYWIN_MAP); +} + +static void UpdateMatchCallInfoBox(struct Pokenav_MatchCallGfx *gfx) +{ + FillWindowPixelBuffer(gfx->infoBoxWindowId, PIXEL_FILL(1)); + PrintNumberRegisteredLabel(gfx->infoBoxWindowId); + PrintNumberRegistered(gfx->infoBoxWindowId); + PrintNumberOfBattlesLabel(gfx->infoBoxWindowId); + PrintNumberOfBattles(gfx->infoBoxWindowId); + CopyWindowToVram(gfx->infoBoxWindowId, COPYWIN_GFX); +} + +static void PrintNumberRegisteredLabel(u16 windowId) +{ + PrintMatchCallInfoLabel(windowId, gText_NumberRegistered, 0); +} + +static void PrintNumberRegistered(u16 windowId) +{ + u8 str[3]; + ConvertIntToDecimalStringN(str, GetNumberRegistered(), STR_CONV_MODE_LEFT_ALIGN, 3); + PrintMatchCallInfoNumber(windowId, str, 1); +} + +static void PrintNumberOfBattlesLabel(u16 windowId) +{ + PrintMatchCallInfoLabel(windowId, gText_NumberOfBattles, 2); +} + +static void PrintNumberOfBattles(u16 windowId) +{ + u8 str[5]; + int numTrainerBattles = GetGameStat(GAME_STAT_TRAINER_BATTLES); + if (numTrainerBattles > 99999) + numTrainerBattles = 99999; + + ConvertIntToDecimalStringN(str, numTrainerBattles, STR_CONV_MODE_LEFT_ALIGN, 5); + PrintMatchCallInfoNumber(windowId, str, 3); +} + +static void PrintMatchCallInfoLabel(u16 windowId, const u8 *str, int top) +{ + int y = top * 16 + 1; + AddTextPrinterParameterized(windowId, FONT_NARROW, str, 2, y, TEXT_SKIP_DRAW, NULL); +} + +static void PrintMatchCallInfoNumber(u16 windowId, const u8 *str, int top) +{ + int x = GetStringRightAlignXOffset(FONT_NARROW, str, 86); + int y = top * 16 + 1; + AddTextPrinterParameterized(windowId, FONT_NARROW, str, x, y, TEXT_SKIP_DRAW, NULL); +} + +static void PrintMatchCallLocation(struct Pokenav_MatchCallGfx *gfx, int delta) +{ + u8 mapName[32]; + int x; + int index = PokenavList_GetSelectedIndex() + delta; + int mapSec = GetMatchCallMapSec(index); + if (mapSec != MAPSEC_NONE) + GetMapName(mapName, mapSec, 0); + else + StringCopy(mapName, gText_Unknown); + + x = GetStringCenterAlignXOffset(FONT_NARROW, mapName, 88); + FillWindowPixelBuffer(gfx->locWindowId, PIXEL_FILL(1)); + AddTextPrinterParameterized(gfx->locWindowId, FONT_NARROW, mapName, x, 1, 0, NULL); +} + +static void PrintMatchCallSelectionOptions(struct Pokenav_MatchCallGfx *gfx) +{ + u32 i; + + FillWindowPixelBuffer(gfx->infoBoxWindowId, PIXEL_FILL(1)); + for (i = 0; i < MATCH_CALL_OPTION_COUNT; i++) + { + int optionText = GetMatchCallOptionId(i); + if (optionText == MATCH_CALL_OPTION_COUNT) + break; + + AddTextPrinterParameterized(gfx->infoBoxWindowId, FONT_NARROW, sMatchCallOptionTexts[optionText], 16, i * 16 + 1, TEXT_SKIP_DRAW, NULL); + } + + CopyWindowToVram(gfx->infoBoxWindowId, COPYWIN_GFX); +} + +static bool32 ShowOptionsCursor(struct Pokenav_MatchCallGfx *gfx) +{ + if (!IsDma3ManagerBusyWithBgCopy()) + { + CreateOptionsCursorSprite(gfx, GetMatchCallOptionCursorPos()); + return FALSE; + } + + return TRUE; +} + +static void UpdateWindowsReturnToTrainerList(struct Pokenav_MatchCallGfx *gfx) +{ + CloseMatchCallSelectOptionsWindow(gfx); + UpdateMatchCallInfoBox(gfx); +} + +static bool32 IsDma3ManagerBusyWithBgCopy1(struct Pokenav_MatchCallGfx *gfx) +{ + return IsDma3ManagerBusyWithBgCopy(); +} + +static void UpdateWindowsToShowCheckPage(struct Pokenav_MatchCallGfx *gfx) +{ + CloseMatchCallSelectOptionsWindow(gfx); + FillWindowPixelBuffer(gfx->infoBoxWindowId, PIXEL_FILL(1)); + CopyWindowToVram(gfx->infoBoxWindowId, COPYWIN_GFX); +} + +static void LoadCallWindowAndFade(struct Pokenav_MatchCallGfx *gfx) +{ + gfx->msgBoxWindowId = AddWindow(&sCallMsgBoxWindowTemplate); + LoadMatchCallWindowGfx(gfx->msgBoxWindowId, 1, 4); + FadeToBlackExceptPrimary(); +} + +static void DrawMsgBoxForMatchCallMsg(struct Pokenav_MatchCallGfx *gfx) +{ + struct Sprite *sprite; + LoadMatchCallWindowGfx(gfx->msgBoxWindowId, 1, 4); + DrawMatchCallTextBoxBorder(gfx->msgBoxWindowId, 1, 4); + FillWindowPixelBuffer(gfx->msgBoxWindowId, PIXEL_FILL(1)); + PutWindowTilemap(gfx->msgBoxWindowId); + CopyWindowToVram(gfx->msgBoxWindowId, COPYWIN_FULL); + sprite = GetSpinningPokenavSprite(); + sprite->x = 24; + sprite->y = 112; + sprite->y2 = 0; +} + +static void DrawMsgBoxForCloseByMsg(struct Pokenav_MatchCallGfx *gfx) +{ + LoadUserWindowBorderGfx(gfx->msgBoxWindowId, 1, 0x40); + DrawTextBorderOuter(gfx->msgBoxWindowId, 1, 4); + FillWindowPixelBuffer(gfx->msgBoxWindowId, PIXEL_FILL(1)); + PutWindowTilemap(gfx->msgBoxWindowId); + CopyWindowToVram(gfx->msgBoxWindowId, COPYWIN_FULL); +} + +static bool32 IsDma3ManagerBusyWithBgCopy2(struct Pokenav_MatchCallGfx *gfx) +{ + return IsDma3ManagerBusyWithBgCopy(); +} + +static void PrintCallingDots(struct Pokenav_MatchCallGfx *gfx) +{ + AddTextPrinterParameterized(gfx->msgBoxWindowId, FONT_NORMAL, sText_CallingDots, 32, 1, 1, NULL); +} + +static bool32 WaitForCallingDotsText(struct Pokenav_MatchCallGfx *gfx) +{ + RunTextPrinters(); + return IsTextPrinterActive(gfx->msgBoxWindowId); +} + +static void PrintTrainerIsCloseBy(struct Pokenav_MatchCallGfx *gfx) +{ + AddTextPrinterParameterized(gfx->msgBoxWindowId, FONT_NORMAL, gText_TrainerCloseBy, 0, 1, 1, NULL); +} + +static bool32 WaitForTrainerIsCloseByText(struct Pokenav_MatchCallGfx *gfx) +{ + RunTextPrinters(); + return IsTextPrinterActive(gfx->msgBoxWindowId); +} + +static void PrintMatchCallMessage(struct Pokenav_MatchCallGfx *gfx) +{ + int index = PokenavList_GetSelectedIndex(); + const u8 *str = GetMatchCallMessageText(index, &gfx->newRematchRequest); + u8 speed = GetPlayerTextSpeedDelay(); + AddTextPrinterParameterized(gfx->msgBoxWindowId, FONT_NORMAL, str, 32, 1, speed, NULL); +} + +static bool32 WaitForMatchCallMessageText(struct Pokenav_MatchCallGfx *gfx) +{ + if (JOY_HELD(A_BUTTON)) + gTextFlags.canABSpeedUpPrint = TRUE; + else + gTextFlags.canABSpeedUpPrint = FALSE; + + RunTextPrinters(); + return IsTextPrinterActive(gfx->msgBoxWindowId); +} + +static void EraseCallMessageBox(struct Pokenav_MatchCallGfx *gfx) +{ + HideSpinningPokenavSprite(); + FillBgTilemapBufferRect_Palette0(1, 0, 0, 0, 32, 20); + CopyBgTilemapBufferToVram(1); +} + +static bool32 WaitForCallMessageBoxErase(struct Pokenav_MatchCallGfx *gfx) +{ + return IsDma3ManagerBusyWithBgCopy(); +} + +static void AllocMatchCallSprites(void) +{ + int i; + u8 paletteNum; + struct SpriteSheet spriteSheet; + struct Pokenav_MatchCallGfx *gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MATCH_CALL_OPEN); + + // Load options cursor gfx + for (i = 0; i < ARRAY_COUNT(sOptionsCursorSpriteSheets); i++) + LoadCompressedSpriteSheet(&sOptionsCursorSpriteSheets[i]); + Pokenav_AllocAndLoadPalettes(sOptionsCursorSpritePalettes); + gfx->optionsCursorSprite = NULL; + + // Load trainer pic gfx + spriteSheet.data = gfx->trainerPicGfx; + spriteSheet.size = sizeof(gfx->trainerPicGfx); + spriteSheet.tag = GFXTAG_TRAINER_PIC; + gfx->trainerPicGfxPtr = (u8 *)OBJ_VRAM0 + LoadSpriteSheet(&spriteSheet) * 0x20; + paletteNum = AllocSpritePalette(PALTAG_TRAINER_PIC); + gfx->trainerPicPalOffset = 0x100 + paletteNum * 0x10; + gfx->trainerPicSprite = CreateTrainerPicSprite(); + gfx->trainerPicSprite->invisible = TRUE; +} + +static void FreeMatchCallSprites(void) +{ + struct Pokenav_MatchCallGfx *gfx = GetSubstructPtr(POKENAV_SUBSTRUCT_MATCH_CALL_OPEN); + if (gfx->optionsCursorSprite) + DestroySprite(gfx->optionsCursorSprite); + if (gfx->trainerPicSprite) + DestroySprite(gfx->trainerPicSprite); + + FreeSpriteTilesByTag(GFXTAG_TRAINER_PIC); + FreeSpriteTilesByTag(GFXTAG_CURSOR); + FreeSpritePaletteByTag(PALTAG_CURSOR); + FreeSpritePaletteByTag(PALTAG_TRAINER_PIC); +} + +static void CreateOptionsCursorSprite(struct Pokenav_MatchCallGfx *gfx, int top) +{ + if (!gfx->optionsCursorSprite) + { + u8 spriteId = CreateSprite(&sOptionsCursorSpriteTemplate, 4, 80, 5); + gfx->optionsCursorSprite = &gSprites[spriteId]; + UpdateCursorGfxPos(gfx, top); + } +} + +static void CloseMatchCallSelectOptionsWindow(struct Pokenav_MatchCallGfx *gfx) +{ + DestroySprite(gfx->optionsCursorSprite); + gfx->optionsCursorSprite = NULL; +} + +static void UpdateCursorGfxPos(struct Pokenav_MatchCallGfx *gfx, int top) +{ + gfx->optionsCursorSprite->y2 = top * 16; +} + +static void SpriteCB_OptionsCursor(struct Sprite *sprite) +{ + if (++sprite->data[0] > 3) + { + sprite->data[0] = 0; + sprite->x2 = (sprite->x2 + 1) & 7; + } +} + +static struct Sprite *CreateTrainerPicSprite(void) +{ + u8 spriteId = CreateSprite(&sTrainerPicSpriteTemplate, 44, 104, 6); + return &gSprites[spriteId]; +} + +static void LoadCheckPageTrainerPic(struct Pokenav_MatchCallGfx *gfx) +{ + u16 cursor; + int trainerPic = GetMatchCallTrainerPic(PokenavList_GetSelectedIndex()); + if (trainerPic >= 0) + { + DecompressPicFromTable(&gTrainerFrontPicTable[trainerPic], gfx->trainerPicGfx, SPECIES_NONE); + LZ77UnCompWram(gTrainerFrontPicPaletteTable[trainerPic].data, gfx->trainerPicPal); + cursor = RequestDma3Copy(gfx->trainerPicGfx, gfx->trainerPicGfxPtr, sizeof(gfx->trainerPicGfx), 1); + LoadPalette(gfx->trainerPicPal, gfx->trainerPicPalOffset, sizeof(gfx->trainerPicPal)); + gfx->trainerPicSprite->data[0] = 0; + gfx->trainerPicSprite->data[7] = cursor; + gfx->trainerPicSprite->callback = SpriteCB_TrainerPicSlideOnscreen; + } +} + +static void TrainerPicSlideOffscreen(struct Pokenav_MatchCallGfx *gfx) +{ + gfx->trainerPicSprite->callback = SpriteCB_TrainerPicSlideOffscreen; +} + +static bool32 WaitForTrainerPic(struct Pokenav_MatchCallGfx *gfx) +{ + return gfx->trainerPicSprite->callback != SpriteCallbackDummy; +} + +static void SpriteCB_TrainerPicSlideOnscreen(struct Sprite *sprite) +{ + switch (sprite->data[0]) + { + case 0: + if (CheckForSpaceForDma3Request(sprite->data[7]) != -1) + { + sprite->x2 = -80; + sprite->invisible = FALSE; + sprite->data[0]++; + } + break; + case 1: + sprite->x2 += 8; + if (sprite->x2 >= 0) + { + sprite->x2 = 0; + sprite->callback = SpriteCallbackDummy; + } + break; + } +} + +static void SpriteCB_TrainerPicSlideOffscreen(struct Sprite *sprite) +{ + sprite->x2 -= 8; + if (sprite->x2 <= -80) + { + sprite->invisible = TRUE; + sprite->callback = SpriteCallbackDummy; + } +} |