mirror of
https://github.com/pret/pokeplatinum.git
synced 2026-07-31 15:17:20 -05:00
490 lines
13 KiB
C
490 lines
13 KiB
C
#include "menu.h"
|
|
|
|
#include <nitro.h>
|
|
#include <string.h>
|
|
|
|
#include "generated/sdat.h"
|
|
#include "generated/text_banks.h"
|
|
|
|
#include "bg_window.h"
|
|
#include "colored_arrow.h"
|
|
#include "core_sys.h"
|
|
#include "font.h"
|
|
#include "heap.h"
|
|
#include "message.h"
|
|
#include "render_window.h"
|
|
#include "string_list.h"
|
|
#include "text.h"
|
|
#include "unk_02005474.h"
|
|
|
|
#include "res/text/bank/common_strings_2.h"
|
|
|
|
static BOOL TryMovingCursorAndPlaySound(Menu *menu, u8 direction, u16 sound);
|
|
static u8 TryMovingCursor(Menu *menu, u8 direction);
|
|
static u8 CalcMaxEntryWidth(Menu *menu);
|
|
static void DrawWholeMenu(Menu *menu);
|
|
static void DrawCursor(Menu *menu);
|
|
static void CalcCursorDrawCoords(Menu *menu, u8 *outX, u8 *outY, u8 cursorPos);
|
|
|
|
Menu *Menu_New(const MenuTemplate *template, u8 xOffset, u8 yOffset, u8 cursorStart, u8 heapID, u32 cancelKeys)
|
|
{
|
|
Menu *menu = Heap_AllocFromHeap(heapID, sizeof(Menu));
|
|
|
|
menu->template = *template;
|
|
menu->cursor = ColoredArrow_New(heapID);
|
|
menu->cancelKeys = cancelKeys;
|
|
menu->cursorPos = cursorStart;
|
|
menu->width = CalcMaxEntryWidth(menu);
|
|
menu->heapID = heapID;
|
|
menu->xOffset = xOffset;
|
|
menu->yOffset = yOffset;
|
|
menu->letterWidth = Font_GetAttribute(template->fontID, FONTATTR_MAX_LETTER_WIDTH) + Font_GetAttribute(template->fontID, FONTATTR_LETTER_SPACING);
|
|
menu->lineHeight = Font_GetAttribute(template->fontID, FONTATTR_MAX_LETTER_HEIGHT) + Font_GetAttribute(template->fontID, FONTATTR_LINE_SPACING);
|
|
|
|
DrawWholeMenu(menu);
|
|
DrawCursor(menu);
|
|
|
|
return menu;
|
|
}
|
|
|
|
Menu *Menu_NewAndCopyToVRAM(const MenuTemplate *template, u8 xOffset, u8 yOffset, u8 cursorStart, u8 heapID, u32 cancelKeys)
|
|
{
|
|
Menu *menu = Menu_New(template, xOffset, yOffset, cursorStart, heapID, cancelKeys);
|
|
Window_CopyToVRAM(menu->template.window);
|
|
|
|
return menu;
|
|
}
|
|
|
|
Menu *Menu_NewSimple(const MenuTemplate *template, u8 cursorStart, u8 heapID)
|
|
{
|
|
return Menu_NewAndCopyToVRAM(template, Font_GetAttribute(template->fontID, FONTATTR_MAX_LETTER_WIDTH), 0, cursorStart, heapID, PAD_BUTTON_B);
|
|
}
|
|
|
|
void Menu_Free(Menu *menu, u8 *outCursorPos)
|
|
{
|
|
if (outCursorPos != NULL) {
|
|
*outCursorPos = menu->cursorPos;
|
|
}
|
|
|
|
ColoredArrow_Free(menu->cursor);
|
|
Heap_FreeToHeapExplicit(menu->heapID, menu);
|
|
}
|
|
|
|
u32 Menu_ProcessInput(Menu *menu)
|
|
{
|
|
menu->lastAction = MENU_ACTION_NONE;
|
|
|
|
if (JOY_NEW(PAD_BUTTON_A)) {
|
|
Sound_PlayEffect(SEQ_SE_CONFIRM);
|
|
return menu->template.choices[menu->cursorPos].index;
|
|
}
|
|
|
|
if (JOY_NEW(menu->cancelKeys)) {
|
|
Sound_PlayEffect(SEQ_SE_CONFIRM);
|
|
return MENU_CANCELED;
|
|
}
|
|
|
|
if (JOY_NEW(PAD_KEY_UP)) {
|
|
if (TryMovingCursorAndPlaySound(menu, SCROLL_DIRECTION_UP, SEQ_SE_CONFIRM) == TRUE) {
|
|
menu->lastAction = MENU_ACTION_MOVE_UP;
|
|
}
|
|
|
|
return MENU_NOTHING_CHOSEN;
|
|
}
|
|
|
|
if (JOY_NEW(PAD_KEY_DOWN)) {
|
|
if (TryMovingCursorAndPlaySound(menu, SCROLL_DIRECTION_DOWN, SEQ_SE_CONFIRM) == TRUE) {
|
|
menu->lastAction = MENU_ACTION_MOVE_DOWN;
|
|
}
|
|
|
|
return MENU_NOTHING_CHOSEN;
|
|
}
|
|
|
|
if (JOY_NEW(PAD_KEY_LEFT)) {
|
|
if (TryMovingCursorAndPlaySound(menu, SCROLL_DIRECTION_LEFT, SEQ_SE_CONFIRM) == TRUE) {
|
|
menu->lastAction = MENU_ACTION_MOVE_LEFT;
|
|
}
|
|
|
|
return MENU_NOTHING_CHOSEN;
|
|
}
|
|
|
|
if (JOY_NEW(PAD_KEY_RIGHT)) {
|
|
if (TryMovingCursorAndPlaySound(menu, SCROLL_DIRECTION_RIGHT, SEQ_SE_CONFIRM) == TRUE) {
|
|
menu->lastAction = MENU_ACTION_MOVE_RIGHT;
|
|
}
|
|
|
|
return MENU_NOTHING_CHOSEN;
|
|
}
|
|
|
|
return MENU_NOTHING_CHOSEN;
|
|
}
|
|
|
|
u32 Menu_ProcessInputWithSound(Menu *menu, u16 sdatID)
|
|
{
|
|
menu->lastAction = MENU_ACTION_NONE;
|
|
|
|
if (JOY_NEW(PAD_BUTTON_A)) {
|
|
Sound_PlayEffect(SEQ_SE_CONFIRM);
|
|
return menu->template.choices[menu->cursorPos].index;
|
|
}
|
|
|
|
if (JOY_NEW(menu->cancelKeys)) {
|
|
Sound_PlayEffect(SEQ_SE_CONFIRM);
|
|
return MENU_CANCELED;
|
|
}
|
|
|
|
if (JOY_NEW(PAD_KEY_UP)) {
|
|
if (TryMovingCursorAndPlaySound(menu, SCROLL_DIRECTION_UP, sdatID) == TRUE) {
|
|
menu->lastAction = MENU_ACTION_MOVE_UP;
|
|
}
|
|
|
|
return MENU_NOTHING_CHOSEN;
|
|
}
|
|
|
|
if (JOY_NEW(PAD_KEY_DOWN)) {
|
|
if (TryMovingCursorAndPlaySound(menu, SCROLL_DIRECTION_DOWN, sdatID) == TRUE) {
|
|
menu->lastAction = MENU_ACTION_MOVE_DOWN;
|
|
}
|
|
|
|
return MENU_NOTHING_CHOSEN;
|
|
}
|
|
|
|
if (JOY_NEW(PAD_KEY_LEFT)) {
|
|
if (TryMovingCursorAndPlaySound(menu, SCROLL_DIRECTION_LEFT, sdatID) == TRUE) {
|
|
menu->lastAction = MENU_ACTION_MOVE_LEFT;
|
|
}
|
|
|
|
return MENU_NOTHING_CHOSEN;
|
|
}
|
|
|
|
if (JOY_NEW(PAD_KEY_RIGHT)) {
|
|
if (TryMovingCursorAndPlaySound(menu, SCROLL_DIRECTION_RIGHT, sdatID) == TRUE) {
|
|
menu->lastAction = MENU_ACTION_MOVE_RIGHT;
|
|
}
|
|
|
|
return MENU_NOTHING_CHOSEN;
|
|
}
|
|
|
|
return MENU_NOTHING_CHOSEN;
|
|
}
|
|
|
|
u32 Menu_ProcessExternalInput(Menu *menu, u8 input)
|
|
{
|
|
switch (input) {
|
|
case MENU_INPUT_CONFIRM:
|
|
Sound_PlayEffect(SEQ_SE_CONFIRM);
|
|
return menu->template.choices[menu->cursorPos].index;
|
|
|
|
case MENU_INPUT_CANCEL:
|
|
Sound_PlayEffect(SEQ_SE_CONFIRM);
|
|
return 0xfffffffe;
|
|
|
|
case MENU_INPUT_MOVE_UP:
|
|
TryMovingCursorAndPlaySound(menu, SCROLL_DIRECTION_UP, SEQ_SE_CONFIRM);
|
|
return MENU_NOTHING_CHOSEN;
|
|
|
|
case MENU_INPUT_MOVE_DOWN:
|
|
TryMovingCursorAndPlaySound(menu, SCROLL_DIRECTION_DOWN, SEQ_SE_CONFIRM);
|
|
return MENU_NOTHING_CHOSEN;
|
|
|
|
case MENU_INPUT_MOVE_LEFT:
|
|
TryMovingCursorAndPlaySound(menu, SCROLL_DIRECTION_LEFT, SEQ_SE_CONFIRM);
|
|
return MENU_NOTHING_CHOSEN;
|
|
|
|
case MENU_INPUT_MOVE_RIGHT:
|
|
TryMovingCursorAndPlaySound(menu, SCROLL_DIRECTION_RIGHT, SEQ_SE_CONFIRM);
|
|
return MENU_NOTHING_CHOSEN;
|
|
}
|
|
|
|
return MENU_NOTHING_CHOSEN;
|
|
}
|
|
|
|
u8 Menu_GetCursorPos(Menu *menu)
|
|
{
|
|
return menu->cursorPos;
|
|
}
|
|
|
|
u8 Menu_GetLastAction(Menu *menu)
|
|
{
|
|
return menu->lastAction;
|
|
}
|
|
|
|
static BOOL TryMovingCursorAndPlaySound(Menu *menu, u8 direction, u16 sound)
|
|
{
|
|
u8 oldCursorPos = menu->cursorPos;
|
|
if (TryMovingCursor(menu, direction) == FALSE) {
|
|
return FALSE;
|
|
}
|
|
|
|
u8 bgColor = Font_GetAttribute(menu->template.fontID, FONTATTR_BG_COLOR);
|
|
|
|
u8 x, y;
|
|
CalcCursorDrawCoords(menu, &x, &y, oldCursorPos);
|
|
Window_FillRectWithColor(menu->template.window, bgColor, x, y, 8, menu->lineHeight);
|
|
|
|
DrawCursor(menu);
|
|
Sound_PlayEffect(sound);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static u8 TryMovingCursor(Menu *menu, u8 direction)
|
|
{
|
|
s8 newCursorPos;
|
|
|
|
if (direction == SCROLL_DIRECTION_UP) {
|
|
if (menu->template.ySize <= 1) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (menu->cursorPos % menu->template.ySize == 0) {
|
|
if (menu->template.loopAround == FALSE) {
|
|
return FALSE;
|
|
}
|
|
|
|
newCursorPos = menu->cursorPos + (menu->template.ySize - 1);
|
|
} else {
|
|
newCursorPos = menu->cursorPos - 1;
|
|
}
|
|
} else if (direction == SCROLL_DIRECTION_DOWN) {
|
|
if (menu->template.ySize <= 1) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (menu->cursorPos % menu->template.ySize == menu->template.ySize - 1) {
|
|
if (menu->template.loopAround == FALSE) {
|
|
return FALSE;
|
|
}
|
|
|
|
newCursorPos = menu->cursorPos - (menu->template.ySize - 1);
|
|
} else {
|
|
newCursorPos = menu->cursorPos + 1;
|
|
}
|
|
} else if (direction == SCROLL_DIRECTION_LEFT) {
|
|
if (menu->template.xSize <= 1) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (menu->cursorPos < menu->template.ySize) {
|
|
if (menu->template.loopAround == FALSE) {
|
|
return FALSE;
|
|
}
|
|
|
|
newCursorPos = menu->cursorPos + (menu->template.ySize * (menu->template.xSize - 1));
|
|
} else {
|
|
newCursorPos = menu->cursorPos - menu->template.ySize;
|
|
}
|
|
} else {
|
|
if (menu->template.xSize <= 1) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (menu->cursorPos >= menu->template.ySize * (menu->template.xSize - 1)) {
|
|
if (menu->template.loopAround == FALSE) {
|
|
return FALSE;
|
|
}
|
|
|
|
newCursorPos = menu->cursorPos % menu->template.ySize;
|
|
} else {
|
|
newCursorPos = menu->cursorPos + menu->template.ySize;
|
|
}
|
|
}
|
|
|
|
if (menu->template.choices[newCursorPos].index == MENU_DUMMY) {
|
|
return FALSE;
|
|
}
|
|
|
|
menu->cursorPos = newCursorPos;
|
|
return TRUE;
|
|
}
|
|
|
|
static u8 CalcMaxEntryWidth(Menu *menu)
|
|
{
|
|
u8 maxWidth = 0;
|
|
|
|
u8 width;
|
|
for (u8 i = 0; i < menu->template.xSize * menu->template.ySize; i++) {
|
|
width = Font_CalcStrbufWidth(menu->template.fontID, menu->template.choices[i].entry, 0);
|
|
|
|
if (maxWidth < width) {
|
|
maxWidth = width;
|
|
}
|
|
}
|
|
|
|
return maxWidth;
|
|
}
|
|
|
|
static void DrawWholeMenu(Menu *menu)
|
|
{
|
|
const void *entry;
|
|
u8 x, y, dx;
|
|
u8 i, j;
|
|
|
|
Window_FillTilemap(menu->template.window, Font_GetAttribute(menu->template.fontID, FONTATTR_BG_COLOR));
|
|
|
|
x = menu->xOffset;
|
|
dx = menu->width + menu->letterWidth * 2;
|
|
|
|
for (i = 0; i < menu->template.xSize; i++) {
|
|
for (j = 0; j < menu->template.ySize; j++) {
|
|
entry = menu->template.choices[i * menu->template.ySize + j].entry;
|
|
y = (menu->lineHeight + menu->template.lineSpacing) * j + menu->yOffset;
|
|
|
|
Text_AddPrinterWithParams(menu->template.window, menu->template.fontID, entry, x, y, TEXT_SPEED_NO_TRANSFER, NULL);
|
|
}
|
|
|
|
x += dx;
|
|
}
|
|
}
|
|
|
|
static void DrawCursor(Menu *menu)
|
|
{
|
|
if (menu->template.suppressCursor == TRUE) {
|
|
return;
|
|
}
|
|
|
|
u8 x, y;
|
|
CalcCursorDrawCoords(menu, &x, &y, menu->cursorPos);
|
|
ColoredArrow_Print(menu->cursor, menu->template.window, x, y);
|
|
}
|
|
|
|
static void CalcCursorDrawCoords(Menu *menu, u8 *outX, u8 *outY, u8 cursorPos)
|
|
{
|
|
*outX = (cursorPos / menu->template.ySize) * (menu->width + menu->letterWidth * 2);
|
|
*outY = (cursorPos % menu->template.ySize) * (menu->lineHeight + menu->template.lineSpacing) + menu->yOffset;
|
|
}
|
|
|
|
Menu *Menu_MakeYesNoChoiceWithCursorAt(BgConfig *bgConfig, const WindowTemplate *winTemplate, u16 borderTileStart, u8 borderPalette, u8 cursorStart, u32 heapID)
|
|
{
|
|
MenuTemplate menuTemplate;
|
|
MessageLoader *msgLoader;
|
|
StringList *choices;
|
|
|
|
msgLoader = MessageLoader_Init(MESSAGE_LOADER_NARC_HANDLE, NARC_INDEX_MSGDATA__PL_MSG, TEXT_BANK_COMMON_STRINGS_2, heapID);
|
|
choices = StringList_New(2, heapID);
|
|
|
|
StringList_AddFromMessageBank(choices, msgLoader, pl_msg_00000361_00041, 0);
|
|
StringList_AddFromMessageBank(choices, msgLoader, pl_msg_00000361_00042, MENU_CANCELED);
|
|
MessageLoader_Free(msgLoader);
|
|
|
|
menuTemplate.choices = choices;
|
|
menuTemplate.window = Window_New(heapID, 1);
|
|
menuTemplate.fontID = FONT_SYSTEM;
|
|
menuTemplate.xSize = 1;
|
|
menuTemplate.ySize = 2;
|
|
menuTemplate.lineSpacing = 0;
|
|
menuTemplate.suppressCursor = FALSE;
|
|
menuTemplate.loopAround = FALSE;
|
|
|
|
Window_AddFromTemplate(bgConfig, menuTemplate.window, winTemplate);
|
|
Window_DrawStandardFrame(menuTemplate.window, 1, borderTileStart, borderPalette);
|
|
|
|
return Menu_NewAndCopyToVRAM(&menuTemplate, 8, 0, cursorStart, heapID, PAD_BUTTON_B);
|
|
}
|
|
|
|
Menu *Menu_MakeYesNoChoice(BgConfig *bgConfig, const WindowTemplate *winTemplate, u16 borderTileStart, u8 borderPalette, u32 heapID)
|
|
{
|
|
return Menu_MakeYesNoChoiceWithCursorAt(bgConfig, winTemplate, borderTileStart, borderPalette, 0, heapID);
|
|
}
|
|
|
|
u32 Menu_ProcessInputAndHandleExit(Menu *menu, u32 heapID)
|
|
{
|
|
u32 result = Menu_ProcessInput(menu);
|
|
if (result != MENU_NOTHING_CHOSEN) {
|
|
Menu_DestroyForExit(menu, heapID);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
u32 Menu_ProcessExternalInputAndHandleExit(Menu *menu, u8 input, u32 heapID)
|
|
{
|
|
u32 result = Menu_ProcessExternalInput(menu, input);
|
|
if (result != MENU_NOTHING_CHOSEN) {
|
|
Menu_DestroyForExit(menu, heapID);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void Menu_DestroyForExit(Menu *menu, u32 heapID)
|
|
{
|
|
Window_EraseStandardFrame(menu->template.window, 0);
|
|
Window_Remove(menu->template.window);
|
|
Heap_FreeToHeapExplicit(heapID, menu->template.window);
|
|
StringList_Free(menu->template.choices);
|
|
Menu_Free(menu, NULL);
|
|
}
|
|
|
|
static const u8 sArrowCursorBitmap[] = {
|
|
0xff,
|
|
0xff,
|
|
0xff,
|
|
0x0,
|
|
0xff,
|
|
0xff,
|
|
0xff,
|
|
0x0,
|
|
0x21,
|
|
0xff,
|
|
0xff,
|
|
0x0,
|
|
0x11,
|
|
0xf2,
|
|
0xff,
|
|
0x0,
|
|
0x11,
|
|
0x21,
|
|
0xff,
|
|
0x0,
|
|
0x11,
|
|
0x11,
|
|
0xf2,
|
|
0x0,
|
|
0x11,
|
|
0x11,
|
|
0x21,
|
|
0x0,
|
|
0x11,
|
|
0x11,
|
|
0x22,
|
|
0x0,
|
|
0x11,
|
|
0x21,
|
|
0xf2,
|
|
0x0,
|
|
0x11,
|
|
0x22,
|
|
0xff,
|
|
0x0,
|
|
0x21,
|
|
0xf2,
|
|
0xff,
|
|
0x0,
|
|
0x22,
|
|
0xff,
|
|
0xff,
|
|
0x0,
|
|
0x0,
|
|
0x0,
|
|
0x0,
|
|
0x0,
|
|
0x0,
|
|
0x0,
|
|
0x0,
|
|
0x0,
|
|
0x0,
|
|
0x0,
|
|
0x0,
|
|
0x0,
|
|
0x0,
|
|
0x0,
|
|
0x0,
|
|
0x0
|
|
};
|
|
|
|
void Window_DrawMenuCursor(Window *window, u32 x, u32 y)
|
|
{
|
|
Window_BlitBitmapRect(window, (void *)sArrowCursorBitmap, 0, 0, 8, 16, x, y, 8, 16);
|
|
}
|