From f97150bdec0ba3b97a6178414f0b3e28aa12ff5c Mon Sep 17 00:00:00 2001 From: Cuyler36 Date: Tue, 30 May 2023 03:55:27 -0400 Subject: [PATCH] Implement & link save_menu.c --- config/rel_slices.yml | 4 + include/m_cpak.h | 11 ++ include/m_font.h | 3 + include/m_npc.h | 2 + include/m_private.h | 2 +- include/m_view.h | 7 ++ include/s_cpak.h | 20 ++++ include/save_menu.h | 28 ++++- include/types.h | 2 + rel/save_menu.c | 264 ++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 338 insertions(+), 5 deletions(-) create mode 100644 include/s_cpak.h create mode 100644 rel/save_menu.c diff --git a/config/rel_slices.yml b/config/rel_slices.yml index bb60a7a1..9013c360 100644 --- a/config/rel_slices.yml +++ b/config/rel_slices.yml @@ -138,6 +138,10 @@ m_trademark.c: .text: [0x8062B848, 0x8062C048] .rodata: [0x8064D1C0, 0x8064D1C8] .data: [0x806D4958, 0x806D4B18] +save_menu.c: + .text: [0x8062CA5C, 0x8062D39C] + .rodata: [0x8064D1F8, 0x8064D318] + .data: [0x806D4B80, 0x806D4B98] sys_dynamic.c: .bss: [0x813413F8, 0x81361820] # ac_aprilfool_control/aPC_actor_dt.c: common_data is pure bs, diff --git a/include/m_cpak.h b/include/m_cpak.h index 3c54b764..d1477f3c 100644 --- a/include/m_cpak.h +++ b/include/m_cpak.h @@ -2,12 +2,23 @@ #define M_CPAK_H #include "types.h" +#include "s_cpak.h" +#include "m_private.h" +#include "m_npc.h" #ifdef __cplusplus extern "C" { #endif +typedef struct contpak_s { + int _00; + sCPk_c save_pak; +} mCPk_c; + extern int mCPk_InitPak(int pak_idx); +extern int mCPk_PakOpen(mCPk_c* cpak, int pak_idx); +extern int mCPk_SavePak(Private_c* private_data, Animal_c* animals, mCPk_c* cpak); +extern mCPk_c* mCPk_get_pkinfo(); #ifdef __cplusplus } diff --git a/include/m_font.h b/include/m_font.h index 70d24ac0..ffe2b1a4 100644 --- a/include/m_font.h +++ b/include/m_font.h @@ -279,6 +279,9 @@ extern "C" { #define mFont_MARKTYPE_CHOICE 4 #define mFont_MARKTYPE_TOTAL 5 +#define mFont_MODE_POLY 0 +#define mFont_MODE_FONT 1 + enum { mFont_CONT_CODE_BEGIN = 0, mFont_CONT_CODE_LAST = mFont_CONT_CODE_BEGIN, diff --git a/include/m_npc.h b/include/m_npc.h index e2e3ed04..7046b7b9 100644 --- a/include/m_npc.h +++ b/include/m_npc.h @@ -187,6 +187,8 @@ extern void mNpc_ClearCacheName(); extern void mNpc_ClearInAnimal(); extern void mNpc_FirstClearGoodbyMail(); extern void mNpc_ClearIslandNpcRoomData(); +extern void mNpc_CopyAnimalPersonalID(AnmPersonalID_c* dst, AnmPersonalID_c* src); +extern AnmPersonalID_c* mNpc_GetOtherAnimalPersonalID(AnmPersonalID_c* ids, int num_ids); extern void mNpc_PrintRemoveInfo(gfxprint_t* gfxprint); extern void mNpc_PrintFriendship_fdebug(gfxprint_t* gfxprint); diff --git a/include/m_private.h b/include/m_private.h index 39e64418..6c473574 100644 --- a/include/m_private.h +++ b/include/m_private.h @@ -132,7 +132,7 @@ typedef struct private_s { /* 0x1088 */ u16 cloth_idx; /* index value for texture? */ /* 0x108A */ mActor_name_t cloth; /* shirt item */ - /* 0x108C */ AnmPersonalID_c stored_anm_id; /* not sure what the function of this is */ + /* 0x108C */ AnmPersonalID_c stored_anm_id; /* foriegn animal personal ID leftover from N64? */ /* 0x109A */ mPr_destiny_c destiny; /* player fortune, seemingly called destiny */ /* 0x10A4 */ mPr_birthday_c birthday; /* player birthday */ diff --git a/include/m_view.h b/include/m_view.h index b4ddd2c5..1e21cc4b 100644 --- a/include/m_view.h +++ b/include/m_view.h @@ -11,6 +11,12 @@ extern "C" { #endif +#define VIEW_UPDATE_LOOKAT (1 << 0) // 1 +#define VIEW_UPDATE_SCISSOR (1 << 1) // 2 +#define VIEW_UPDATE_PERSPECTIVE (1 << 2) // 4 +#define VIEW_UPDATE_ORTHOGRAPHIC (1 << 3) // 8 +#define VIEW_UPDATE_ALL (VIEW_UPDATE_LOOKAT | VIEW_UPDATE_SCISSOR | VIEW_UPDATE_PERSPECTIVE | VIEW_UPDATE_ORTHOGRAPHIC) // 15 + /* sizeof(struct view_s) == 0x120 */ typedef struct view_s { GRAPH* graph; @@ -44,6 +50,7 @@ typedef struct view_s { } View; extern void initView(View* view, GRAPH* graph); +extern void showView(View* view, int flags); #ifdef __cplusplus } diff --git a/include/s_cpak.h b/include/s_cpak.h new file mode 100644 index 00000000..2416b1bc --- /dev/null +++ b/include/s_cpak.h @@ -0,0 +1,20 @@ +#ifndef S_CPAK_H +#define S_CPAK_H + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct save_pak_s { + u8 unused[0x54]; +} sCPk_c; + +extern int sCPk_PakOpen(sCPk_c* s_pak); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/save_menu.h b/include/save_menu.h index b6b0dfcc..ad990a04 100644 --- a/include/save_menu.h +++ b/include/save_menu.h @@ -9,16 +9,36 @@ extern "C" { #endif +enum save_mode { + SAVE_MODE_BEGIN, + + SAVE_MODE_FLASHROM = SAVE_MODE_BEGIN, + SAVE_MODE_CPAK, + + SAVE_MODE_NUM +}; + +enum save_error { + SAVE_ERROR_NONE, + SAVE_ERROR_FLASHROM, + SAVE_ERROR_CPAK, + SAVE_ERROR_EXIT, + + SAVE_ERROR_NUM +}; + /* sizeof(struct game_save_menu_s) == 0x0228 */ typedef struct game_save_menu_s { /* 0x0000 */ GAME game; /* 0x00E0 */ View view; - // TODO: finish this - /* 0x0200 */ u8 _temp[0x28]; + /* 0x0200 */ u32 frame; + /* 0x0204 */ int mode; + /* 0x0208 */ int error; + /* 0x020C */ int cursor_col[SAVE_MODE_NUM][3]; } GAME_SAVE_MENU; -extern void save_menu_init(GAME_SAVE_MENU* save_menu); -extern void save_menu_cleanup(GAME_SAVE_MENU* save_menu); +extern void save_menu_init(GAME* game); +extern void save_menu_cleanup(GAME* game); #ifdef __cplusplus } diff --git a/include/types.h b/include/types.h index 48bafdc7..a2a0bbec 100644 --- a/include/types.h +++ b/include/types.h @@ -53,6 +53,8 @@ typedef u32 unknown; #endif #endif +#define ARRAY_SIZE(arr, type) (sizeof(arr) / sizeof(type)) + #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #define MIN(a, b) (((a) < (b)) ? (a) : (b)) diff --git a/rel/save_menu.c b/rel/save_menu.c new file mode 100644 index 00000000..1098ba40 --- /dev/null +++ b/rel/save_menu.c @@ -0,0 +1,264 @@ +#include "save_menu.h" + +#include "m_npc.h" +#include "m_private.h" +#include "m_cpak.h" +#include "m_land.h" +#include "m_font.h" +#include "m_trademark.h" +#include "m_controller.h" +#include "m_rcp.h" +#include "sys_matrix.h" +#include "m_common_data.h" + +static void save_menu_set_cursor_col(GAME_SAVE_MENU* save_menu) { + /* this was likely meant to be static */ + int cursor_col[10][3] = { + { 192, 120, 120 }, + { 224, 130, 130 }, + { 240, 150, 150 }, + { 255, 180, 180 }, + { 240, 150, 150 }, + { 224, 130, 130 }, + { 192, 120, 120 }, + { 128, 80, 80 }, + { 64, 64, 64 }, + { 128, 80, 80 }, + }; + + int (*dst)[3] = &save_menu->cursor_col[save_menu->mode]; + int (*color)[3] = &cursor_col[(u32)save_menu->frame / 4]; + int i; + for (i = 0; i < 3; i++) { + (*dst)[i] = (*color)[i]; + } +} + +static void save_menu_reset_cursor_col(int (*color)[3]) { + int default_color[3] = { 40, 40, 40 }; + int i; + + for (i = 0; i < 3; i++) { + (*color)[i] = default_color[i]; + } +} + +typedef void (*SAVE_MENU_PROC)(GAME_SAVE_MENU*); + +static void save_menu_data_save_from(GAME_SAVE_MENU* save_menu) { + if ((int)Common_Get(player_no) != mPr_FOREIGNER) { + Common_Get(now_private)->exists = TRUE; + save_menu->error = SAVE_ERROR_EXIT; // OK + } + else { + save_menu->error = SAVE_ERROR_FLASHROM; // Player is foriegner + } +} + +static void save_menu_data_save_pak(GAME_SAVE_MENU* save_menu) { + Private_c* private = Common_Get(now_private); + if ((int)Common_Get(player_no) == mPr_FOREIGNER) { + AnmPersonalID_c* foriegn_id = mNpc_GetOtherAnimalPersonalID(NULL, 0); + if (foriegn_id != NULL) { + mNpc_CopyAnimalPersonalID(&private->stored_anm_id, foriegn_id); + } + } + + mCPk_PakOpen(mCPk_get_pkinfo(), 0); + if (mCPk_SavePak(Save_Get(private), Save_Get(animals), mCPk_get_pkinfo()) == TRUE) { + if (mLd_PlayerManKindCheck() == FALSE) { + Common_Get(now_private)->exists = FALSE; + } + + save_menu->error = SAVE_ERROR_EXIT; // OK + } + else { + save_menu->error = SAVE_ERROR_CPAK; // Failed to save to CPak + } +} + +static void save_menu_move_do_save(GAME_SAVE_MENU* save_menu) { + static SAVE_MENU_PROC save_proc[SAVE_MODE_NUM] = { &save_menu_data_save_from, &save_menu_data_save_pak }; + + int mode = save_menu->mode; + + /* Check and save to select location */ + if (chkTrigger(BUTTON_A)) { + (*save_proc[mode])(save_menu); + } + + /* Check and change selected save mode */ + if (chkTrigger(BUTTON_R) || chkTrigger(BUTTON_DUP) || chkTrigger(BUTTON_DDOWN)) { + save_menu->frame = 0; + save_menu_reset_cursor_col(save_menu->cursor_col + mode); + save_menu->mode++; + + if (save_menu->mode >= SAVE_MODE_NUM) { + save_menu->mode = SAVE_MODE_BEGIN; + } + } + + /* Check if should exit menu */ + if (chkTrigger(BUTTON_B)) { + save_menu->error = SAVE_ERROR_EXIT; // OK + } +} + +static void save_menu_move_finish(GAME_SAVE_MENU* save_menu) { + GAME_GOTO_NEXT((GAME*)save_menu, trademark, TRADEMARK); +} + +static void save_menu_move_err(GAME_SAVE_MENU* save_menu) { + save_menu->error = SAVE_ERROR_NONE; // cleared +} + +static void save_menu_move_main(GAME_SAVE_MENU* save_menu) { + static SAVE_MENU_PROC sub_proc[SAVE_ERROR_NUM] = { + &save_menu_move_do_save, + &save_menu_move_err, + &save_menu_move_err, + &save_menu_move_finish + }; + + int error = save_menu->error; + + if (error >= SAVE_ERROR_NONE && error < SAVE_ERROR_NUM) { + (*sub_proc[error])(save_menu); + } + + save_menu_set_cursor_col(save_menu); + save_menu->frame++; + + if (save_menu->frame == 40) { + save_menu->frame = 0; + } +} + +static void save_menu_draw_title(GAME_SAVE_MENU* save_menu) { + /* This translates to 'セーブ メニュー' (save menu), the devs didn't bother translating it */ + u8 title[] = { 0x9E, 0x90, 0xDF, CHAR_SPACE, 0xB2, 0xA6, 0x8D, 0x90 }; + + mFont_SetMatrix(save_menu->game.graph, mFont_MODE_FONT); + mFont_SetLineStrings_AndSpace((GAME*)save_menu, title, ARRAY_SIZE(title, u8), 110.0f, 30.0f, 200, 50, 50, 255, FALSE, TRUE, FALSE, 1.1f, 1.1f, mFont_MODE_FONT); + mFont_UnSetMatrix(save_menu->game.graph, mFont_MODE_FONT); +} + +static void save_menu_draw_push_a(GAME_SAVE_MENU* save_menu) { + /* Push A Button */ + u8 push_a[] = { CHAR_P, CHAR_u, CHAR_s, CHAR_h, CHAR_SPACE, CHAR_A, CHAR_SPACE, CHAR_B, CHAR_u, CHAR_t, CHAR_t, CHAR_o, CHAR_n }; + + mFont_SetMatrix(save_menu->game.graph, mFont_MODE_FONT); + mFont_SetLineStrings_AndSpace((GAME*)save_menu, push_a, ARRAY_SIZE(push_a, u8), 95.0f, 175.0f, 200, 200, 200, 255, FALSE, TRUE, FALSE, 0.8f, 0.8f, mFont_MODE_FONT); + mFont_UnSetMatrix(save_menu->game.graph, mFont_MODE_FONT); +} + +static void save_menu_draw_select_r(GAME_SAVE_MENU* save_menu) { + /* Select R Button */ + u8 select_r[] = { CHAR_S, CHAR_e, CHAR_l, CHAR_e, CHAR_c, CHAR_t, CHAR_SPACE, CHAR_R, CHAR_SPACE, CHAR_B, CHAR_u, CHAR_t, CHAR_t, CHAR_o, CHAR_n }; + + mFont_SetMatrix(save_menu->game.graph, mFont_MODE_FONT); + mFont_SetLineStrings_AndSpace((GAME*)save_menu, select_r, ARRAY_SIZE(select_r, u8), 76.0f, 185.0f, 200, 200, 200, 255, FALSE, TRUE, FALSE, 0.8f, 0.8f, mFont_MODE_FONT); + mFont_UnSetMatrix(save_menu->game.graph, mFont_MODE_FONT); +} + +static void save_menu_draw_push_b(GAME_SAVE_MENU* save_menu) { + /* Push B Button to EXIT */ + u8 push_b[] = { CHAR_P, CHAR_u, CHAR_s, CHAR_h, CHAR_SPACE, CHAR_B, CHAR_SPACE, CHAR_B, CHAR_u, CHAR_t, CHAR_t, CHAR_o, CHAR_n, CHAR_SPACE, CHAR_t, CHAR_o, CHAR_SPACE, CHAR_E, CHAR_X, CHAR_I, CHAR_T }; + + mFont_SetMatrix(save_menu->game.graph, mFont_MODE_FONT); + mFont_SetLineStrings_AndSpace((GAME*)save_menu, push_b, ARRAY_SIZE(push_b, u8), 50.0f, 210.0f, 200, 200, 200, 255, FALSE, TRUE, FALSE, 0.8f, 0.8f, mFont_MODE_FONT); + mFont_UnSetMatrix(save_menu->game.graph, mFont_MODE_FONT); +} + +static void save_menu_draw_select_mode(GAME_SAVE_MENU* save_menu) { + /* + + [0] = 'FlashRom にセーブ' "Save to FlashRom" + [1] = 'パック にセーブ ' "Save to Pak" + + */ + u8 select_mode[SAVE_MODE_NUM][13] = { + { CHAR_F, CHAR_l, CHAR_a, CHAR_s, CHAR_h, CHAR_R, CHAR_o, CHAR_m, CHAR_SPACE, 0x15, 0x9E, 0x90, 0xDF }, + { 0xE2, 0x8F, 0x98, CHAR_SPACE, 0x15, 0x9E, 0x90, 0xDF, CHAR_SPACE, CHAR_SPACE, CHAR_SPACE, CHAR_SPACE, CHAR_SPACE }, + }; + + mFont_SetMatrix(save_menu->game.graph, mFont_MODE_FONT); + mFont_SetLineStrings_AndSpace( + (GAME*)save_menu, + select_mode[SAVE_MODE_FLASHROM], ARRAY_SIZE(select_mode[SAVE_MODE_FLASHROM], u8), + 60.0f, 85.0f, + save_menu->cursor_col[SAVE_MODE_FLASHROM][0], save_menu->cursor_col[SAVE_MODE_FLASHROM][1], save_menu->cursor_col[SAVE_MODE_FLASHROM][2], 255, + FALSE, TRUE, FALSE, + 1.2f, 1.2f, + mFont_MODE_FONT + ); + mFont_UnSetMatrix(save_menu->game.graph, mFont_MODE_FONT); + + mFont_SetMatrix(save_menu->game.graph, mFont_MODE_FONT); + mFont_SetLineStrings_AndSpace( + (GAME*)save_menu, + select_mode[SAVE_MODE_CPAK], ARRAY_SIZE(select_mode[SAVE_MODE_CPAK], u8), + 100.0f, 125.0f, + save_menu->cursor_col[SAVE_MODE_CPAK][0], save_menu->cursor_col[SAVE_MODE_CPAK][1], save_menu->cursor_col[SAVE_MODE_CPAK][2], 255, + FALSE, TRUE, FALSE, + 1.2f, 1.2f, + mFont_MODE_FONT + ); + mFont_UnSetMatrix(save_menu->game.graph, mFont_MODE_FONT); +} + +extern void save_menu_draw_main(GAME_SAVE_MENU* save_menu) { + GRAPH* g = save_menu->game.graph; + + OPEN_DISP(g); + + gSPSegment(NOW_POLY_OPA_DISP++, G_MWO_SEGMENT_0, 0); + DisplayList_initialize(g, 0, 0, 0, NULL); + gDPPipeSync(NOW_POLY_OPA_DISP++); + + CLOSE_DISP(g); + + showView(&save_menu->view, VIEW_UPDATE_ALL); + save_menu_draw_title(save_menu); + save_menu_draw_push_a(save_menu); + save_menu_draw_select_r(save_menu); + save_menu_draw_push_b(save_menu); + save_menu_draw_select_mode(save_menu); +} + +static void save_menu_main(GAME* game) { + GRAPH* g; + GAME_SAVE_MENU* save_menu = (GAME_SAVE_MENU*)game; + save_menu_move_main(save_menu); + save_menu_draw_main(save_menu); + + g = game->graph; + game_debug_draw_last(game, g); + game_draw_last(g); +} + +extern void save_menu_cleanup(GAME* game) { } + +extern void save_menu_init(GAME* game) { + GRAPH* g = game->graph; + View* view; + GAME_SAVE_MENU* save_menu = (GAME_SAVE_MENU*)game; + int i; + + game->exec = &save_menu_main; + game->cleanup = &save_menu_cleanup; + + view = &save_menu->view; + initView(view, g); + view->flag = VIEW_UPDATE_ORTHOGRAPHIC; + new_Matrix(game); + SetGameFrame(1); + + save_menu->frame = 0; + save_menu->mode = SAVE_MODE_BEGIN; + save_menu->error = SAVE_ERROR_NONE; + + for (i = 0; i < SAVE_MODE_NUM; i++) { + save_menu_reset_cursor_col(save_menu->cursor_col + i); + } +}