From d55c971abac07b30a331a0a1321645fc674ffb53 Mon Sep 17 00:00:00 2001 From: Cuyler36 Date: Sun, 19 Nov 2023 21:52:12 -0500 Subject: [PATCH] Implement & link m_submenu.c --- config/rel_slices.yml | 15 +- include/m_collision_bg.h | 1 + include/m_msg.h | 1 + include/m_name_table.h | 3 +- include/m_play.h | 5 +- include/m_player.h | 130 ++++++- include/m_player_lib.h | 3 + include/m_submenu.h | 55 ++- include/m_submenu_ovl.h | 2 + rel/m_play.c | 6 +- rel/m_submenu.c | 727 +++++++++++++++++++++++++++++++++++++++ 11 files changed, 925 insertions(+), 23 deletions(-) create mode 100644 rel/m_submenu.c diff --git a/config/rel_slices.yml b/config/rel_slices.yml index db7f7285..4cb40f58 100644 --- a/config/rel_slices.yml +++ b/config/rel_slices.yml @@ -269,11 +269,11 @@ m_start_data_init.c: m_string.c: .text: [0x803EED30, 0x803EF290] .bss: [0x8129F320, 0x8129F400] -m_time.c: - .text: [0x803F33DC, 0x803F3E58] - .rodata: [0x806433B0, 0x806433D8] - .data: [0x8065E378, 0x8065E438] - .bss: [0x8129F410, 0x8129F420] +m_submenu.c: + .text: [0x803EF290, 0x803F0610] + .rodata: [0x806432F0, 0x806432F8] + .data: [0x8065DDD0, 0x8065DE80] + .bss: [0x8129F400, 0x8129F408] m_scene.c: .text: [0x803F0610, 0x803F1528] .rodata: [0x806432F8, 0x80643310] @@ -284,6 +284,11 @@ m_skin_matrix.c: m_snowman.c: .text: [0x803F1BB4, 0x803F1F94] .rodata: [0x80643318, 0x80643330] +m_time.c: + .text: [0x803F33DC, 0x803F3E58] + .rodata: [0x806433B0, 0x806433D8] + .data: [0x8065E378, 0x8065E438] + .bss: [0x8129F410, 0x8129F420] m_view.c: .text: [0x803F3E58, 0x803F4E08] .rodata: [0x806433D8, 0x80643408] diff --git a/include/m_collision_bg.h b/include/m_collision_bg.h index 159045e7..731ad911 100644 --- a/include/m_collision_bg.h +++ b/include/m_collision_bg.h @@ -258,6 +258,7 @@ extern int mCoBG_GetHoleNumber(xyz_t wpos); extern int mCoBG_Attr2CheckPlaceNpc(u32 attribute); extern int mCoBG_ExistHeightGap_KeepAndNow(xyz_t wpos); extern void mCoBG_GetNorm_By3Point(xyz_t* norm, xyz_t* p0, xyz_t* p1, xyz_t* p2); +extern int mCoBG_SearchWaterLimitDistN(xyz_t* water_pos, xyz_t wpos, s16 angle, float max_dist, int divisor); extern void mCoBG_InitMoveBgData(); extern void mCoBG_InitBlockBgCheckMode(); diff --git a/include/m_msg.h b/include/m_msg.h index c08b1321..b948a855 100644 --- a/include/m_msg.h +++ b/include/m_msg.h @@ -260,6 +260,7 @@ extern int mMsg_Check_main_index(mMsg_Window_c* msg_win, int index); extern int mMsg_request_main_appear(mMsg_Window_c* msg_win, ACTOR* other_actor, int display_name, rgba_t* window_color_p, int msg_no, int request_priority); extern int mMsg_Check_main_hide(mMsg_Window_c* msg_win); extern int mMsg_sound_voice_get_for_editor(int code); +extern int mMsg_sound_spec_change_voice(mMsg_Window_c* msg_win); #ifdef __cplusplus } diff --git a/include/m_name_table.h b/include/m_name_table.h index bb10faff..a7a5624e 100644 --- a/include/m_name_table.h +++ b/include/m_name_table.h @@ -152,7 +152,8 @@ typedef struct offset_table_s { #define MINIDISK_NUM 55 #define DIARY_NUM 16 #define TICKET_NUM 96 -#define INSECT_NUM 40 + 5 // 5 spirits +#define INSECT_ONLY_NUM 40 +#define INSECT_NUM INSECT_ONLY_NUM + 5 // 5 spirits #define HUKUBUKURO_NUM 2 #define KABU_NUM 4 diff --git a/include/m_play.h b/include/m_play.h index f8665aea..2cb233e6 100644 --- a/include/m_play.h +++ b/include/m_play.h @@ -42,8 +42,9 @@ struct game_play_s { /* 0x1DA0 */ pause_t pause; /* 0x1DA8 */ Actor_info actor_info; /* 0x1DEC */ Submenu submenu; - /* 0x1FA4 */ s8 unk1FA4; - /* 0x1FA8 */ u8 _1FA4[0x1FB8 - 0x1FA8]; + /* 0x1FA4 */ s8 submenu_ground_idx; + /* 0x1FA8 */ char* submenu_ground_tex[2]; + /* 0x1FB0 */ char* submenu_ground_pallet[2]; /* 0x1FB8 */ PreRender prerender; /* 0x2000 */ Door_info_c door_info; /* 0x2008 */ int next_scene_no; diff --git a/include/m_player.h b/include/m_player.h index 9f618e90..62eb1896 100644 --- a/include/m_player.h +++ b/include/m_player.h @@ -29,6 +29,130 @@ enum { mPlayer_ADDRESSABLE_NUM }; +enum { + mPlayer_INDEX_DMA, + mPlayer_INDEX_INTRO, + mPlayer_INDEX_REFUSE, + mPlayer_INDEX_REFUSE_PICKUP, + mPlayer_INDEX_RETURN_DEMO, + mPlayer_INDEX_RETURN_OUTDOOR, + mPlayer_INDEX_RETURN_OUTDOOR2, + mPlayer_INDEX_WAIT, + mPlayer_INDEX_WALK, + mPlayer_INDEX_RUN, + mPlayer_INDEX_DASH, + mPlayer_INDEX_TUMBLE, + mPlayer_INDEX_TUMBLE_GETUP, + mPlayer_INDEX_TURN_DASH, + mPlayer_INDEX_FALL, + mPlayer_INDEX_WADE, + mPlayer_INDEX_DOOR, + mPlayer_INDEX_OUTDOOR, + mPlayer_INDEX_INVADE, + mPlayer_INDEX_HOLD, + mPlayer_INDEX_PUSH, + mPlayer_INDEX_PULL, + mPlayer_INDEX_ROTATE_FURNITURE, + mPlayer_INDEX_OPEN_FURNITURE, + mPlayer_INDEX_WAIT_OPEN_FURNITURE, + mPlayer_INDEX_CLOSE_FURNITURE, + mPlayer_INDEX_LIE_BED, + mPlayer_INDEX_WAIT_BED, + mPlayer_INDEX_ROLL_BED, + mPlayer_INDEX_STANDUP_BED, + mPlayer_INDEX_PICKUP, + mPlayer_INDEX_PICKUP_JUMP, + mPlayer_INDEX_PICKUP_FURNITURE, + mPlayer_INDEX_PICKUP_EXCHANGE, + mPlayer_INDEX_SITDOWN, + mPlayer_INDEX_SITDOWN_WAIT, + mPlayer_INDEX_STANDUP, + mPlayer_INDEX_SWING_AXE, + mPlayer_INDEX_AIR_AXE, + mPlayer_INDEX_REFLECT_AXE, + mPlayer_INDEX_BROKEN_AXE, + mPlayer_INDEX_SLIP_NET, + mPlayer_INDEX_READY_NET, + mPlayer_INDEX_READY_WALK_NET, + mPlayer_INDEX_SWING_NET, + mPlayer_INDEX_PULL_NET, + mPlayer_INDEX_STOP_NET, + mPlayer_INDEX_NOTICE_NET, + mPlayer_INDEX_PUTAWAY_NET, + mPlayer_INDEX_READY_ROD, + mPlayer_INDEX_CAST_ROD, + mPlayer_INDEX_AIR_ROD, + mPlayer_INDEX_RELAX_ROD, + mPlayer_INDEX_COLLECT_ROD, + mPlayer_INDEX_VIB_ROD, + mPlayer_INDEX_FLY_ROD, + mPlayer_INDEX_NOTICE_ROD, + mPlayer_INDEX_PUTAWAY_ROD, + mPlayer_INDEX_DIG_SCOOP, + mPlayer_INDEX_FILL_SCOOP, + mPlayer_INDEX_REFLECT_SCOOP, + mPlayer_INDEX_AIR_SCOOP, + mPlayer_INDEX_GET_SCOOP, + mPlayer_INDEX_PUTAWAY_SCOOP, + mPlayer_INDEX_PUTIN_SCOOP, + mPlayer_INDEX_TALK, + mPlayer_INDEX_RECIEVE_WAIT, + mPlayer_INDEX_RECIEVE_STRETCH, + mPlayer_INDEX_RECIEVE, + mPlayer_INDEX_RECIEVE_PUTAWAY, + mPlayer_INDEX_GIVE, + mPlayer_INDEX_GIVE_WAIT, + mPlayer_INDEX_TAKEOUT_ITEM, + mPlayer_INDEX_PUTIN_ITEM, + mPlayer_INDEX_DEMO_WAIT, + mPlayer_INDEX_DEMO_WALK, + mPlayer_INDEX_DEMO_GETON_TRAIN, + mPlayer_INDEX_DEMO_GETON_TRAIN_WAIT, + mPlayer_INDEX_DEMO_GETOFF_TRAIN, + mPlayer_INDEX_DEMO_STANDING_TRAIN, + mPlayer_INDEX_DEMO_WADE, + mPlayer_INDEX_HIDE, + mPlayer_INDEX_GROUNDHOG, + mPlayer_INDEX_RELEASE_CREATURE, + mPlayer_INDEX_WASH_CAR, + mPlayer_INDEX_TIRED, + mPlayer_INDEX_ROTATE_OCTAGON, + mPlayer_INDEX_THROW_MONEY, + mPlayer_INDEX_PRAY, + mPlayer_INDEX_SHAKE_TREE, + mPlayer_INDEX_MAIL_JUMP, + mPlayer_INDEX_MAIL_LAND, + mPlayer_INDEX_READY_PITFALL, + mPlayer_INDEX_FALL_PITFALL, + mPlayer_INDEX_STRUGGLE_PITFALL, + mPlayer_INDEX_CLIMBUP_PITFALL, + mPlayer_INDEX_STUNG_BEE, + mPlayer_INDEX_NOTICE_BEE, + mPlayer_INDEX_REMOVE_GRASS, + mPlayer_INDEX_SHOCK, + mPlayer_INDEX_KNOCK_DOOR, + mPlayer_INDEX_CHANGE_CLOTH, + mPlayer_INDEX_PUSH_SNOWBALL, + mPlayer_INDEX_ROTATE_UMBRELLA, + mPlayer_INDEX_WADE_SNOWBALL, + mPlayer_INDEX_COMPLETE_PAYMENT, + mPlayer_INDEX_FAIL_EMU, + mPlayer_INDEX_STUNG_MOSQUITO, + mPlayer_INDEX_NOTICE_MOSQUITO, + mPlayer_INDEX_SWING_FAN, + mPlayer_INDEX_SWITCH_ON_LIGHTHOUSE, + mPlayer_INDEX_RADIO_EXERCISE, + mPlayer_INDEX_DEMO_GETON_BOAT, + mPlayer_INDEX_DEMO_GETON_BOAT_SITDOWN, + mPlayer_INDEX_DEMO_GETON_BOAT_WAIT, + mPlayer_INDEX_DEMO_GETON_BOAT_WADE, + mPlayer_INDEX_DEMO_GETOFF_BOAT_STANDUP, + mPlayer_INDEX_DEMO_GETOFF_BOAT, + mPlayer_INDEX_DEMO_GET_GOLDEN_ITEM, + mPlayer_INDEX_DEMO_GET_GOLDEN_ITEM2, + mPlayer_INDEX_DEMO_GET_GOLDEN_AXE_WAIT +}; + /* sizeof(struct player_actor_s) == 0x13A8 */ struct player_actor_s { /* 0x0000 */ ACTOR actor_class; @@ -76,7 +200,11 @@ struct player_actor_s { /* 0x1310 */ void (*Set_force_position_angle_proc)(GAME*, const xyz_t*, const s_xyz*, u8); /* 0x1314 */ u8 (*Get_force_position_angle_proc)(GAME*, xyz_t*, s_xyz*); /* 0x1318 */ int (*Get_WadeEndPos_proc)(GAME*, xyz_t*); - /* 0x131C */ u8 tmp131C[0x13A8 - 0x131C]; + /* 0x131C */ u8 tmp131C[0x138C - 0x131C]; + /* 0x138C */ int a_btn_pressed; + /* 0x1390 */ int a_btn_triggers_submenu; + /* 0x1394 */ mActor_name_t item_in_front; /* item directly in front of the player */ + /* 0x1396 */ u8 _1396[0x13A8 - 0x1396]; /* TODO: finish */ }; diff --git a/include/m_player_lib.h b/include/m_player_lib.h index 2682d280..9930389c 100644 --- a/include/m_player_lib.h +++ b/include/m_player_lib.h @@ -42,6 +42,9 @@ extern int mPlib_check_request_main_outdoor_priority(GAME* game); extern int mPlib_check_request_main_talk_type1_priority(GAME* game); extern int mPlib_check_request_main_speak_type1_priority(GAME* game); extern int mPlib_Check_able_force_speak_label(GAME* game); +extern int mPlib_able_submenu_type1(GAME* game); +extern void mPlib_request_main_demo_wait_from_submenu(ACTOR* force_speak_label); +extern void mPlib_Load_PlayerTexAndPallet(void* tex_p, void* pal_p, int idx); extern void mPlib_Object_Exchange_keep_new_PlayerMdl(GAME_PLAY* play); extern void mPlib_Object_Exchange_keep_new_PlayerTex(GAME_PLAY* play, int bank_id, int base_idx); diff --git a/include/m_submenu.h b/include/m_submenu.h index 0a583beb..c16f0627 100644 --- a/include/m_submenu.h +++ b/include/m_submenu.h @@ -14,6 +14,10 @@ extern "C" { typedef struct submenu_s Submenu; +#define mSM_MAP_BUTTON BUTTON_X +#define mSM_INV_BUTTON_0 BUTTON_START +#define mSM_INV_BUTTON_1 BUTTON_Y + enum { mSM_PROCESS_WAIT, mSM_PROCESS_PREWAIT, @@ -24,6 +28,13 @@ enum { mSM_PROCESS_NUM }; +enum { + mSM_DLF_SUBMENU_OVL, + mSM_DLF_PLAYER_ACTOR, + + mSM_DLF_NUM +}; + enum { mSM_MOVE_OUT_RIGHT, mSM_MOVE_IN_RIGHT, @@ -82,6 +93,16 @@ typedef struct submenu_item_s { u8 slot_no; } Submenu_Item_c; +typedef struct submenu_dlftbl { + void* _00; + int _04; + int _08; + int _0C; + int _10; + int _14; + const char* name; +} mSM_dlftbl_c; + typedef void (*SUBMENU_PROC)(Submenu*); typedef void (*SUBMENU_GAME_PROC)(Submenu*, GAME*); @@ -119,19 +140,31 @@ struct submenu_s { /* 0x17C */ Submenu_Item_c items[mPr_POCKETS_SLOT_COUNT]; /* item buffer, entries are only set when an item is selected by the player */ }; -extern void mSM_open_submenu(Submenu* submenu, int menu_type, int arg0, int arg1); -extern void load_player(Submenu* submenu); -extern void* mSM_ovlptr_dllcnv(void* vram, Submenu* submenu, int); -extern void mSM_submenu_dt(Submenu*); -extern void mSM_submenu_ovlptr_cleanup(Submenu*); -extern void mSM_submenu_ovlptr_init(GAME_PLAY*); -extern void mSM_submenu_ct(Submenu*); -extern void mSM_submenu_ctrl(GAME_PLAY*); -extern void mSM_submenu_move(Submenu*); -extern void mSM_submenu_draw(Submenu*, GAME_PLAY*); -extern int mSM_CHECK_ALL_FISH_GET(); +extern int mSM_COLLECT_INSECT_GET(int idx); +extern void mSM_COLLECT_INSECT_SET(int idx); extern int mSM_CHECK_ALL_INSECT_GET(); +extern int mSM_CHECK_LAST_INSECT_GET(int idx); +extern int mSM_COLLECT_FISH_GET(int idx); +extern void mSM_COLLECT_FISH_SET(int idx); +extern int mSM_CHECK_ALL_FISH_GET(); +extern int mSM_CHECK_LAST_FISH_GET(int idx); +extern int SubmenuArea_IsPlayer(); +extern void* mSM_ovlptr_dllcnv(void* proc, Submenu* submenu, int dlf_idx); +extern void mSM_submenu_ovlptr_init(GAME_PLAY* play); +extern void mSM_submenu_ovlptr_cleanup(Submenu* submenu); +extern void load_player(Submenu* submenu); +extern void mSM_submenu_ct(Submenu* submenu); +extern void mSM_submenu_dt(Submenu* submenu); +extern void mSM_open_submenu(Submenu* submenu, int type, int arg0, int arg1); +extern void mSM_open_submenu_new(Submenu* submenu, int type, int arg0, int arg1, void* arg2); +extern void mSM_open_submenu_new2(Submenu* submenu, int type, int arg0, int arg1, void* arg2, int arg3); +extern void mSM_submenu_ctrl(GAME_PLAY* play); +extern void mSM_submenu_move(Submenu* submenu); +extern void mSM_submenu_draw(Submenu* submenu, GAME* game); +extern int mSM_check_open_inventory_itemlist(int type, int param_2); extern void mSM_Object_Exchange_keep_new_Menu(GAME_PLAY* play); +extern u8* mSM_Get_ground_tex_p(GAME_PLAY* play); +extern u16* mSM_Get_ground_pallet_p(GAME_PLAY* play); #ifdef __cplusplus } diff --git a/include/m_submenu_ovl.h b/include/m_submenu_ovl.h index c72b7bb2..018d7bc4 100644 --- a/include/m_submenu_ovl.h +++ b/include/m_submenu_ovl.h @@ -145,6 +145,8 @@ struct submenu_overlay_s { /* 0xA00 */ Mtx* projection_matrix; }; +extern void mSM_menu_ovl_init(Submenu* submenu); + #ifdef __cplusplus } #endif diff --git a/rel/m_play.c b/rel/m_play.c index 59fb1faf..b0265770 100644 --- a/rel/m_play.c +++ b/rel/m_play.c @@ -404,7 +404,7 @@ void play_cleanup(GAME* game){ mNpc_ClearMaskNpc(); mSM_submenu_dt(&play->submenu); - play->unk1FA4 = -1; + play->submenu_ground_idx = -1; mSM_submenu_ovlptr_cleanup(&play->submenu); mPlib_Object_Exchange_keep_Player_dt(play); @@ -461,7 +461,7 @@ void play_init(GAME* game){ mCoBG_InitBlockBgCheckMode(); mCoBG_InitDecalCircle(); - play->unk1FA4 = -1; + play->submenu_ground_idx = -1; Gameplay_Scene_Read(play, Save_Get(scene_no)); @@ -830,7 +830,7 @@ void Game_play_draw(GAME* game){ watch_my_step_draw(play); banti_draw(play); - mSM_submenu_draw(&play->submenu, play); + mSM_submenu_draw(&play->submenu, (GAME*)play); } } if (zurumode_flag != 0) { diff --git a/rel/m_submenu.c b/rel/m_submenu.c new file mode 100644 index 00000000..752c48f1 --- /dev/null +++ b/rel/m_submenu.c @@ -0,0 +1,727 @@ +#include "m_submenu.h" +#include "m_submenu_ovl.h" + +#include "m_common_data.h" +#include "m_name_table.h" +#include "m_player_lib.h" +#include "m_msg.h" +#include "m_quest.h" +#include "libultra/libultra.h" + +static mSM_dlftbl_c SubmenuArea_dlftbl[mSM_DLF_NUM] = { + { NULL, 0, 0, 0, 0, 0, "submenu_ovl" }, + { NULL, 0, 0, 0, 0, 0, "player_actor" } +}; + +static mSM_dlftbl_c* SubmenuArea_visit = NULL; +static void* SubmenuArea_allocp = NULL; + +extern int mSM_COLLECT_INSECT_GET(int idx) { + u32 ftr_idx = (0x2F2 << 2) + (idx << 2); + return (Common_Get(now_private)->furniture_collected_bitfield[ftr_idx >> 2 >> 5] & (1 << ((ftr_idx >> 2) & 0x1F))) != 0; +} + +extern void mSM_COLLECT_INSECT_SET(int idx) { + u32 ftr_idx = (0x2F2 << 2) + (idx << 2); + Common_Get(now_private)->furniture_collected_bitfield[ftr_idx >> 2 >> 5] |= (1 << ((ftr_idx >> 2) & 0x1F)); +} + +static int mSM_CHECK_ALL_INSECT_GET_SUB() { + int i; + int n = 0; + + for (i = 0; i < INSECT_ONLY_NUM; i++) { + if (mSM_COLLECT_INSECT_GET(i) != FALSE) { + n++; + } + } + + return n; +} + +extern int mSM_CHECK_ALL_INSECT_GET() { + if (mSM_CHECK_ALL_INSECT_GET_SUB() == INSECT_ONLY_NUM) { + return TRUE; + } + + return FALSE; +} + +extern int mSM_CHECK_LAST_INSECT_GET(int idx) { + int res = FALSE; + + if (mSM_CHECK_ALL_INSECT_GET_SUB() == (INSECT_ONLY_NUM - 1) && mSM_COLLECT_INSECT_GET(idx) == FALSE) { + res = TRUE; + } + + return res; +} + +extern int mSM_COLLECT_FISH_GET(int idx) { + u32 ftr_idx = (0x31A << 2) + (idx << 2); + return (Common_Get(now_private)->furniture_collected_bitfield[ftr_idx >> 2 >> 5] & (1 << ((ftr_idx >> 2) & 0x1F))) != 0; +} + +extern void mSM_COLLECT_FISH_SET(int idx) { + u32 ftr_idx = (0x31A << 2) + (idx << 2); + Common_Get(now_private)->furniture_collected_bitfield[ftr_idx >> 2 >> 5] |= (1 << ((ftr_idx >> 2) & 0x1F)); +} + +static int mSM_CHECK_ALL_FISH_GET_SUB() { + int i; + int n = 0; + + for (i = 0; i < FISH_NUM; i++) { + if (mSM_COLLECT_FISH_GET(i) != FALSE) { + n++; + } + } + + return n; +} + +extern int mSM_CHECK_ALL_FISH_GET() { + if (mSM_CHECK_ALL_FISH_GET_SUB() == FISH_NUM) { + return TRUE; + } + + return FALSE; +} + +extern int mSM_CHECK_LAST_FISH_GET(int idx) { + int res = FALSE; + + if (mSM_CHECK_ALL_FISH_GET_SUB() == (FISH_NUM - 1) && mSM_COLLECT_FISH_GET(idx) == FALSE) { + res = TRUE; + } + + return res; +} + +extern int SubmenuArea_IsPlayer() { + return SubmenuArea_visit == &SubmenuArea_dlftbl[mSM_DLF_PLAYER_ACTOR]; +} + +static void mSM_load_player_anime(GAME_PLAY* play) { + // stubbed +} + +static void SubmenuArea_DoLink(mSM_dlftbl_c* dlftbl, Submenu* submenu, int dlf_idx) { + dlftbl->_00 = SubmenuArea_allocp; + dlftbl->_14 = 0; + SubmenuArea_visit = dlftbl; + submenu->overlay_address = dlftbl->_00; + submenu->next_overlay_address = dlftbl->_00; +} + +static void SubmenuArea_DoUnlink(mSM_dlftbl_c* dlftbl, Submenu* submenu) { + if (dlftbl->_00 != NULL) { + submenu->overlay_address = dlftbl->_00; + submenu->next_overlay_address = dlftbl->_00; + dlftbl->_14 = 0; + dlftbl->_00 = NULL; + SubmenuArea_visit = NULL; + } +} + +static int mSM_ovlptr_dllcnv_sub(void* proc, mSM_dlftbl_c* dlftbl, Submenu* submenu, int dlf_idx) { + if (dlf_idx == mSM_DLF_SUBMENU_OVL || dlf_idx == mSM_DLF_PLAYER_ACTOR) { + SubmenuArea_DoLink(dlftbl, submenu, dlf_idx); + return TRUE; + } + + return FALSE; +} + +extern void* mSM_ovlptr_dllcnv(void* proc, Submenu* submenu, int dlf_idx) { + if (SubmenuArea_visit != NULL) { + return; // ?? + } + else if (mSM_ovlptr_dllcnv_sub(proc, SubmenuArea_dlftbl, submenu, dlf_idx) == FALSE) { + return NULL; + } + + return proc; +} + +extern void mSM_submenu_ovlptr_init(GAME_PLAY* play) { + SubmenuArea_allocp = (void*)1; + SubmenuArea_visit = NULL; +} + +extern void mSM_submenu_ovlptr_cleanup(Submenu* submenu) { + if (SubmenuArea_visit != NULL) { + SubmenuArea_DoUnlink(SubmenuArea_visit, submenu); + SubmenuArea_visit = NULL; + } + + SubmenuArea_allocp = NULL; +} + +extern void load_player(Submenu* submenu) { + mSM_dlftbl_c* dlftbl = &SubmenuArea_dlftbl[mSM_DLF_PLAYER_ACTOR]; + + if (SubmenuArea_visit != dlftbl) { + if (SubmenuArea_visit != NULL) { + SubmenuArea_DoUnlink(SubmenuArea_visit, submenu); + } + + SubmenuArea_DoLink(dlftbl, submenu, mSM_DLF_PLAYER_ACTOR); + } +} + +extern void mSM_submenu_ct(Submenu* submenu) { + bzero(submenu, sizeof(Submenu)); + submenu->process_status = mSM_PROCESS_WAIT; + submenu->wait_timer = 0; + + if (Common_Get(submenu_disabled) == TRUE) { + submenu->disable_start_btn_flag = TRUE; + Common_Set(submenu_disabled, FALSE); + } + + submenu->move_proc = (SUBMENU_PROC)&none_proc1; + submenu->draw_proc = (SUBMENU_GAME_PROC)&none_proc1; +} + +extern void mSM_submenu_dt(Submenu* submenu) { + // stubbed +} + +extern void mSM_open_submenu(Submenu* submenu, int type, int arg0, int arg1) { + mSM_open_submenu_new2(submenu, type, arg0, arg1, NULL, 0); +} + +extern void mSM_open_submenu_new(Submenu* submenu, int type, int arg0, int arg1, void* arg2) { + mSM_open_submenu_new2(submenu, type, arg0, arg1, arg2, 0); +} + +extern void mSM_open_submenu_new2(Submenu* submenu, int type, int arg0, int arg1, void* arg2, int arg3) { + submenu->menu_type = type; + submenu->param0 = arg0; + submenu->param1 = arg1; + submenu->param2 = arg2; + submenu->param3 = arg3; +} + +static void mSM_Reset_player_btn_type1(GAME_PLAY* play) { + PLAYER_ACTOR* player = GET_PLAYER_ACTOR(play); + + if (player != NULL) { + player->a_btn_pressed = FALSE; + player->a_btn_triggers_submenu = TRUE; + } +} + +static void mSM_Reset_player_btn_type2(GAME_PLAY* play) { + PLAYER_ACTOR* player = GET_PLAYER_ACTOR(play); + + if (player != NULL) { + player->a_btn_triggers_submenu = TRUE; + } +} + +static int mSM_check_open_map_new(GAME_PLAY* play) { + PLAYER_ACTOR* player = GET_PLAYER_ACTOR(play); + int open_map = FALSE; + int bx; + int bz; + + if (chkTrigger(mSM_MAP_BUTTON) && Common_Get(map_flag) == TRUE) { + open_map = TRUE; + } + + if (open_map == FALSE) { + return FALSE; + } + + if (player == NULL) { + return FALSE; + } + + if (Save_Get(scene_no) == SCENE_COTTAGE_MY || Save_Get(scene_no) == SCENE_COTTAGE_NPC) { + return FALSE; + } + + mFI_Wpos2BlockNum(&bx, &bz, player->actor_class.world.position); + return mFI_CheckBlockKind_OR(bx, bz, mRF_BLOCKKIND_OCEAN) == FALSE; +} + +extern void mSM_submenu_ctrl(GAME_PLAY* play) { + Submenu* submenu = &play->submenu; + int open_inventory; + + if (submenu->process_status != mSM_PROCESS_WAIT) { + return; + } + + if (play->fb_fade_type != 0) { + return; + } + + if (play->fb_wipe_mode != 0) { + return; + } + + open_inventory = FALSE; + if (chkTrigger(mSM_INV_BUTTON_0) || chkTrigger(mSM_INV_BUTTON_1)) { + open_inventory = TRUE; + } + + if ( + ( + (open_inventory && Common_Get(reset_flag) == FALSE) || + (mSM_check_open_map_new(play) == TRUE && Common_Get(reset_flag) == FALSE) + ) && + submenu->disable_start_btn_flag == FALSE && submenu->disable_start_btn_timer == 0 && + mPlib_able_submenu_type1((GAME*)play) && mEv_CheckFirstIntro() == FALSE + ) { + if (open_inventory) { + mSM_open_submenu(submenu, mSM_OVL_INVENTORY, 0, 0); + } + else { + mSM_open_submenu(submenu, mSM_OVL_MAP, 1, 0); + } + + mSM_Reset_player_btn_type2(play); + } + else { + PLAYER_ACTOR* player = GET_PLAYER_ACTOR(play); + + if ( + player != NULL && player->a_btn_pressed == TRUE && + Common_Get(reset_flag) == FALSE && submenu->disable_start_btn_flag == FALSE && + submenu->disable_start_btn_timer == 0 && mPlib_able_submenu_type1((GAME*)play) + ) { + s16 y_dir = player->actor_class.shape_info.rotation.y; + int dir; + + y_dir -= -0x8000; + dir = ABS(y_dir); + + if (dir < DEG2SHORT_ANGLE(45.0f)) { + switch (player->item_in_front) { + case MESSAGE_BOARD1: + case MESSAGE_BOARD0: + mSM_open_submenu(submenu, mSM_OVL_NOTICE, 0, 0); + mSM_Reset_player_btn_type1(play); + break; + case MAP_BOARD1: + case MAP_BOARD0: + mSM_open_submenu(submenu, mSM_OVL_MAP, 0, 0); + mSM_Reset_player_btn_type1(play); + break; + } + } + } + } + + if (submenu->menu_type != mSM_OVL_NONE) { + submenu->process_status = mSM_PROCESS_PREWAIT; + submenu->mode = 1; + SetGameFrame(1); + } +} + +static void mSM_move_Wait(Submenu* submenu) { + if (submenu->wait_timer != 0) { + submenu->wait_timer--; + } + + if (submenu->disable_start_btn_timer != 0) { + submenu->disable_start_btn_timer--; + } +} + +static void mSM_move_PREWait(Submenu* submenu) { + if (submenu->mode >= 3) { + submenu->process_status = mSM_PROCESS_LINKWAIT; + } +} + +static void mSM_move_LINKWait(Submenu* submenu) { + Submenu_Item_c* item; + mSM_dlftbl_c* dlftbl = &SubmenuArea_dlftbl[mSM_DLF_SUBMENU_OVL]; + int i; + + if (SubmenuArea_visit != dlftbl) { + if (SubmenuArea_visit != NULL) { + SubmenuArea_DoUnlink(SubmenuArea_visit, submenu); + } + + SubmenuArea_DoLink(dlftbl, submenu, mSM_DLF_SUBMENU_OVL); + submenu->move_proc = (SUBMENU_PROC)mSM_ovlptr_dllcnv(&mSM_menu_ovl_init, submenu, mSM_DLF_SUBMENU_OVL); + submenu->draw_proc = (SUBMENU_GAME_PROC)&none_proc1; + submenu->process_status = mSM_PROCESS_PLAY; + submenu->flag = TRUE; + submenu->after_mode = 7; + submenu->unk_164 = 0; + mMl_clear_mail(&submenu->mail); + submenu->item_p = &submenu->items[0]; + submenu->item_num = mPr_POCKETS_SLOT_COUNT; + + item = submenu->item_p; + for (i = 0; i < submenu->item_num; i++) { + item->item = EMPTY_NO; + item->slot_no = mPr_POCKETS_SLOT_COUNT; + item++; + } + + if (submenu->mode != 4) { + if ( + (submenu->menu_type == mSM_OVL_LEDIT && submenu->param0 == 0) || + Common_Get(now_private)->gender == mPr_SEX_MALE + ) { + sAdo_SpecChange(5); + } + else { + sAdo_SpecChange(6); + } + + sAdo_SetVoiceMode(0); + } + } +} + +static void mSM_move_Play(Submenu* submenu) { + (*submenu->move_proc)(submenu); +} + +static void mSM_move_End(Submenu* submenu) { + mSM_dlftbl_c* dlftbl = &SubmenuArea_dlftbl[mSM_DLF_SUBMENU_OVL]; + GAME_PLAY* play = (GAME_PLAY*)gamePT; + + (*submenu->move_proc)(submenu); + submenu->process_status = mSM_PROCESS_WAIT; + submenu->menu_type = mSM_OVL_NONE; + submenu->wait_timer = 2; + submenu->flag = FALSE; + SetGameFrame(1); + + if (submenu->mode != 4) { + mMsg_Window_c* msg_win = mMsg_Get_base_window_p(); + submenu->mode = 0; + mSc_dmacopy_all_exchange_bank(&play->object_exchange); + SubmenuArea_DoUnlink(dlftbl, submenu); + load_player(submenu); + mSM_load_player_anime(play); + submenu->disable_start_btn_timer = 1; + + if (submenu->after_mode == 12) { + mPlib_request_main_demo_wait_from_submenu((ACTOR*)submenu->overlay->menu_info[mSM_OVL_MSCORE].data2); + } + + if (mMsg_Check_main_hide(msg_win) == FALSE && mMsg_Check_not_series_main_wait(msg_win)) { + mMsg_sound_spec_change_voice(msg_win); + } + } +} + +extern void mSM_submenu_move(Submenu* submenu) { + static SUBMENU_PROC move_proc[mSM_PROCESS_NUM] = { + &mSM_move_Wait, + &mSM_move_PREWait, + &mSM_move_LINKWait, + &mSM_move_Play, + &mSM_move_End + }; + + (*move_proc[submenu->process_status])(submenu); +} + +extern void mSM_submenu_draw(Submenu* submenu, GAME* game) { + if ( + submenu->mode >= 3 && + submenu->process_status == mSM_PROCESS_PLAY && + SubmenuArea_visit == &SubmenuArea_dlftbl[mSM_DLF_SUBMENU_OVL] + ) { + (*submenu->draw_proc)(submenu, game); + } +} + +static int mSM_check_item_for_furniture(int slot_no, int param_2) { + Private_c* priv = Common_Get(now_private); + mActor_name_t item = priv->inventory.pockets[slot_no]; + int cat = ITEM_NAME_GET_CAT(item); + int res = FALSE; + + if ( + item != EMPTY_NO && + mPr_GET_ITEM_COND(priv->inventory.item_conditions, slot_no) == mPr_ITEM_COND_NORMAL && + ITEM_NAME_GET_TYPE(item) == NAME_TYPE_ITEM1 && + cat != ITEM1_CAT_FISH && + cat != ITEM1_CAT_KABU && + cat != ITEM1_CAT_INSECT && + item != ITM_KNIFE_AND_FORK && + !(item >= ITM_EXCERCISE_CARD00 && item <= ITM_EXCERCISE_CARD12) + ) { + res = TRUE; + } + + return res; +} + +static int mSM_check_item_for_quest(int slot_no, int param_2) { + Private_c* priv = Common_Get(now_private); + mActor_name_t item = priv->inventory.pockets[slot_no]; + int res = FALSE; + + if ( + item != EMPTY_NO && + !(item >= ITM_EXCERCISE_CARD00 && item <= ITM_EXCERCISE_CARD12) && + item != ITM_KNIFE_AND_FORK && + !(item >= ITM_SPIRIT0 && item <= ITM_SPIRIT4) + ) { + res = TRUE; + } + + return res; +} + +static int mSM_check_item_for_sell(int slot_no, int param_2) { + Private_c* priv = Common_Get(now_private); + mActor_name_t item = priv->inventory.pockets[slot_no]; + int res = FALSE; + + if ( + item != EMPTY_NO && + mPr_GET_ITEM_COND(priv->inventory.item_conditions, slot_no) == mPr_ITEM_COND_NORMAL && + (ITEM_NAME_GET_TYPE(item) != NAME_TYPE_ITEM1 || ITEM_NAME_GET_CAT(item) != ITEM1_CAT_MONEY) && + !(item >= ITM_EXCERCISE_CARD00 && item <= ITM_EXCERCISE_CARD12) && + item != ITM_KNIFE_AND_FORK && + !(item >= ITM_SPIRIT0 && item <= ITM_SPIRIT4) + ) { + res = TRUE; + } + + return res; +} + +static int mSM_check_item_for_give(int slot_no, int param_2) { + Private_c* priv = Common_Get(now_private); + mActor_name_t item = priv->inventory.pockets[slot_no]; + int res = FALSE; + + if ( + item != EMPTY_NO && + mPr_GET_ITEM_COND(priv->inventory.item_conditions, slot_no) == mPr_ITEM_COND_NORMAL && + !(item >= ITM_EXCERCISE_CARD00 && item <= ITM_EXCERCISE_CARD12) && + item != ITM_KNIFE_AND_FORK && + !(item >= ITM_SPIRIT0 && item <= ITM_SPIRIT4) + ) { + res = TRUE; + } + + return res; +} + +static int mSM_check_item_for_take(int slot_no, int param_2) { + Private_c* priv = Common_Get(now_private); + mActor_name_t item = priv->inventory.pockets[slot_no]; + int cat = ITEM_NAME_GET_CAT(item); + int res = FALSE; + + if ( + item != EMPTY_NO && + mPr_GET_ITEM_COND(priv->inventory.item_conditions, slot_no) == mPr_ITEM_COND_NORMAL && + !(item >= ITM_EXCERCISE_CARD00 && item <= ITM_EXCERCISE_CARD12) && + item != ITM_KNIFE_AND_FORK && + !(item >= ITM_SPIRIT0 && item <= ITM_SPIRIT4) && + ( + param_2 == 0 || + ( + ITEM_NAME_GET_TYPE(item) == NAME_TYPE_ITEM1 && + ((cat == ITEM1_CAT_FISH && param_2 == 1) || + (cat == ITEM1_CAT_INSECT && param_2 == 2)) + ) + ) + ) { + res = TRUE; + } + + return res; +} + +static int mSM_check_item_for_minidisk(int slot_no, int param_2) { + Private_c* priv = Common_Get(now_private); + mActor_name_t item = priv->inventory.pockets[slot_no]; + + if ( + mPr_GET_ITEM_COND(priv->inventory.item_conditions, slot_no) == mPr_ITEM_COND_NORMAL && + ITEM_NAME_GET_TYPE(item) == NAME_TYPE_ITEM1 && + ITEM_NAME_GET_CAT(item) == ITEM1_CAT_MINIDISK + ) { + return TRUE; + } + + return FALSE; +} + +static int mSM_check_item_for_shrine(int slot_no, int param_2) { + Private_c* priv = Common_Get(now_private); + if ( + mPr_GET_ITEM_COND(priv->inventory.item_conditions, slot_no) == mPr_ITEM_COND_QUEST && + mQst_CheckLimitbyPossessionIdx(slot_no) + ) { + return TRUE; + } + + return FALSE; +} + +static int mSM_check_item_for_entrust(int slot_no, int param_2) { + Private_c* priv = Common_Get(now_private); + mActor_name_t item = priv->inventory.pockets[slot_no]; + int res = FALSE; + + if ( + item == EMPTY_NO || + mPr_GET_ITEM_COND(priv->inventory.item_conditions, slot_no) == mPr_ITEM_COND_NORMAL && + (ITEM_NAME_GET_TYPE(item) != NAME_TYPE_ITEM1 || ITEM_NAME_GET_CAT(item) != ITEM1_CAT_MONEY) && + !(item >= ITM_EXCERCISE_CARD00 && item <= ITM_EXCERCISE_CARD12) && + item != ITM_KNIFE_AND_FORK && + !(item >= ITM_SPIRIT0 && item <= ITM_SPIRIT4) + ) { + res = TRUE; + } + + return res; +} + +static int mSM_check_item_for_exchange(int slot_no, int exchange_id) { + int res = FALSE; + Private_c* priv = Common_Get(now_private); + mActor_name_t item = priv->inventory.pockets[slot_no]; + + if ( + item != EMPTY_NO && mPr_GET_ITEM_COND(priv->inventory.item_conditions, slot_no) == mPr_ITEM_COND_NORMAL && + item != ITM_SIGNBOARD && item != ITM_KNIFE_AND_FORK && !(item >= ITM_EXCERCISE_CARD00 && item <= ITM_EXCERCISE_CARD12) + ) { + if ( + (ITEM_NAME_GET_TYPE(item) == NAME_TYPE_ITEM1 && ITEM_NAME_GET_CAT(item) == ITEM1_CAT_FISH) && + (ITEM_NAME_GET_TYPE(exchange_id) != NAME_TYPE_ITEM1 || ITEM_NAME_GET_CAT(exchange_id) != ITEM1_CAT_FISH) + ) { + PLAYER_ACTOR* player = GET_PLAYER_ACTOR_NOW(); + xyz_t water_pos; + + if (mCoBG_SearchWaterLimitDistN(&water_pos, player->actor_class.world.position, player->actor_class.shape_info.rotation.y, 120.0f, 12) == FALSE) { + return FALSE; + } + + xyz_t_move(&((GAME_PLAY*)gamePT)->submenu.water_pos, &water_pos); + } + + res = TRUE; + } + + return res; +} + +static int mSM_check_item_for_curator(int slot_no, int param_2) { + Private_c* priv = Common_Get(now_private); + mActor_name_t item = priv->inventory.pockets[slot_no]; + int res = FALSE; + + if ( + item != EMPTY_NO && + mPr_GET_ITEM_COND(priv->inventory.item_conditions, slot_no) == mPr_ITEM_COND_NORMAL && + item != ITM_KNIFE_AND_FORK && + !(item >= ITM_EXCERCISE_CARD00 && item <= ITM_EXCERCISE_CARD12) + ) { + res = TRUE; + } + + return res; +} + +typedef int (*mSM_INVENTORY_CHECK_PROC)(int, int); + +extern int mSM_check_open_inventory_itemlist(int type, int param_2) { + static mSM_INVENTORY_CHECK_PROC check_process[] = { + NULL, + NULL, + &mSM_check_item_for_entrust, + NULL, + &mSM_check_item_for_quest, + &mSM_check_item_for_sell, + &mSM_check_item_for_give, + NULL, + &mSM_check_item_for_take, + &mSM_check_item_for_furniture, + &mSM_check_item_for_minidisk, + &mSM_check_item_for_shrine, + NULL, + &mSM_check_item_for_exchange, + NULL, + &mSM_check_item_for_curator, + NULL + }; + + mSM_INVENTORY_CHECK_PROC check_proc = check_process[type]; + int i; + int res = 0; + + if (check_proc == NULL) { + return 0xFFFF; /* all slots are valid */ + } + + for (i = 0; i < mPr_POCKETS_SLOT_COUNT; i++) { + if ((*check_proc)(i, param_2) != FALSE) { + res |= (1 << i); // slot is valid + } + } + + return res; +} + +static char* mSM_Object_Exchange_keep_new(GAME_PLAY* play, s16 bank_id, size_t size) { + Object_Exchange_c* exchange = &play->object_exchange; + Object_Bank_c* bank = &exchange->banks[exchange->bank_idx]; + + bank->bank_id = bank_id; + bank->dma_start = exchange->next_bank_ram_address; + bank->ram_start = exchange->next_bank_ram_address; + bank->size = size; + + if (exchange->bank_idx < mSc_OBJECT_BANK_NUM - 1) { + exchange->next_bank_ram_address = (char*)ALIGN_NEXT((u32)(exchange->next_bank_ram_address + size), 16); + exchange->bank_idx++; + } + + return bank->dma_start; +} + +static void mSM_Object_Exchange_keep_new_MenuTexAndPallet(GAME_PLAY* play, int idx) { + char* tex_p = mSM_Object_Exchange_keep_new(play, ACTOR_OBJ_BANK_14, (32*32)/2); + char* pal_p = mSM_Object_Exchange_keep_new(play, ACTOR_OBJ_BANK_15, 16 * sizeof(u16)); + + play->submenu_ground_tex[idx] = tex_p; + play->submenu_ground_pallet[idx] = pal_p; + mPlib_Load_PlayerTexAndPallet(tex_p, pal_p, Common_Get(now_private)->backgound_texture - ITM_CLOTH_START); +} + +extern void mSM_Object_Exchange_keep_new_Menu(GAME_PLAY* play) { + play->submenu_ground_idx = 0; + mSM_Object_Exchange_keep_new_MenuTexAndPallet(play, 0); + mSM_Object_Exchange_keep_new_MenuTexAndPallet(play, 1); +} + +extern u8* mSM_Get_ground_tex_p(GAME_PLAY* play) { + int idx = play->submenu_ground_idx; + + if (idx < 0) { + return NULL; + } + + return (u8*)play->submenu_ground_tex[idx]; +} + +extern u16* mSM_Get_ground_pallet_p(GAME_PLAY* play) { + int idx = play->submenu_ground_idx; + + if (idx < 0) { + return NULL; + } + + return (u16*)play->submenu_ground_pallet[idx]; +}