From e90f8ea4ef4301a3e73ac3f6a0bd616c3fbdc086 Mon Sep 17 00:00:00 2001 From: Cuyler36 Date: Thu, 25 Apr 2024 18:06:18 -0400 Subject: [PATCH] Implement & link m_hand_ovl --- config/rel_slices.yml | 5 + include/audio_defs.h | 6 + include/c_keyframe.h | 9 + include/m_cporiginal_ovl.h | 21 + include/m_gba_ovl.h | 17 + include/m_hand_ovl.h | 51 +- include/m_inventory_ovl.h | 53 ++ include/m_inventory_ovl_h.h | 16 + include/m_name_table.h | 135 +++++ include/m_needlework_ovl.h | 3 + include/m_player_lib.h | 1 + include/m_private.h | 303 +++++----- include/m_submenu_ovl.h | 18 +- include/m_tag_ovl.h | 144 ++++- src/m_hand_ovl.c | 1124 +++++++++++++++++++++++++++++++++++ 15 files changed, 1750 insertions(+), 156 deletions(-) create mode 100644 include/m_cporiginal_ovl.h create mode 100644 include/m_gba_ovl.h create mode 100644 include/m_inventory_ovl.h create mode 100644 include/m_inventory_ovl_h.h create mode 100644 src/m_hand_ovl.c diff --git a/config/rel_slices.yml b/config/rel_slices.yml index bc782823..2d193b33 100644 --- a/config/rel_slices.yml +++ b/config/rel_slices.yml @@ -911,6 +911,11 @@ m_editor_ovl.c: .rodata: [0x8064B300, 0x8064B368] .data: [0x806CC9D8, 0x806CD068] .bss: [0x8133F5C8, 0x8133F600] +m_hand_ovl.c: + .text: [0x805DD104, 0x805DFA00] + .rodata: [0x8064B388, 0x8064B418] + .data: [0x806CD0A0, 0x806CD260] + .bss: [0x8133F608, 0x8133F980] m_haniwaPortrait_ovl.c: .text: [0x805DFA00, 0x805DFE48] .rodata: [0x8064B418, 0x8064B448] diff --git a/include/audio_defs.h b/include/audio_defs.h index b912a55c..e8fddb79 100644 --- a/include/audio_defs.h +++ b/include/audio_defs.h @@ -45,6 +45,8 @@ typedef enum audio_sound_effects { NA_SE_MONEY2, NA_SE_COIN, + NA_SE_52 = 0x52, + NA_SE_BIRTH_FTR = 0x57, NA_SE_CLEAN_UP_FTR = 0x58, @@ -52,6 +54,8 @@ typedef enum audio_sound_effects { NA_SE_AMI_HIT = 0x5C, NA_SE_TOOL_GET, + NA_SE_60 = 0x60, + NA_SE_GASAGOSO = 0x69, NA_SE_TOILE_CHAIR_STANDUP = 0x72, @@ -104,6 +108,8 @@ typedef enum audio_sound_effects { NA_SE_ROTATE = 0x41A, + NA_SE_41C = 0x41C, + NA_SE_SOFT_CHAIR_SIT = 0x41F, NA_SE_HARD_CHAIR_SIT, NA_SE_BUBU_CHAIR_SIT, diff --git a/include/c_keyframe.h b/include/c_keyframe.h index 4d45b4ab..5ea08181 100644 --- a/include/c_keyframe.h +++ b/include/c_keyframe.h @@ -111,6 +111,15 @@ typedef struct tex_anim_s { s16 timer; } cKF_TextureAnimation_c; +typedef struct anim_info_s { + cKF_Animation_R_c* animation; + f32 speed; + f32 start_frame; + f32 end_frame; + int mode; + f32 counter; +} cKF_AnimInfo_c; + typedef int (*cKF_draw_callback)(GAME*, cKF_SkeletonInfo_R_c*, int, Gfx**, u8*, void*, s_xyz*, xyz_t*); #define cKF_FRAMERATE 30.0f diff --git a/include/m_cporiginal_ovl.h b/include/m_cporiginal_ovl.h new file mode 100644 index 00000000..103f50f9 --- /dev/null +++ b/include/m_cporiginal_ovl.h @@ -0,0 +1,21 @@ +#ifndef M_CPORIGINAL_OVL_H +#define M_CPORIGINAL_OVL_H + +#include "types.h" +#include "m_submenu_ovl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern void mCO_swap_image(Submenu* submenu, mActor_name_t item0, mActor_name_t item1); +extern int mCO_top_folder(Submenu* submenu); +extern int mCO_check_hide_flg(Submenu* submenu, int folder, int idx); +extern void mCO_on_hide_flg(Submenu* submenu, int folder, int idx); +extern void mCO_clear_hide_flg(Submenu* submenu); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/m_gba_ovl.h b/include/m_gba_ovl.h new file mode 100644 index 00000000..8fb4896f --- /dev/null +++ b/include/m_gba_ovl.h @@ -0,0 +1,17 @@ +#ifndef M_GBA_OVL_H +#define M_GBA_OVL_H + +#include "types.h" +#include "m_submenu_ovl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern void mGB_copy_image(Submenu*, mActor_name_t, mActor_name_t); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/m_hand_ovl.h b/include/m_hand_ovl.h index 67a51fa4..ec248a5b 100644 --- a/include/m_hand_ovl.h +++ b/include/m_hand_ovl.h @@ -4,21 +4,70 @@ #include "types.h" #include "m_hand_ovl_h.h" #include "m_submenu_ovl.h" +#include "c_keyframe.h" #ifdef __cplusplus extern "C" { #endif +enum { + mHD_ACTION_SASU, + mHD_ACTION_SIDE, + mHD_ACTION_CLOSE, + mHD_ACTION_CLOSE_KEEP, + mHD_ACTION_OPEN, + mHD_ACTION_CLOSE2, + mHD_ACTION_SASU2, + + mHD_ACTION_NUM +}; + +enum { + mHD_MOVE_NONE, + mHD_MOVE_NORMAL, + mHD_MOVE_SWITCH_LEFT, + mHD_MOVE_SWITCH_RIGHT, + + mHD_MOVE_NUM +}; + typedef void (*mHD_OVL_NOP_HAND_FUNC)(Submenu*); typedef void (*mHD_OVL_SET_HAND_FUNC)(Submenu*); +typedef struct hand_info_s { + int type; + f32 pos[2]; + f32 ofs[2]; + s16 move_flag; + s16 wait_timer; + cKF_SkeletonInfo_R_c keyframe; + int keyframe_state; + s_xyz work[29]; + s_xyz morph[29]; + u8 _1E8[72]; + s16 act; + s16 next_act; + mActor_name_t item; + Mail_c mail; + u32 item_cond; + u8 hold_tbl; + u8 hold_idx; + u8 ret_flag; + u8 catch_pg; + s16 haniwa_item_cond; + u32 haniwa_item_price; +} mHD_hand_info_c; + /* sizeof(struct hand_ovl_s) == 0x378 */ struct hand_ovl_s { - u8 _000[0x370 - 0x000]; /* TODO */ + mHD_hand_info_c info; mHD_OVL_NOP_HAND_FUNC nop_hand_func; mHD_OVL_SET_HAND_FUNC set_hand_func; }; +extern void mHD_hand_ovl_construct(Submenu* submenu); +extern void mHD_hand_ovl_destruct(Submenu* submenu); + #ifdef __cplusplus } #endif diff --git a/include/m_inventory_ovl.h b/include/m_inventory_ovl.h new file mode 100644 index 00000000..bb698174 --- /dev/null +++ b/include/m_inventory_ovl.h @@ -0,0 +1,53 @@ +#ifndef M_INVENTORY_OVL_H +#define M_INVENTORY_OVL_H + +#include "types.h" +#include "m_inventory_ovl_h.h" +#include "m_submenu_ovl.h" +#include "c_keyframe.h" +#include "libultra/ultratypes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define mIV_PLAYER_JOINT_NUM 27 +#define mIV_ITEM_JOINT_NUM 8 + +/* sizeof (struct inventory_ovl_s) == 0x5EC */ +struct inventory_ovl_s { + cKF_SkeletonInfo_R_c player_keyframe0; + cKF_SkeletonInfo_R_c player_keyframe1; + s_xyz player_work[mIV_PLAYER_JOINT_NUM]; + s_xyz player_morph[mIV_PLAYER_JOINT_NUM]; + + cKF_SkeletonInfo_R_c item_keyframe; + s_xyz item_work[mIV_ITEM_JOINT_NUM]; + s_xyz item_morph[mIV_ITEM_JOINT_NUM]; + + MtxF item_mtx; + MtxF food_mtx; + + u8 _374[0x3BC - 0x374]; + + u16 selected_item_bitfield; + u16 selected_mail_bitfield; + + u32 disp_money; + int disp_money_change_frames; + + xyz_t shovel_pos; + xyz_t release_pos; + u8 shovel_flag; + u8 release_flag; + + u8 food_idx; + + u8 _3E3[0x5EC - 0x3E3]; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/m_inventory_ovl_h.h b/include/m_inventory_ovl_h.h new file mode 100644 index 00000000..9313bbcc --- /dev/null +++ b/include/m_inventory_ovl_h.h @@ -0,0 +1,16 @@ +#ifndef M_INVENTORY_OVL_H_H +#define M_INVENTORY_OVL_H_H + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct inventory_ovl_s mIV_Ovl_c; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/m_name_table.h b/include/m_name_table.h index e6730a89..88d74367 100644 --- a/include/m_name_table.h +++ b/include/m_name_table.h @@ -142,6 +142,10 @@ typedef struct offset_table_s { #define NPC_NUM 236 #define NPC_ISLANDER_NUM 18 +#define TICKET_STACK_MAX 5 +#define WISP_STACK_MAX 5 +#define PAPER_STACK_MAX 4 + #define FTR_NUM 1266 #define PAPER_NUM 256 #define MONEY_NUM 4 @@ -198,6 +202,18 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define NPC_HOUSE_ID_TO_NPC_ID(house) (house + 0x9000) #define NPC_ID_TO_NPC_HOUSE_ID(npc) (npc - 0x9000) +#define ITEM_IS_WISP(n) ((n) >= ITM_SPIRIT0 && (n) <= ITM_SPIRIT4) +#define ITEM_IS_PAPER(n) ((n) >= ITM_PAPER_START && (n) <= (ITM_PAPER_END - 1)) +#define ITEM_IS_CLOTH(n) ((n) >= ITM_CLOTH_START && (n) < ITM_CLOTH_END) + +#define ITEM_IS_RSVCLOTH(n) ((n) >= RSV_CLOTH && (n) <= RSV_CLOTH7) +#define ITEM_IS_RSVNWORG(n) ((n) >= RSV_NW_ORIGINAL0 && (n) <= RSV_NW_ORIGINAL7) +#define ITEM_IS_RSVCPORG(n) ((n) >= RSV_CPORIGINAL_FLD0_00 && (n) <= RSV_CPORIGINAL_FLD7_11) +#define ITEM_IS_RSVGBAORG(n) ((n) >= RSV_GBAORIGINAL0 && (n) <= RSV_GBAORIGINAL7) + +#define PAPER2TYPE(n) ((n) % PAPER_UNIQUE_NUM) +#define PAPER2STACK(n) ((n) / PAPER_UNIQUE_NUM) + #define ITEM_IS_FTR(n) \ (ITEM_NAME_GET_TYPE(n) == NAME_TYPE_FTR0 || ITEM_NAME_GET_TYPE(n) == NAME_TYPE_FTR1) @@ -2778,6 +2794,125 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define RSV_FE1C 0xFE1C #define RSV_FE1F 0xFE1F #define RSV_CLOTH 0xFE20 +#define RSV_CLOTH1 0xFE21 +#define RSV_CLOTH2 0xFE22 +#define RSV_CLOTH3 0xFE23 +#define RSV_CLOTH4 0xFE24 +#define RSV_CLOTH5 0xFE25 +#define RSV_CLOTH6 0xFE26 +#define RSV_CLOTH7 0xFE27 +#define RSV_NW_ORIGINAL0 0xFE31 +#define RSV_NW_ORIGINAL1 0xFE32 +#define RSV_NW_ORIGINAL2 0xFE33 +#define RSV_NW_ORIGINAL3 0xFE34 +#define RSV_NW_ORIGINAL4 0xFE35 +#define RSV_NW_ORIGINAL5 0xFE36 +#define RSV_NW_ORIGINAL6 0xFE37 +#define RSV_NW_ORIGINAL7 0xFE38 +#define RSV_CPORIGINAL_FLD0_00 0xFE39 +#define RSV_CPORIGINAL_FLD0_01 0xFE3A +#define RSV_CPORIGINAL_FLD0_02 0xFE3B +#define RSV_CPORIGINAL_FLD0_03 0xFE3C +#define RSV_CPORIGINAL_FLD0_04 0xFE3D +#define RSV_CPORIGINAL_FLD0_05 0xFE3E +#define RSV_CPORIGINAL_FLD0_06 0xFE3F +#define RSV_CPORIGINAL_FLD0_07 0xFE40 +#define RSV_CPORIGINAL_FLD0_08 0xFE41 +#define RSV_CPORIGINAL_FLD0_09 0xFE42 +#define RSV_CPORIGINAL_FLD0_10 0xFE43 +#define RSV_CPORIGINAL_FLD0_11 0xFE44 +#define RSV_CPORIGINAL_FLD1_00 0xFE45 +#define RSV_CPORIGINAL_FLD1_01 0xFE46 +#define RSV_CPORIGINAL_FLD1_02 0xFE47 +#define RSV_CPORIGINAL_FLD1_03 0xFE48 +#define RSV_CPORIGINAL_FLD1_04 0xFE49 +#define RSV_CPORIGINAL_FLD1_05 0xFE4A +#define RSV_CPORIGINAL_FLD1_06 0xFE4B +#define RSV_CPORIGINAL_FLD1_07 0xFE4C +#define RSV_CPORIGINAL_FLD1_08 0xFE4D +#define RSV_CPORIGINAL_FLD1_09 0xFE4E +#define RSV_CPORIGINAL_FLD1_10 0xFE4F +#define RSV_CPORIGINAL_FLD1_11 0xFE50 +#define RSV_CPORIGINAL_FLD2_00 0xFE51 +#define RSV_CPORIGINAL_FLD2_01 0xFE52 +#define RSV_CPORIGINAL_FLD2_02 0xFE53 +#define RSV_CPORIGINAL_FLD2_03 0xFE54 +#define RSV_CPORIGINAL_FLD2_04 0xFE55 +#define RSV_CPORIGINAL_FLD2_05 0xFE56 +#define RSV_CPORIGINAL_FLD2_06 0xFE57 +#define RSV_CPORIGINAL_FLD2_07 0xFE58 +#define RSV_CPORIGINAL_FLD2_08 0xFE59 +#define RSV_CPORIGINAL_FLD2_09 0xFE5A +#define RSV_CPORIGINAL_FLD2_10 0xFE5B +#define RSV_CPORIGINAL_FLD2_11 0xFE5C +#define RSV_CPORIGINAL_FLD3_00 0xFE5D +#define RSV_CPORIGINAL_FLD3_01 0xFE5E +#define RSV_CPORIGINAL_FLD3_02 0xFE5F +#define RSV_CPORIGINAL_FLD3_03 0xFE60 +#define RSV_CPORIGINAL_FLD3_04 0xFE61 +#define RSV_CPORIGINAL_FLD3_05 0xFE62 +#define RSV_CPORIGINAL_FLD3_06 0xFE63 +#define RSV_CPORIGINAL_FLD3_07 0xFE64 +#define RSV_CPORIGINAL_FLD3_08 0xFE65 +#define RSV_CPORIGINAL_FLD3_09 0xFE66 +#define RSV_CPORIGINAL_FLD3_10 0xFE67 +#define RSV_CPORIGINAL_FLD3_11 0xFE68 +#define RSV_CPORIGINAL_FLD4_00 0xFE69 +#define RSV_CPORIGINAL_FLD4_01 0xFE6A +#define RSV_CPORIGINAL_FLD4_02 0xFE6B +#define RSV_CPORIGINAL_FLD4_03 0xFE6C +#define RSV_CPORIGINAL_FLD4_04 0xFE6D +#define RSV_CPORIGINAL_FLD4_05 0xFE6E +#define RSV_CPORIGINAL_FLD4_06 0xFE6F +#define RSV_CPORIGINAL_FLD4_07 0xFE70 +#define RSV_CPORIGINAL_FLD4_08 0xFE71 +#define RSV_CPORIGINAL_FLD4_09 0xFE72 +#define RSV_CPORIGINAL_FLD4_10 0xFE73 +#define RSV_CPORIGINAL_FLD4_11 0xFE74 +#define RSV_CPORIGINAL_FLD5_00 0xFE75 +#define RSV_CPORIGINAL_FLD5_01 0xFE76 +#define RSV_CPORIGINAL_FLD5_02 0xFE77 +#define RSV_CPORIGINAL_FLD5_03 0xFE78 +#define RSV_CPORIGINAL_FLD5_04 0xFE79 +#define RSV_CPORIGINAL_FLD5_05 0xFE7A +#define RSV_CPORIGINAL_FLD5_06 0xFE7B +#define RSV_CPORIGINAL_FLD5_07 0xFE7C +#define RSV_CPORIGINAL_FLD5_08 0xFE7D +#define RSV_CPORIGINAL_FLD5_09 0xFE7E +#define RSV_CPORIGINAL_FLD5_10 0xFE7F +#define RSV_CPORIGINAL_FLD5_11 0xFE80 +#define RSV_CPORIGINAL_FLD6_00 0xFE81 +#define RSV_CPORIGINAL_FLD6_01 0xFE82 +#define RSV_CPORIGINAL_FLD6_02 0xFE83 +#define RSV_CPORIGINAL_FLD6_03 0xFE84 +#define RSV_CPORIGINAL_FLD6_04 0xFE85 +#define RSV_CPORIGINAL_FLD6_05 0xFE86 +#define RSV_CPORIGINAL_FLD6_06 0xFE87 +#define RSV_CPORIGINAL_FLD6_07 0xFE88 +#define RSV_CPORIGINAL_FLD6_08 0xFE89 +#define RSV_CPORIGINAL_FLD6_09 0xFE8A +#define RSV_CPORIGINAL_FLD6_10 0xFE8B +#define RSV_CPORIGINAL_FLD6_11 0xFE8C +#define RSV_CPORIGINAL_FLD7_00 0xFE8D +#define RSV_CPORIGINAL_FLD7_01 0xFE8E +#define RSV_CPORIGINAL_FLD7_02 0xFE8F +#define RSV_CPORIGINAL_FLD7_03 0xFE90 +#define RSV_CPORIGINAL_FLD7_04 0xFE91 +#define RSV_CPORIGINAL_FLD7_05 0xFE92 +#define RSV_CPORIGINAL_FLD7_06 0xFE93 +#define RSV_CPORIGINAL_FLD7_07 0xFE94 +#define RSV_CPORIGINAL_FLD7_08 0xFE95 +#define RSV_CPORIGINAL_FLD7_09 0xFE96 +#define RSV_CPORIGINAL_FLD7_10 0xFE97 +#define RSV_CPORIGINAL_FLD7_11 0xFE98 +#define RSV_GBAORIGINAL0 0xFE99 +#define RSV_GBAORIGINAL1 0xFE9A +#define RSV_GBAORIGINAL2 0xFE9B +#define RSV_GBAORIGINAL3 0xFE9C +#define RSV_GBAORIGINAL4 0xFE9D +#define RSV_GBAORIGINAL5 0xFE9E +#define RSV_GBAORIGINAL6 0xFE9F +#define RSV_GBAORIGINAL7 0xFEA0 #define RSV_ISLAND_FTR0 0xFEB3 /* mRmTp_FTRSIZE_1x1 S */ #define RSV_ISLAND_FTR1 0xFEB4 /* mRmTp_FTRSIZE_1x1 E */ #define RSV_ISLAND_FTR2 0xFEB5 /* mRmTp_FTRSIZE_1x1 N */ diff --git a/include/m_needlework_ovl.h b/include/m_needlework_ovl.h index cd80e58b..4dfe124f 100644 --- a/include/m_needlework_ovl.h +++ b/include/m_needlework_ovl.h @@ -9,6 +9,9 @@ extern "C" { #endif extern u8 mNW_get_image_no(Submenu* submenu, int slot_no); +extern int mNW_check_hide_flg(Submenu* submenu, int idx); +extern void mNW_on_hide_flg(Submenu* submenu, int idx); +extern void mNW_clear_hide_flg(Submenu* submenu); #ifdef __cplusplus } diff --git a/include/m_player_lib.h b/include/m_player_lib.h index 55b7fda8..a85da2a0 100644 --- a/include/m_player_lib.h +++ b/include/m_player_lib.h @@ -70,6 +70,7 @@ extern int mPlib_check_player_warp_forEvent(void); extern int mPlib_check_player_actor_main_index_Furniture_Move(GAME* game); extern int mPlib_request_main_sitdown_type1(GAME* game, int direct, const xyz_t* pos, int ftr_no); extern int mPlib_request_main_lie_bed_type1(GAME* game, int direct, const xyz_t* pos, int head_direct, int ftr_no); +extern void mPlib_change_player_cloth(GAME* game, int idx); extern mPlayer_change_data_from_submenu_c* mPlib_Get_change_data_from_submenu_p(); diff --git a/include/m_private.h b/include/m_private.h index a6d4d029..abca39d1 100644 --- a/include/m_private.h +++ b/include/m_private.h @@ -18,18 +18,18 @@ extern "C" { #define mPr_WALLET_MAX 99999 #define mPr_DEPOSIT_MAX 999999999 -#define mPr_FLAG_MASK_CAT_SCHEDULED (1 << 0) // Blanca appears when travelling -#define mPr_FLAG_1 (1 << 1) // unused? -#define mPr_FLAG_POSTOFFICE_GIFT0 (1 << 2) // 1,000,000 Bells -#define mPr_FLAG_POSTOFFICE_GIFT1 (1 << 3) // 10,000,000 Bells -#define mPr_FLAG_POSTOFFICE_GIFT2 (1 << 4) // 100,000,000 Bells -#define mPr_FLAG_POSTOFFICE_GIFT3 (1 << 5) // 999,999,999 Bells +#define mPr_FLAG_MASK_CAT_SCHEDULED (1 << 0) // Blanca appears when travelling +#define mPr_FLAG_1 (1 << 1) // unused? +#define mPr_FLAG_POSTOFFICE_GIFT0 (1 << 2) // 1,000,000 Bells +#define mPr_FLAG_POSTOFFICE_GIFT1 (1 << 3) // 10,000,000 Bells +#define mPr_FLAG_POSTOFFICE_GIFT2 (1 << 4) // 100,000,000 Bells +#define mPr_FLAG_POSTOFFICE_GIFT3 (1 << 5) // 999,999,999 Bells #define mPr_FLAG_MUSEUM_COMP_HANDBILL_SCHEDULED (1 << 6) // player is scheduled to receive completion letter & reward -#define mPr_FLAG_MUSEUM_COMP_HANDBILL_RECEIVED (1 << 7) // player has received the completion letter & reward -#define mPr_FLAG_8 (1 << 8) // unused? -#define mPr_FLAG_UPDATE_OUTLOOK_PENDING (1 << 9) // player bought a new coat of roof paint to be repainted -#define mPr_FLAG_BIRTHDAY_ACTIVE (1 << 10) // player's birthday is active and a villager can give them a gift -#define mPr_FLAG_TOTAKEKE_INTRODUCTION (1 << 11) // player has spoken to K.K. Slider before +#define mPr_FLAG_MUSEUM_COMP_HANDBILL_RECEIVED (1 << 7) // player has received the completion letter & reward +#define mPr_FLAG_8 (1 << 8) // unused? +#define mPr_FLAG_UPDATE_OUTLOOK_PENDING (1 << 9) // player bought a new coat of roof paint to be repainted +#define mPr_FLAG_BIRTHDAY_ACTIVE (1 << 10) // player's birthday is active and a villager can give them a gift +#define mPr_FLAG_TOTAKEKE_INTRODUCTION (1 << 11) // player has spoken to K.K. Slider before #define mPr_MONEY_POWER_MIN -80 @@ -37,42 +37,42 @@ extern "C" { #define mPr_GOODS_POWER_MAX 50 enum { - mPr_PLAYER_0, - mPr_PLAYER_1, - mPr_PLAYER_2, - mPr_PLAYER_3, - mPr_FOREIGNER, + mPr_PLAYER_0, + mPr_PLAYER_1, + mPr_PLAYER_2, + mPr_PLAYER_3, + mPr_FOREIGNER, - mPr_PLAYER_NUM + mPr_PLAYER_NUM }; enum { - mPr_ITEM_COND_NORMAL, - mPr_ITEM_COND_PRESENT, - mPr_ITEM_COND_QUEST, - - mPr_ITEM_COND_NUM + mPr_ITEM_COND_NORMAL, + mPr_ITEM_COND_PRESENT, + mPr_ITEM_COND_QUEST, + + mPr_ITEM_COND_NUM }; enum { - mPr_SEX_MALE, - mPr_SEX_FEMALE, - mPr_SEX_OTHER, + mPr_SEX_MALE, + mPr_SEX_FEMALE, + mPr_SEX_OTHER, - mPr_SEX_NUM = mPr_SEX_OTHER + mPr_SEX_NUM = mPr_SEX_OTHER }; enum { - mPr_FACE_TYPE0, - mPr_FACE_TYPE1, - mPr_FACE_TYPE2, - mPr_FACE_TYPE3, - mPr_FACE_TYPE4, - mPr_FACE_TYPE5, - mPr_FACE_TYPE6, - mPr_FACE_TYPE7, + mPr_FACE_TYPE0, + mPr_FACE_TYPE1, + mPr_FACE_TYPE2, + mPr_FACE_TYPE3, + mPr_FACE_TYPE4, + mPr_FACE_TYPE5, + mPr_FACE_TYPE6, + mPr_FACE_TYPE7, - mPr_FACE_TYPE_NUM + mPr_FACE_TYPE_NUM }; #define mPr_ECARD_NUM 367 @@ -88,175 +88,182 @@ enum { #define mPr_RADIOCARD_MAX_DAYS 13 #define mPr_GET_ITEM_COND(all_cond, slot_no) (((all_cond) >> (((u32)(slot_no)) << 1)) & mPr_ITEM_COND_NUM) -#define mPr_SET_ITEM_COND(all_cond, slot_no, cond) (((all_cond) & ~((u32)mPr_ITEM_COND_NUM << ((u32)(slot_no) << 1))) | ((u32)(cond) << ((u32)(i) << 1))) +#define mPr_SET_ITEM_COND(all_cond, slot_no, cond) \ + (((all_cond) & ~((u32)mPr_ITEM_COND_NUM << ((u32)(slot_no) << 1))) | ((u32)(cond) << ((u32)(slot_no) << 1))) enum { - mPr_SUNBURN_RANK_MIN, + mPr_SUNBURN_RANK_MIN, - mPr_SUNBURN_RANK0 = mPr_SUNBURN_RANK_MIN, - mPr_SUNBURN_RANK1, - mPr_SUNBURN_RANK2, - mPr_SUNBURN_RANK3, - mPr_SUNBURN_RANK4, - mPr_SUNBURN_RANK5, - mPr_SUNBURN_RANK6, - mPr_SUNBURN_RANK7, - mPr_SUNBURN_RANK8, - - mPr_SUNBURN_RANK_MAX = mPr_SUNBURN_RANK8, + mPr_SUNBURN_RANK0 = mPr_SUNBURN_RANK_MIN, + mPr_SUNBURN_RANK1, + mPr_SUNBURN_RANK2, + mPr_SUNBURN_RANK3, + mPr_SUNBURN_RANK4, + mPr_SUNBURN_RANK5, + mPr_SUNBURN_RANK6, + mPr_SUNBURN_RANK7, + mPr_SUNBURN_RANK8, - mPr_SUNBURN_RANK_NUM + mPr_SUNBURN_RANK_MAX = mPr_SUNBURN_RANK8, + + mPr_SUNBURN_RANK_NUM }; enum { - mPr_DESTINY_NORMAL, /* standard fortune state */ - mPr_DESTINY_POPULAR, /* good luck with villagers */ - mPr_DESTINY_UNPOPULAR, /* bad luck with villagers */ - mPr_DESTINY_BAD_LUCK, /* bad luck in general */ - mPr_DESTINY_MONEY_LUCK, /* good money luck */ - mPr_DESTINY_GOODS_LUCK, /* good goods/item luck */ + mPr_DESTINY_NORMAL, /* standard fortune state */ + mPr_DESTINY_POPULAR, /* good luck with villagers */ + mPr_DESTINY_UNPOPULAR, /* bad luck with villagers */ + mPr_DESTINY_BAD_LUCK, /* bad luck in general */ + mPr_DESTINY_MONEY_LUCK, /* good money luck */ + mPr_DESTINY_GOODS_LUCK, /* good goods/item luck */ - mPr_DESTINY_NUM + mPr_DESTINY_NUM }; /* sizeof(mPr_destiny_c) == 0xA */ typedef struct player_destiny_s { - /* 0x00 */ lbRTC_time_c received_time; /* time fortune was received */ - /* 0x08 */ u8 type; /* fortune type */ + /* 0x00 */ lbRTC_time_c received_time; /* time fortune was received */ + /* 0x08 */ u8 type; /* fortune type */ } mPr_destiny_c; /* sizeof(mPr_birthday_c) == 4 */ typedef struct player_birthday_s { - /* 0x00 */ u16 year; /* assumed, set in mPr_ClearPrivateBirthday but goes unused elsewhere */ - /* 0x02 */ u8 month; - /* 0x03 */ u8 day; + /* 0x00 */ u16 year; /* assumed, set in mPr_ClearPrivateBirthday but goes unused elsewhere */ + /* 0x02 */ u8 month; + /* 0x03 */ u8 day; } mPr_birthday_c; /* sizeof(mPr_catalog_order_c) == 4 */ typedef struct player_catalog_order_s { - /* 0x00 */ mActor_name_t item; /* ordered item */ - /* 0x02 */ u8 shop_level; /* shop 'level' at time of order */ + /* 0x00 */ mActor_name_t item; /* ordered item */ + /* 0x02 */ u8 shop_level; /* shop 'level' at time of order */ } mPr_catalog_order_c; /* sizeof(mPr_animal_memory_c) == 0xA */ typedef struct player_animal_memory_s { - /* 0x00 */ mActor_name_t npc_id; - /* 0x02 */ u8 land_name[LAND_NAME_SIZE]; + /* 0x00 */ mActor_name_t npc_id; + /* 0x02 */ u8 land_name[LAND_NAME_SIZE]; } mPr_animal_memory_c; /* sizeof(mPr_map_info_c) == 0xA */ typedef struct player_map_s { - /* 0x00 */ u8 land_name[LAND_NAME_SIZE]; - /* 0x08 */ u16 land_id; + /* 0x00 */ u8 land_name[LAND_NAME_SIZE]; + /* 0x08 */ u16 land_id; } mPr_map_info_c; /* sizeof(mPr_day_day_c) == 6 */ typedef struct player_day_day_s { - /* 0x00 */ lbRTC_ymd_c last_date; /* last date modified */ - /* 0x04 */ u8 days; /* number of unique days */ + /* 0x00 */ lbRTC_ymd_c last_date; /* last date modified */ + /* 0x04 */ u8 days; /* number of unique days */ } mPr_day_day_c; /* sizeof(mPr_sunburn_c) == 6 */ typedef struct player_sunburn_s { - /* 0x00 */ lbRTC_ymd_c last_changed_date; /* last date that the sunburn rank changed */ - /* 0x04 */ s8 rank; /* level of sunburn, 0-8 */ - /* 0x05 */ s8 rankdown_days; /* days until sunburn rank decreases */ + /* 0x00 */ lbRTC_ymd_c last_changed_date; /* last date that the sunburn rank changed */ + /* 0x04 */ s8 rank; /* level of sunburn, 0-8 */ + /* 0x05 */ s8 rankdown_days; /* days until sunburn rank decreases */ } mPr_sunburn_c; /* sizeof(mPr_carde_data_c) == 0x32 */ typedef struct player_ecard_data_s { - /* 0x00 */ lbRTC_ymd_c letter_send_date; /* date the latest eCard letter was sent */ - /* 0x04 */ u8 card_letters_sent[mPr_ECARD_LETTER_NUM]; /* bitfield keeping track of which eCard letters have been sent to the player [0, 366] */ + /* 0x00 */ lbRTC_ymd_c letter_send_date; /* date the latest eCard letter was sent */ + /* 0x04 */ u8 card_letters_sent[mPr_ECARD_LETTER_NUM]; /* bitfield keeping track of which eCard letters have been + sent to the player [0, 366] */ } mPr_carde_data_c; #define mPr_MOTHER_MAIL_NORMAL_NUM 7 #define mPr_MOTHER_MAIL_MONTHLY_NUM 2 typedef struct private_mother_mail_data_s { - u8 normal[mPr_MOTHER_MAIL_NORMAL_NUM]; - u8 monthly[mPr_MOTHER_MAIL_MONTHLY_NUM]; - u8 august; // unique byte for month of august + u8 normal[mPr_MOTHER_MAIL_NORMAL_NUM]; + u8 monthly[mPr_MOTHER_MAIL_MONTHLY_NUM]; + u8 august; // unique byte for month of august } mPr_mother_mail_data_c; typedef struct private_mother_mail_info_s { - lbRTC_ymd_c date; - mPr_mother_mail_data_c data; + lbRTC_ymd_c date; + mPr_mother_mail_data_c data; } mPr_mother_mail_info_c; typedef struct private_cloth_s { - u16 idx; - mActor_name_t item; + u16 idx; + mActor_name_t item; } mPr_cloth_c; struct private_s { - /* 0x0000 */ PersonalID_c player_ID; /* player's id info */ - /* 0x0014 */ s8 gender; /* gender/sex of player */ - /* 0x0015 */ s8 face; /* face type of player */ - /* 0x0016 */ u8 reset_count; /* times player has reset */ - /* 0x0017 */ mMsm_record_c museum_record; /* museum items & remail info */ + /* 0x0000 */ PersonalID_c player_ID; /* player's id info */ + /* 0x0014 */ s8 gender; /* gender/sex of player */ + /* 0x0015 */ s8 face; /* face type of player */ + /* 0x0016 */ u8 reset_count; /* times player has reset */ + /* 0x0017 */ mMsm_record_c museum_record; /* museum items & remail info */ - /* must be a struct due to alignment of first member */ - /* 0x0068 */ struct { - /* 0x0068 */ mActor_name_t pockets[mPr_POCKETS_SLOT_COUNT]; /* items in inventory */ - /* 0x0086 */ u8 lotto_ticket_expiry_month; - /* 0x0087 */ u8 lotto_ticket_mail_storage; - /* 0x0088 */ u32 item_conditions; /* bitfield (15 values), 2 bits per pocket slot */ - /* 0x008C */ u32 wallet; - /* 0x0090 */ u32 loan; - } inventory; + /* must be a struct due to alignment of first member */ + /* 0x0068 */ struct { + /* 0x0068 */ mActor_name_t pockets[mPr_POCKETS_SLOT_COUNT]; /* items in inventory */ + /* 0x0086 */ u8 lotto_ticket_expiry_month; + /* 0x0087 */ u8 lotto_ticket_mail_storage; + /* 0x0088 */ u32 item_conditions; /* bitfield (15 values), 2 bits per pocket slot */ + /* 0x008C */ u32 wallet; + /* 0x0090 */ u32 loan; + } inventory; - /* 0x0094 */ mQst_delivery_c deliveries[mPr_DELIVERY_QUEST_NUM]; /* delivery quests */ - /* 0x02EC */ mQst_errand_c errands[mPr_ERRAND_QUEST_NUM]; /* errand quests */ + /* 0x0094 */ mQst_delivery_c deliveries[mPr_DELIVERY_QUEST_NUM]; /* delivery quests */ + /* 0x02EC */ mQst_errand_c errands[mPr_ERRAND_QUEST_NUM]; /* errand quests */ - /* 0x04A4 */ mActor_name_t equipment; /* equipped item */ + /* 0x04A4 */ mActor_name_t equipment; /* equipped item */ - /* 0x04A6 */ Mail_hs_c saved_mail_header; /* saved mail header/footer which is inserted when writing new letters */ - /* 0x04E0 */ Mail_c mail[mPr_INVENTORY_MAIL_COUNT]; /* letters in inventory */ - /* 0x1084 */ mActor_name_t backgound_texture; /* inventory background shirt item id */ - /* 0x1086 */ u8 exists; /* 0/1 if player exists or not */ - /* 0x1087 */ u8 hint_count; /* total hints heard from villagers (initial dialog) */ + /* 0x04A6 */ Mail_hs_c saved_mail_header; /* saved mail header/footer which is inserted when writing new letters */ + /* 0x04E0 */ Mail_c mail[mPr_INVENTORY_MAIL_COUNT]; /* letters in inventory */ + /* 0x1084 */ mActor_name_t backgound_texture; /* inventory background shirt item id */ + /* 0x1086 */ u8 exists; /* 0/1 if player exists or not */ + /* 0x1087 */ u8 hint_count; /* total hints heard from villagers (initial dialog) */ - /* 0x1088 */ mPr_cloth_c cloth; - /* 0x1088 */ //u16 cloth_idx; /* index value for texture? */ - /* 0x108A */ //mActor_name_t cloth; /* shirt item */ + /* 0x1088 */ mPr_cloth_c cloth; + /* 0x1088 */ // u16 cloth_idx; /* index value for texture? */ + /* 0x108A */ // mActor_name_t cloth; /* shirt item */ - /* 0x108C */ AnmPersonalID_c stored_anm_id; /* foriegn animal personal ID leftover from N64? */ + /* 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 */ - /* 0x10A8 */ mPr_catalog_order_c catalog_orders[mPr_CATALOG_ORDER_NUM]; /* items ordered from catalog to be mailed */ - /* 0x10BC */ u8 unk_10A8[24]; /* seemingly unused? */ - /* 0x10D4 */ u32 aircheck_collect_bitfield[2]; /* TODO: this should be a define like #define mPr_AIRCHECK_BITFIELD_NUM ((MD_COUNT / 32) + 1) */ - /* 0x10DC */ Anmremail_c remail; /* scheduled mail received from a foreign villager? */ - /* 0x10F4 */ u32 reset_code; /* 0 when not reset, random value after reset */ - /* 0x10F8 */ mPr_animal_memory_c animal_memory; /* id and town of last animal to move to another town */ - /* 0x1102 */ u8 complete_fish_insect_flags; /* bit0 = completed fish, bit1 = villager acknowledged completed fish, bit2 = completed insect, bit3 = villager acknowledged complete insect */ - /* 0x1104 */ lbRTC_year_t celebrated_birthday_year; /* last year a birthday was celebrated by card or visitor */ + /* 0x109A */ mPr_destiny_c destiny; /* player fortune, seemingly called destiny */ + /* 0x10A4 */ mPr_birthday_c birthday; /* player birthday */ + /* 0x10A8 */ mPr_catalog_order_c + catalog_orders[mPr_CATALOG_ORDER_NUM]; /* items ordered from catalog to be mailed */ + /* 0x10BC */ u8 unk_10A8[24]; /* seemingly unused? */ + /* 0x10D4 */ u32 aircheck_collect_bitfield[2]; /* TODO: this should be a define like #define + mPr_AIRCHECK_BITFIELD_NUM ((MD_COUNT / 32) + 1) */ + /* 0x10DC */ Anmremail_c remail; /* scheduled mail received from a foreign villager? */ + /* 0x10F4 */ u32 reset_code; /* 0 when not reset, random value after reset */ + /* 0x10F8 */ mPr_animal_memory_c animal_memory; /* id and town of last animal to move to another town */ + /* 0x1102 */ u8 + complete_fish_insect_flags; /* bit0 = completed fish, bit1 = villager acknowledged completed fish, bit2 = + completed insect, bit3 = villager acknowledged complete insect */ + /* 0x1104 */ lbRTC_year_t celebrated_birthday_year; /* last year a birthday was celebrated by card or visitor */ - /* catalog */ - /* 0x1108 */ u32 furniture_collected_bitfield[43]; - /* 0x11B4 */ u32 wall_collected_bitfield[3]; - /* 0x11C0 */ u32 carpet_collected_bitfield[3]; - /* 0x11CC */ u32 paper_collected_bitfield[2]; - /* 0x11D4 */ u32 music_collected_bitfield[2]; + /* catalog */ + /* 0x1108 */ u32 furniture_collected_bitfield[43]; + /* 0x11B4 */ u32 wall_collected_bitfield[3]; + /* 0x11C0 */ u32 carpet_collected_bitfield[3]; + /* 0x11CC */ u32 paper_collected_bitfield[2]; + /* 0x11D4 */ u32 music_collected_bitfield[2]; - /* 0x11DC */ mPr_map_info_c maps[mPr_FOREIGN_MAP_COUNT]; /* maps 'collected' for foreign towns */ + /* 0x11DC */ mPr_map_info_c maps[mPr_FOREIGN_MAP_COUNT]; /* maps 'collected' for foreign towns */ - /* 0x122C */ u32 bank_account; /* probably 'deposit' interally */ - /* 0x1240 */ mNW_original_design_c my_org[mPr_ORIGINAL_DESIGN_COUNT]; /* Able Sisters' designs */ - /* 0x2340 */ u8 my_org_no_table[mPr_ORIGINAL_DESIGN_COUNT]; /* order of designs */ - /* 0x2348 */ u32 state_flags; /* TODO: this might be a bitfield/struct, also document bits */ - /* 0x234C */ mCD_player_calendar_c calendar; /* player calendar data */ - /* 0x23B4 */ u32 soncho_trophy_field0; /* first 28 tortimer event flags */ - /* 0x23B8 */ mPr_day_day_c nw_visitor; /* info for how many unique days the player has talked to Sable */ - /* 0x23BE */ mPr_day_day_c radiocard; /* radio stamp days */ - /* 0x23C4 */ mPr_sunburn_c sunburn; /* sunburn state */ - /* 0x23CA */ u8 unused_23CA[14]; /* seemingly unused data */ - /* 0x23D8 */ mActor_name_t birthday_present_npc; /* npc id of the 'best friend' villger who will gift the player a present on their birthday (at the door) */ - /* 0x23DA */ u8 golden_items_collected; /* bitfield tracking which golden items the player has received */ - /* 0x23DC */ u32 soncho_trophy_field1; /* remaining tortimer event flags */ - /* 0x23E0 */ mPr_carde_data_c ecard_letter_data; /* info relating to scanned e-Card letters */ - /* 0x2412 */ u8 unused_2412[46]; + /* 0x122C */ u32 bank_account; /* probably 'deposit' interally */ + /* 0x1240 */ mNW_original_design_c my_org[mPr_ORIGINAL_DESIGN_COUNT]; /* Able Sisters' designs */ + /* 0x2340 */ u8 my_org_no_table[mPr_ORIGINAL_DESIGN_COUNT]; /* order of designs */ + /* 0x2348 */ u32 state_flags; /* TODO: this might be a bitfield/struct, also document bits */ + /* 0x234C */ mCD_player_calendar_c calendar; /* player calendar data */ + /* 0x23B4 */ u32 soncho_trophy_field0; /* first 28 tortimer event flags */ + /* 0x23B8 */ mPr_day_day_c nw_visitor; /* info for how many unique days the player has talked to Sable */ + /* 0x23BE */ mPr_day_day_c radiocard; /* radio stamp days */ + /* 0x23C4 */ mPr_sunburn_c sunburn; /* sunburn state */ + /* 0x23CA */ u8 unused_23CA[14]; /* seemingly unused data */ + /* 0x23D8 */ mActor_name_t birthday_present_npc; /* npc id of the 'best friend' villger who will gift the player a + present on their birthday (at the door) */ + /* 0x23DA */ u8 golden_items_collected; /* bitfield tracking which golden items the player has received */ + /* 0x23DC */ u32 soncho_trophy_field1; /* remaining tortimer event flags */ + /* 0x23E0 */ mPr_carde_data_c ecard_letter_data; /* info relating to scanned e-Card letters */ + /* 0x2412 */ u8 unused_2412[46]; }; extern void mPr_ClearPlayerName(u8* buf); @@ -280,16 +287,22 @@ extern int mPr_CheckCmpPrivate(Private_c* priv0, Private_c* priv1); extern int mPr_GetPrivateIdx(PersonalID_c* pid); extern int mPr_GetPossessionItemIdx(Private_c* priv, mActor_name_t item); extern int mPr_GetPossessionItemIdxWithCond(Private_c* priv, mActor_name_t item, u32 cond); -extern int mPr_GetPossessionItemIdxFGTypeWithCond_cancel(Private_c* priv, mActor_name_t fg_type, u32 cond, mActor_name_t cancel_item); +extern int mPr_GetPossessionItemIdxFGTypeWithCond_cancel(Private_c* priv, mActor_name_t fg_type, u32 cond, + mActor_name_t cancel_item); extern int mPr_GetPossessionItemIdxItem1Category(Private_c* priv, u8 item1_type); -extern int mPr_GetPossessionItemIdxItem1CategoryWithCond_cancel(Private_c* priv, u8 item1_type, u32 cond, mActor_name_t cancel_item); -extern int mPr_GetPossessionItemIdxKindWithCond(Private_c* priv, mActor_name_t kind_start, mActor_name_t kind_end, u32 cond); +extern int mPr_GetPossessionItemIdxItem1CategoryWithCond_cancel(Private_c* priv, u8 item1_type, u32 cond, + mActor_name_t cancel_item); +extern int mPr_GetPossessionItemIdxKindWithCond(Private_c* priv, mActor_name_t kind_start, mActor_name_t kind_end, + u32 cond); extern int mPr_GetPossessionItemSum(Private_c* priv, mActor_name_t item); extern int mPr_GetPossessionItemSumWithCond(Private_c* priv, mActor_name_t item, u32 cond); -extern int mPr_GetPossessionItemSumFGTypeWithCond_cancel(Private_c* priv, mActor_name_t fg_type, u32 cond, mActor_name_t cancel_item); -extern int mPr_GetPossessionItemSumItemCategoryWithCond_cancel(Private_c* priv, u8 item1_type, u32 cond, mActor_name_t cancel_item); +extern int mPr_GetPossessionItemSumFGTypeWithCond_cancel(Private_c* priv, mActor_name_t fg_type, u32 cond, + mActor_name_t cancel_item); +extern int mPr_GetPossessionItemSumItemCategoryWithCond_cancel(Private_c* priv, u8 item1_type, u32 cond, + mActor_name_t cancel_item); extern int mPr_GetPossessionItemSumItemCategoryWithCond(Private_c* priv, u8 item1_type, u32 cond); -extern int mPr_GetPossessionItemSumKindWithCond(Private_c* priv, mActor_name_t kind_start, mActor_name_t kind_end, u32 cond); +extern int mPr_GetPossessionItemSumKindWithCond(Private_c* priv, mActor_name_t kind_start, mActor_name_t kind_end, + u32 cond); extern void mPr_SetItemCollectBit(mActor_name_t item); extern mActor_name_t mPr_DummyPresentToTruePresent(); extern void mPr_SetPossessionItem(Private_c* priv, int idx, mActor_name_t item, u32 cond); diff --git a/include/m_submenu_ovl.h b/include/m_submenu_ovl.h index 15e28afd..10f904e6 100644 --- a/include/m_submenu_ovl.h +++ b/include/m_submenu_ovl.h @@ -27,6 +27,7 @@ #include "m_tag_ovl_h.h" #include "m_catalog_ovl_h.h" #include "m_hand_ovl_h.h" +#include "m_inventory_ovl_h.h" #ifdef __cplusplus extern "C" { @@ -44,7 +45,12 @@ enum { // TODO: fill this out typedef struct submenu_segment_s { - u8 _00[0x54]; + int _00; + s16 _04; + s16 _06; + s16 _08; + s16 _0A; + u8 _0C[0x54 - 0x0C]; } mSM_Segment_c; typedef struct submenu_menu_info_s { @@ -104,8 +110,10 @@ typedef void (*mSM_MOVE_CHG_BASE_PROC)(mSM_MenuInfo_c*, int); typedef void (*mSM_SET_CHAR_MATRIX_PROC)(GRAPH*); typedef void (*mSM_CBUF_COPY_PROC)(GRAPH*, PreRender*, int, int, int); typedef void (*mSM_SET_DRAWMODE_PROC)(GRAPH*, PreRender*, f32, f32, s16); -typedef void (*mSM_DRAW_ITEM_PROC)(GRAPH*, f32, f32, f32, mActor_name_t, int, int, int); -typedef void (*mSM_DRAW_MAIL_PROC)(GRAPH*, f32, f32, f32, Mail_c*, int, int); +typedef void (*mSM_DRAW_ITEM_PROC)(GRAPH* graph, f32 pos_x, f32 pos_y, f32 scale, mActor_name_t item, int present_flag, + int color_flag, int anim_frame, int shadow_flag, int mark_flag); +typedef void (*mSM_DRAW_MAIL_PROC)(GRAPH* graph, f32 pos_x, f32 pos_y, f32 scale, Mail_c* mail, int color_flag, + int shadow_flag, int mark_flag); typedef void (*mSM_SETUP_VIEW_PROC)(Submenu*, GRAPH*, int); typedef void (*mSM_CHANGE_VIEW_PROC)(GRAPH*, f32, f32, f32, f32, s16, int, int); @@ -135,7 +143,7 @@ struct submenu_overlay_s { /* 0x97C */ mTG_Ovl_c* tag_ovl; /* 0x980 */ mHD_Ovl_c* hand_ovl; /* 0x984 */ mHP_Ovl_c* hanwiaPortrait_ovl; - /* 0x988 */ void* inventory_ovl; + /* 0x988 */ mIV_Ovl_c* inventory_ovl; /* 0x98C */ mED_Ovl_c* editor_ovl; /* 0x990 */ mBD_Ovl_c* board_ovl; /* 0x994 */ mAD_Ovl_c* address_ovl; @@ -172,6 +180,8 @@ struct submenu_overlay_s { }; extern void mSM_menu_ovl_init(Submenu* submenu); +extern void mSM_draw_original(Submenu* submenu, GRAPH* graph, f32 pos_x, f32 pos_y, f32 scale, mActor_name_t item, + int shadow_flag); #ifdef __cplusplus } diff --git a/include/m_tag_ovl.h b/include/m_tag_ovl.h index 1fd216de..70128978 100644 --- a/include/m_tag_ovl.h +++ b/include/m_tag_ovl.h @@ -11,29 +11,161 @@ extern "C" { #define mTG_TAG_NUM 4 -typedef void (*mTG_INIT_TAG_DATA_ITEM_WIN_PROC)(Submenu*); -typedef void (*mTG_CHG_TAG_FUNC_PROC)(Submenu*, int, int, int, f32, f32); +enum { + mTG_TYPE_NONE, + mTG_TYPE_FIELD_DEFAULT, + mTG_TYPE_FIELD_DEFAULT_BURY, + mTG_TYPE_FIELD_LETTER, + mTG_TYPE_FIELD_LETTER_BURY, + mTG_TYPE_FIELD_HUKUBUKURO, + mTG_TYPE_FIELD_HUKUBUKURO_BURY, + mTG_TYPE_FIELD_RELEASE, + mTG_TYPE_CATCH_ITEM, + mTG_TYPE_FIELD_PLANT, + mTG_TYPE_FIELD_PLANT_JOB, + mTG_TYPE_PRESENT_ITEM, + mTG_TYPE_ROOM_DEFAULT, + mTG_TYPE_ROOM_WALL, + mTG_TYPE_ROOM_CARPET, + mTG_TYPE_ROOM_LETTER, + mTG_TYPE_ROOM_HUKUBUKURO, + mTG_TYPE_OTHER_LETTER, + mTG_TYPE_OTHER_HUKUBUKURO, + mTG_TYPE_DEF_RMAIL, + mTG_TYPE_ROOM_RMAIL, + mTG_TYPE_DEF_RMAIL_PRE, + mTG_TYPE_DEF_SMAIL, + mTG_TYPE_ROOM_SMAIL, + mTG_TYPE_DEF_SMAIL_PRE, + mTG_TYPE_DUMP_MAIL, + mTG_TYPE_MONEY_SACK, + mTG_TYPE_QUEST_ITEM, + mTG_TYPE_SELL_ITEM, + mTG_TYPE_GIVE_ITEM, + mTG_TYPE_SEND_MAIL, + mTG_TYPE_FIELD_TICKET, + mTG_TYPE_FIELD_TICKET_BURY, + mTG_TYPE_ROOM_TICKET, + mTG_TYPE_CATCH_TICKET, + mTG_TYPE_PUTIN_ITEM, + mTG_TYPE_SHRINE_ITEM, + mTG_TYPE_HANIWA_ITEM, + mTG_TYPE_HANIWA_PUT_ITEM, + mTG_TYPE_HANIWA_PRICE, + mTG_TYPE_HANIWA_GET_ITEM, + mTG_TYPE_ORDER_ITEM, + mTG_TYPE_CP_DELETE, + mTG_TYPE_CP_DELETE2, + mTG_TYPE_FIELD_MAIL_MARK, + mTG_TYPE_DUMP_MAIL_MARK_CONF, + mTG_TYPE_FIELD_MAIL_MARK2, + mTG_TYPE_CPACK_MAIL_MARK, + mTG_TYPE_SELL_ALL_ITEM, + mTG_TYPE_MUSIC_SELECT, + mTG_TYPE_MUSIC_SELECT_MANY, + mTG_TYPE_FIELD_WISP, + mTG_TYPE_CATCH_WISP, + mTG_TYPE_TAG_HAND_OVER_CURATOR, + mTG_TYPE_TAG_NW_SELECT, + mTG_TYPE_TAG_NW_MY_ROOM, + mTG_TYPE_TAG_NW_OT_ROOM, + mTG_TYPE_TAG_NW_UG_ROOM, + mTG_TYPE_TAG_NW_MR_SEL_STICK, + mTG_TYPE_TAG_NW_OR_SEL_STICK, + mTG_TYPE_TAG_NW_SEL_PUT, + mTG_TYPE_TAG_NW_SEL_STK_PATTERN, + mTG_TYPE_TAG_REMOVE, + mTG_TYPE_TAG_PUT_ALL, + mTG_TYPE_TAG_PUT_CHK, + mTG_TYPE_FIELD_LETTERS, + mTG_TYPE_FIELD_LETTERS_BURY, + mTG_TYPE_ROOM_LETTERS, + mTG_TYPE_OTHER_LETTERS, + mTG_TYPE_CHANGE_ORIGINAL, + mTG_TYPE_TAISOU_CARD, + mTG_TYPE_DUMP_ITEM, + mTG_TYPE_FIELD_SIGN, + mTG_TYPE_FIELD_BALLOON, + mTG_TYPE_TAG_NW_SELECT_CHANGE, + mTG_TYPE_TAG_NW_SELECT_PUT, + mTG_TYPE_76, + mTG_TYPE_TAG_PASSWORD_ITEM, + + mTG_TYPE_NUM +}; + +enum { + mTG_TABLE_ITEM, + mTG_TABLE_MAIL, + mTG_TABLE_MONEY, + mTG_TABLE_PLAYER, + mTG_TABLE_BG, + mTG_TABLE_MBOX, + mTG_TABLE_HANIWA, + mTG_TABLE_COLLECT, + mTG_TABLE_WCHANGE, + mTG_TABLE_CPMAIL, + mTG_TABLE_CPMAIL_WC, + mTG_TABLE_CPMAIL_TI, + mTG_TABLE_CPEDIT, + mTG_TABLE_CPEDIT_END, + mTG_TABLE_CATALOG, + mTG_TABLE_CATALOG_WC, + mTG_TABLE_MUSIC_MAIN, + mTG_TABLE_NEEDLEWORK, + mTG_TABLE_CPORIGINAL, + mTG_TABLE_INVENTORY_WC_ORG, + mTG_TABLE_CPORIGINAL_NW, + mTG_TABLE_CPORIGINAL_WC, + mTG_TABLE_CPORIGINAL_TI, + mTG_TABLE_GBA, + mTG_TABLE_GBA_NW, + mTG_TABLE_CARD, + mTG_TABLE_GBA_NW2, + + mTG_TABLE_NUM +}; /* sizeof(mTG_tag_c) == 0xB4 */ typedef struct tag_s { u8 type; - u8 _01[0x40 - 0x01]; + u8 _01; + u8 _02; + u8 _03; + f32 _04[2]; + f32 pos[2]; + u8 _14[0x38 - 0x14]; + int table; + int _3C; int _40; u8 _44[0xB4 - 0x44]; } mTG_tag_c; +typedef void (*mTG_INIT_TAG_DATA_ITEM_WIN_PROC)(Submenu*); +typedef void (*mTG_CHG_TAG_FUNC_PROC)(Submenu*, int, int, int, f32, f32); +typedef void (*mTG_SET_HAND_POS_PROC)(Submenu*, f32*, int, int); +typedef void (*mTG_EXCHANGE_PROC)(Submenu*, mSM_MenuInfo_c*); +typedef Mail_c* (*mTG_GET_MAIL_POINTER_PROC)(Submenu*, mHD_Ovl_c*); +typedef int (*mTG_GET_TABLE_IDX_PROC)(mTG_tag_c*); + /* TODO */ struct tag_ovl_s { /* 0x000 */ int sel_tag_idx; /* 0x004 */ int ret_tag_idx; /* 0x008 */ mTG_tag_c tags[mTG_TAG_NUM]; - /* 0x2D8 */ void* _2D8; - /* 0x2DC */ void* _2DC; + /* 0x2D8 */ mTG_SET_HAND_POS_PROC set_hand_pos_proc; + /* 0x2DC */ mTG_EXCHANGE_PROC exchange_proc; /* 0x2E0 */ mTG_INIT_TAG_DATA_ITEM_WIN_PROC init_tag_data_item_win_proc; /* 0x2E4 */ mTG_CHG_TAG_FUNC_PROC chg_tag_func_proc; - /* 0x2E8 */ u8 _2E8[0x3C4 - 0x2E8]; + /* 0x2E8 */ mTG_GET_MAIL_POINTER_PROC get_mail_pointer_proc; + /* 0x2EC */ mTG_GET_TABLE_IDX_PROC get_table_idx_proc; + /* 0x2F0 */ s16 item_name_wait_time; + /* 0x2F2 */ u8 _2F2[0x3C4 - 0x2F2]; }; +extern int mTG_mark_main(Submenu*, mSM_MenuInfo_c*, int, int); +extern int mTG_mark_mainX(Submenu*, mSM_MenuInfo_c*, int, int, int, int); + #ifdef __cplusplus } #endif diff --git a/src/m_hand_ovl.c b/src/m_hand_ovl.c new file mode 100644 index 00000000..290dab93 --- /dev/null +++ b/src/m_hand_ovl.c @@ -0,0 +1,1124 @@ +#include "m_hand_ovl.h" + +#include "m_submenu_ovl.h" +#include "m_tag_ovl.h" +#include "m_debug.h" +#include "audio.h" +#include "m_common_data.h" +#include "m_cporiginal_ovl.h" +#include "m_gba_ovl.h" +#include "m_inventory_ovl.h" +#include "m_player_lib.h" +#include "m_needlework_ovl.h" +#include "sys_matrix.h" +#include "m_rcp.h" + +static mHD_Ovl_c hand_ovl_data; + +extern cKF_Animation_R_c cKF_ba_r_hnd_sasu; +extern cKF_Animation_R_c cKF_ba_r_hnd_side; +extern cKF_Animation_R_c cKF_ba_r_hnd_catch; + +static cKF_AnimInfo_c mHD_animeTable[mHD_ACTION_NUM] = { + { &cKF_ba_r_hnd_sasu, 1.0f, 1.0f, 16.0f, cKF_FRAMECONTROL_REPEAT, 0.0f }, + { &cKF_ba_r_hnd_side, 1.0f, 1.0f, 16.0f, cKF_FRAMECONTROL_REPEAT, 0.0f }, + { &cKF_ba_r_hnd_catch, 1.0f, 1.0f, 7.0f, cKF_FRAMECONTROL_STOP, 0.0f }, + { &cKF_ba_r_hnd_catch, 1.0f, 7.0f, 7.0f, cKF_FRAMECONTROL_STOP, 0.0f }, + { &cKF_ba_r_hnd_catch, 1.0f, 7.0f, 1.0f, cKF_FRAMECONTROL_STOP, 0.0f }, + { &cKF_ba_r_hnd_catch, 1.0f, 1.0f, 7.0f, cKF_FRAMECONTROL_STOP, 0.0f }, + { &cKF_ba_r_hnd_sasu, 1.0f, 1.0f, 16.0f, cKF_FRAMECONTROL_REPEAT, 0.0f }, +}; + +static f32 mHD_animeSpdTable[mHD_ACTION_NUM] = { 0.275f, 0.275f, 0.45f, 0.45f, 0.45f, 0.45f, 0.275f }; + +static f32 mHD_hand_offsetX_table[mHD_ACTION_NUM] = { 16.0f, 16.0f, 10.0f, 10.0f, 10.0f, 10.0f, 16.0f }; +static f32 mHD_hand_offsetY_table[mHD_ACTION_NUM] = { 6.0f, 6.0f, 2.0f, 2.0f, 2.0f, 2.0f, 6.0f }; + +static void mHD_set_anime(Submenu* submenu, cKF_SkeletonInfo_R_c* keyframe) { + int idx = submenu->overlay->hand_ovl->info.act; + cKF_AnimInfo_c* anim_info = &mHD_animeTable[idx]; + f32 anim_speed = mHD_animeSpdTable[idx]; + + cKF_SkeletonInfo_R_init(keyframe, keyframe->skeleton, anim_info->animation, anim_info->start_frame, + anim_info->end_frame, anim_info->start_frame, anim_speed, 0.0f, anim_info->mode, NULL); +} + +extern cKF_Skeleton_R_c cKF_bs_r_hnd; + +static void mHD_hand_shape_init(Submenu* submenu) { + mHD_Ovl_c* hand_ovl = submenu->overlay->hand_ovl; + cKF_SkeletonInfo_R_c* keyframe = &hand_ovl->info.keyframe; + + cKF_SkeletonInfo_R_ct(keyframe, &cKF_bs_r_hnd, NULL, hand_ovl->info.work, hand_ovl->info.morph); + mHD_set_anime(submenu, keyframe); + keyframe->morph_counter = 0.0f; +} + +static void mHD_hand_shape_move(Submenu* submenu) { + mHD_Ovl_c* hand_ovl = submenu->overlay->hand_ovl; + + hand_ovl->info.keyframe_state = cKF_SkeletonInfo_R_play(&hand_ovl->info.keyframe); +} + +static void mHD_calc_hand_offset(Submenu* submenu) { + mHD_Ovl_c* hand_ovl = submenu->overlay->hand_ovl; + + chase_f(&hand_ovl->info.ofs[0], mHD_hand_offsetX_table[hand_ovl->info.act], 0.5f); + chase_f(&hand_ovl->info.ofs[1], mHD_hand_offsetY_table[hand_ovl->info.act], 0.5f); +} + +static void mHD_hand_pos_get(Submenu* submenu, f32* pos, int table_type, int table_idx, mHD_Ovl_c* hand_ovl) { + mActor_name_t item = hand_ovl->info.item; + + submenu->overlay->tag_ovl->set_hand_pos_proc(submenu, pos, table_type, table_idx); + + if (table_type == mTG_TABLE_MUSIC_MAIN) { + pos[0] += 4.0f; + pos[1] += 5.0f; + } + + if (table_type == mTG_TABLE_NEEDLEWORK && item != EMPTY_NO && !(item >= RSV_CLOTH && item <= RSV_CLOTH7) && + !(item >= ITM_MY_ORG_UMBRELLA0 && item <= ITM_MY_ORG_UMBRELLA7)) { + if (submenu->overlay->menu_info[mSM_OVL_NEEDLEWORK].data0 == 0) { + pos[0] += -11.0f; + pos[1] += 23.0f; + } else { + pos[1] += 23.0f; + } + } else if ((table_type == mTG_TABLE_GBA || table_type == mTG_TABLE_GBA_NW || table_type == mTG_TABLE_CARD || + table_type == mTG_TABLE_GBA_NW2 || table_type == mTG_TABLE_CPORIGINAL || + table_type == mTG_TABLE_CPORIGINAL_NW) && + item != EMPTY_NO) { + pos[0] += -2.0f; + pos[1] += 17.0f; + } else if (((item != EMPTY_NO && !(item >= RSV_CLOTH && item <= RSV_CLOTH7) && + !(item >= ITM_MY_ORG_UMBRELLA0 && item <= ITM_MY_ORG_UMBRELLA7)) || + mMl_check_not_used_mail(&hand_ovl->info.mail) == FALSE) && + table_type != mTG_TABLE_CPMAIL_WC && table_type != mTG_TABLE_CPORIGINAL_WC) { + pos[0] += -5.0f; + pos[1] += 12.0f; + } +} + +static void mHD_hand_position_move(Submenu* submenu) { + mHD_Ovl_c* hand_ovl = submenu->overlay->hand_ovl; + mTG_tag_c* tag = &submenu->overlay->tag_ovl->tags[0]; + int table_idx = submenu->overlay->tag_ovl->get_table_idx_proc(tag); + f32 pos[2]; + f32 dX; + f32 dY; + f32 rate; + + if (hand_ovl->info.move_flag == mHD_MOVE_SWITCH_LEFT) { + pos[0] = -160.0f; + pos[1] = hand_ovl->info.pos[1]; + rate = 1.0f; + } else if (hand_ovl->info.move_flag == mHD_MOVE_SWITCH_RIGHT) { + pos[0] = 160.0f; + pos[1] = hand_ovl->info.pos[1]; + rate = 1.0f; + } else { + mHD_hand_pos_get(submenu, pos, tag->table, table_idx, hand_ovl); + rate = 0.5f; + } + + dX = pos[0] - hand_ovl->info.pos[0]; + dY = pos[1] - hand_ovl->info.pos[1]; + + if (fabsf(dX) > 0.01f || fabsf(dY) > 0.01f) { + f32 dist = sqrtf(dX * dX + dY * dY); + f32 dist2 = dist; + f32 rate_speed = sqrtf(1.0f - rate); + s16 p0 = (GETREG(UREG, 19)); + s16 p1 = (GETREG(UREG, 20)); + f32 calc = add_calc(&dist2, 0.0f, 1.0f - rate_speed, (12.0f + p0 * 0.1f) * 0.5f, (1.0f + p1 * 0.1f) * 0.5f); + + if (fabsf(calc) < 0.1f) { + if (hand_ovl->info.move_flag == mHD_MOVE_SWITCH_LEFT) { + submenu->overlay->tag_ovl->set_hand_pos_proc(submenu, hand_ovl->info.pos, tag->table, table_idx); + hand_ovl->info.pos[0] = 160.0f; + hand_ovl->info.move_flag = mHD_MOVE_NORMAL; + } else if (hand_ovl->info.move_flag == mHD_MOVE_SWITCH_RIGHT) { + submenu->overlay->tag_ovl->set_hand_pos_proc(submenu, hand_ovl->info.pos, tag->table, table_idx); + hand_ovl->info.pos[0] = -160.0f; + hand_ovl->info.move_flag = mHD_MOVE_NORMAL; + } else { + hand_ovl->info.pos[0] = pos[0]; + hand_ovl->info.pos[1] = pos[1]; + hand_ovl->info.move_flag = mHD_MOVE_NONE; + } + } else { + f32 percent; + + if (hand_ovl->info.move_flag == mHD_MOVE_NONE) { + hand_ovl->info.move_flag = mHD_MOVE_NORMAL; + } + + percent = fabsf(dist - dist2) / dist; + hand_ovl->info.pos[0] += dX * percent; + hand_ovl->info.pos[1] += dY * percent; + } + } else { + hand_ovl->info.move_flag = mHD_MOVE_NONE; + } +} + +static void mHD_drop_item(Submenu* submenu, mTG_tag_c* tag, mActor_name_t* item, Mail_c* mail) { + Submenu_Overlay_c* overlay = submenu->overlay; + mHD_Ovl_c* hand_ovl = submenu->overlay->hand_ovl; + mSM_MenuInfo_c* menu_info = &submenu->overlay->menu_info[submenu->menu_type]; + int table; + int table_idx = submenu->overlay->tag_ovl->get_table_idx_proc(&submenu->overlay->tag_ovl->tags[0]); + mActor_name_t now_item; + + if (hand_ovl->info.ret_flag) { + table = hand_ovl->info.hold_tbl; + table_idx = hand_ovl->info.hold_idx; + } else { + table = tag->table; + } + + if (item != NULL && *item != EMPTY_NO && table != mTG_TABLE_GBA_NW2 && table != mTG_TABLE_GBA_NW) { + now_item = *item; + mTG_mark_mainX(submenu, menu_info, table, table_idx, 2, 0); + + /* Duplicate check */ + if ((table != mTG_TABLE_NEEDLEWORK || table != mTG_TABLE_NEEDLEWORK || + (hand_ovl->info.item != EMPTY_NO && !(hand_ovl->info.item >= 0xFE31 && hand_ovl->info.item <= 0xFE38) && + !(hand_ovl->info.item >= 0xFE39 && hand_ovl->info.item <= 0xFE98) && + !(hand_ovl->info.item >= 0xFE99 && hand_ovl->info.item <= 0xFEA0))) && + table != mTG_TABLE_CPORIGINAL && table != mTG_TABLE_CPORIGINAL_NW && table != mTG_TABLE_CARD && + table != mTG_TABLE_GBA) { + *item = hand_ovl->info.item; + } + + if (!(now_item >= RSV_CLOTH && now_item <= RSV_CLOTH7) && + !(now_item >= ITM_MY_ORG_UMBRELLA0 && now_item <= ITM_MY_ORG_UMBRELLA7) && + !(*item >= 0xFE99 && *item <= 0xFEA0)) { + if (table != mTG_TABLE_PLAYER && table != mTG_TABLE_BG && + (table != mTG_TABLE_NEEDLEWORK || + (table == mTG_TABLE_NEEDLEWORK && + (*item == EMPTY_NO || (*item >= 0xFE31 && *item <= 0xFE38) || (*item >= 0xFE39 && *item <= 0xFE98) || + (*item >= 0xFE99 && *item <= 0xFEA0))))) { + switch (table) { + case mTG_TABLE_NEEDLEWORK: + case mTG_TABLE_CPORIGINAL: + case mTG_TABLE_CPORIGINAL_NW: { + if ((*item == EMPTY_NO || + ((*item >= 0xFE31 && *item <= 0xFE38) || (*item >= 0xFE39 && *item <= 0xFE98) || + (*item >= 0xFE99 && *item <= 0xFEA0)))) { + mCO_swap_image(submenu, hand_ovl->info.item, *item); + } else { + hand_ovl->info.item = now_item; + } + break; + } + default: { + hand_ovl->info.item = now_item; + } + } + + hand_ovl->info.next_act = mHD_ACTION_CLOSE; + sAdo_SysTrgStart(NA_SE_41C); + + if (mail != NULL) { + if (mail->content.font == mMl_FONT_0) { + mail->content.font = mMl_FONT_3; + hand_ovl->info.item_cond = mPr_ITEM_COND_PRESENT; + } else if (mail->content.font == mMl_FONT_2) { + mail->content.font = mMl_FONT_4; + hand_ovl->info.item_cond = mPr_ITEM_COND_PRESENT; + } + } + } else { + int set_item = FALSE; + + hand_ovl->info.item = EMPTY_NO; + hand_ovl->info.item_cond = mPr_ITEM_COND_NORMAL; + hand_ovl->info.move_flag = mHD_MOVE_NORMAL; + hand_ovl->info.next_act = mHD_ACTION_SASU; + + if (hand_ovl->info.hold_tbl == mTG_TABLE_ITEM) { + if (Now_Private->inventory.pockets[hand_ovl->info.hold_idx] == EMPTY_NO) { + mPr_SetPossessionItem(Now_Private, hand_ovl->info.hold_idx, now_item, mPr_ITEM_COND_NORMAL); + set_item = TRUE; + } + } else if (hand_ovl->info.hold_tbl == mTG_TABLE_MAIL) { + if (Now_Private->mail[hand_ovl->info.hold_idx].present == EMPTY_NO) { + Now_Private->mail[hand_ovl->info.hold_idx].present = now_item; + set_item = TRUE; + } + } + + if (set_item == FALSE) { + int idx = mPr_GetPossessionItemIdx(Now_Private, EMPTY_NO); + + if (idx >= 0) { + mPr_SetPossessionItem(Now_Private, idx, now_item, mPr_ITEM_COND_NORMAL); + } else { + /* No free inventory spots so put it back in the hand */ + hand_ovl->info.item = now_item; + hand_ovl->info.next_act = mHD_ACTION_CLOSE; + } + } + + if (table == mTG_TABLE_BG) { + if (hand_ovl->info.item == EMPTY_NO) { + sAdo_SysTrgStart(NA_SE_60); + } else { + sAdo_SysTrgStart(NA_SE_41C); + } + } + } + } else { + hand_ovl->info.item = EMPTY_NO; + hand_ovl->info.next_act = mHD_ACTION_SASU; + hand_ovl->info.move_flag = mHD_MOVE_NORMAL; + } + } else { + mSM_MenuInfo_c* menu_info = &submenu->overlay->menu_info[submenu->menu_type]; + + mTG_mark_mainX(submenu, menu_info, table, table_idx, 2, 0); + + if (table == mTG_TABLE_GBA_NW || table == mTG_TABLE_GBA_NW2) { + mGB_copy_image(submenu, hand_ovl->info.item, *item); + } else if (item != NULL) { + *item = hand_ovl->info.item; + + if (mail != NULL) { + if (mail->content.font == mMl_FONT_0) { + mail->content.font = mMl_FONT_3; + } else if (mail->content.font == mMl_FONT_2) { + mail->content.font = mMl_FONT_4; + } + } + } + + hand_ovl->info.item = EMPTY_NO; + hand_ovl->info.item_cond = mPr_ITEM_COND_NORMAL; + hand_ovl->info.move_flag = mHD_MOVE_NORMAL; + hand_ovl->info.next_act = mHD_ACTION_SASU; + + if (table != mTG_TABLE_PLAYER) { + if (menu_info->menu_type == mSM_OVL_INVENTORY && menu_info->data0 == mSM_IV_OPEN_EXCHANGE) { + submenu->overlay->tag_ovl->exchange_proc(submenu, menu_info); + } else { + sAdo_SysTrgStart(NA_SE_60); + } + } + } + + submenu->overlay->tag_ovl->init_tag_data_item_win_proc(submenu); + + if (overlay->segment._04 == 1) { + overlay->segment._08 = 0; + } +} + +#define mHD_TICKET_MONTH(item) (1 + (((item) >> 3) & 0xF)) +#define mHD_TICKET_COUNT(item) ((item) & 7) + +static void mHD_prepare_drop_ticket(mHD_Ovl_c* hand_ovl, mActor_name_t* item, int idx) { + u32 cond = hand_ovl->info.item_cond; + + /* Both are ITEM1 type */ + if (ITEM_IS_ITEM1(hand_ovl->info.item) && ITEM_IS_ITEM1(*item)) { + /* both are tickets */ + if (ITEM_NAME_GET_CAT(hand_ovl->info.item) == ITEM1_CAT_TICKET && + ITEM_NAME_GET_CAT(*item) == ITEM1_CAT_TICKET) { + /* @BUG - only the hand item has a condition */ + if (cond == mPr_ITEM_COND_NORMAL && cond == mPr_ITEM_COND_NORMAL) { + /* from same month */ + int month = mHD_TICKET_MONTH(hand_ovl->info.item); + if (month == mHD_TICKET_MONTH(*item)) { + int held_num = mHD_TICKET_COUNT(hand_ovl->info.item) + 1; + int target_num = mHD_TICKET_COUNT(*item) + 1; + + /* no max stack tickets */ + if (held_num != TICKET_STACK_MAX && target_num != TICKET_STACK_MAX) { + int total = held_num + target_num; + int new_total = total - TICKET_STACK_MAX; + + if (new_total > 0) { + /* Stack went over max */ + Now_Private->inventory.pockets[idx] = + ITM_TICKET_START | ((month - 1) << 3) | (new_total - 1); + hand_ovl->info.item = ITM_TICKET_START | ((month - 1) << 3) | (TICKET_STACK_MAX - 1); + } else { + Now_Private->inventory.pockets[idx] = EMPTY_NO; + hand_ovl->info.item = ITM_TICKET_START | ((month - 1) << 3) | (total - 1); + } + } + } + } + } + } +} + +#define mHD_WISP2NUM(wisp) (1 + wisp - ITM_SPIRIT0) +static void mHD_prepare_drop_wisp(mHD_Ovl_c* hand_ovl, mActor_name_t* item, int idx) { + u32 cond = hand_ovl->info.item_cond; + + /* Held item must be a spirit */ + if (ITEM_IS_WISP(hand_ovl->info.item)) { + /* Target item must be a spirit */ + if (ITEM_IS_WISP(*item)) { + /* Held item must not have any condition */ + if (cond == mPr_ITEM_COND_NORMAL && cond == mPr_ITEM_COND_NORMAL) { + int held_num = ITEM_IS_WISP(hand_ovl->info.item) ? mHD_WISP2NUM(hand_ovl->info.item) : 0; + int target_num = ITEM_IS_WISP(*item) ? mHD_WISP2NUM(*item) : 0; + + if (held_num != WISP_STACK_MAX && target_num != WISP_STACK_MAX) { + int total = held_num + target_num; + int new_total = total - WISP_STACK_MAX; + + if (new_total > 0) { + Now_Private->inventory.pockets[idx] = ITM_SPIRIT0 + (new_total - 1); + hand_ovl->info.item = ITM_SPIRIT4; /* 5 in hand */ + } else { + Now_Private->inventory.pockets[idx] = EMPTY_NO; + hand_ovl->info.item = ITM_SPIRIT0 + (total - 1); + } + } + } + } + } +} + +static void mHD_prepare_drop_paper(mHD_Ovl_c* hand_ovl, mActor_name_t* item, int idx) { + u32 cond = hand_ovl->info.item_cond; + int type; + + /* Held item must be stationery */ + if (ITEM_IS_PAPER(hand_ovl->info.item)) { + /* Target item must be stationery */ + if (ITEM_IS_PAPER(*item)) { + int paper_idx = hand_ovl->info.item - ITM_PAPER_START; + int paper_idx2 = *item - ITM_PAPER_START; + + type = PAPER2TYPE(paper_idx); + + /* Stationery must be the same type */ + if (type == PAPER2TYPE(paper_idx2)) { + /* Held item must not have any condition */ + if (cond == mPr_ITEM_COND_NORMAL && cond == mPr_ITEM_COND_NORMAL) { + int held_num = 1 + PAPER2STACK(paper_idx); + int target_num = 1 + PAPER2STACK(paper_idx2); + + if (held_num != PAPER_STACK_MAX && target_num != PAPER_STACK_MAX) { + int total = held_num + target_num; + int new_total = total - PAPER_STACK_MAX; + + if (new_total > 0) { + Now_Private->inventory.pockets[idx] = + ITM_PAPER_START + type + (new_total - 1) * PAPER_UNIQUE_NUM; + hand_ovl->info.item = ITM_PAPER_STACK_FOUR_START + type; /* 4 stack in hand */ + } else { + Now_Private->inventory.pockets[idx] = EMPTY_NO; + hand_ovl->info.item = ITM_PAPER_START + type + (total - 1) * PAPER_UNIQUE_NUM; + } + } + } + } + } + } +} + +static void mHD_drop_item2(Submenu* submenu, mTG_tag_c* tag, mActor_name_t* item, int idx) { + mHD_Ovl_c* hand_ovl = submenu->overlay->hand_ovl; + int cond = hand_ovl->info.item_cond; + + if (*item != EMPTY_NO) { + hand_ovl->info.item_cond = mPr_GET_ITEM_COND(Now_Private->inventory.item_conditions, idx); + } else { + hand_ovl->info.item_cond = mPr_ITEM_COND_NORMAL; + } + + Now_Private->inventory.item_conditions = mPr_SET_ITEM_COND(Now_Private->inventory.item_conditions, idx, cond); + mHD_prepare_drop_ticket(hand_ovl, item, idx); + mHD_prepare_drop_wisp(hand_ovl, item, idx); + mHD_prepare_drop_paper(hand_ovl, item, idx); + mHD_drop_item(submenu, tag, item, NULL); +} + +static void mHD_open_sack(Submenu* submenu) { + static int sack_amount[] = { 1000, 10000, 30000, 100 }; + mHD_Ovl_c* hand_ovl = submenu->overlay->hand_ovl; + int amount = sack_amount[hand_ovl->info.item - ITM_MONEY_START]; + + hand_ovl->info.item = EMPTY_NO; + Now_Private->inventory.wallet += amount; + hand_ovl->info.move_flag = mHD_MOVE_NORMAL; + hand_ovl->info.next_act = mHD_ACTION_SASU; + hand_ovl->info.wait_timer = 42; + sAdo_SysTrgStart(MONO(NA_SE_52)); + submenu->overlay->inventory_ovl->disp_money_change_frames = amount / 42; +} + +static void mHD_drop_mail(Submenu* submenu, Mail_c* mail) { + mHD_Ovl_c* hand_ovl = submenu->overlay->hand_ovl; + + if (mMl_check_not_used_mail(mail) == TRUE) { + mMl_copy_mail(mail, &hand_ovl->info.mail); + mMl_clear_mail(&hand_ovl->info.mail); + hand_ovl->info.move_flag = mHD_MOVE_NORMAL; + hand_ovl->info.next_act = mHD_ACTION_SASU; + sAdo_SysTrgStart(NA_SE_60); + } else { + Mail_c tmp_mail; + + mTG_mark_main(submenu, &submenu->overlay->menu_info[submenu->menu_type], 2, 0); + mMl_copy_mail(&tmp_mail, mail); + mMl_copy_mail(mail, &hand_ovl->info.mail); + mMl_copy_mail(&hand_ovl->info.mail, &tmp_mail); + hand_ovl->info.next_act = mHD_ACTION_CLOSE; + sAdo_SysTrgStart(NA_SE_41C); + } + + submenu->overlay->tag_ovl->init_tag_data_item_win_proc(submenu); +} + +static void mHD_change_iv_back_segment(void) { + GAME_PLAY* play = (GAME_PLAY*)gamePT; + int idx = ITEM_IS_CLOTH(Now_Private->backgound_texture) ? (Now_Private->backgound_texture - ITM_CLOTH_START) : 0; + + play->submenu_ground_idx ^= 1; + mPlib_Load_PlayerTexAndPallet(play->submenu_ground_tex[play->submenu_ground_idx], + play->submenu_ground_pallet[play->submenu_ground_idx], idx); +} + +static void mHD_open_end_proc_item_type0(Submenu* submenu, int idx, int table) { + mHD_Ovl_c* hand_ovl = submenu->overlay->hand_ovl; + mTG_tag_c* tag = &submenu->overlay->tag_ovl->tags[0]; + + mQst_CheckPutItem(hand_ovl->info.item, idx); + mHD_drop_item2(submenu, tag, &Now_Private->inventory.pockets[idx], idx); +} + +static void mHD_open_end_proc_item_type1(Submenu* submenu, int idx, int table) { + mHD_Ovl_c* hand_ovl = submenu->overlay->hand_ovl; + mTG_tag_c* tag = &submenu->overlay->tag_ovl->tags[0]; + + mHD_drop_item(submenu, tag, &Now_Private->mail[idx].present, &Now_Private->mail[idx]); +} + +static void mHD_open_end_proc_item_type2(Submenu* submenu, int idx, int table) { + mHD_open_sack(submenu); +} + +static void mHD_open_end_proc_item_type3(Submenu* submenu, int idx, int table) { + u16 cloth_idx; + mPr_cloth_c* cloth_p; + mHD_Ovl_c* hand_ovl = submenu->overlay->hand_ovl; + mTG_tag_c* tag = &submenu->overlay->tag_ovl->tags[0]; + mActor_name_t item = hand_ovl->info.item; + int category = ITEM_NAME_GET_CAT(item); + + if (item == RSV_CLOTH || ITEM_IS_CLOTH(item)) { + if (cKF_FrameControl_passCheck_now(&submenu->overlay->inventory_ovl->player_keyframe0.frame_control, 36.0f)) { + cloth_p = &Now_Private->cloth; + + mHD_drop_item(submenu, tag, &cloth_p->item, NULL); + if (cloth_p->item == RSV_CLOTH) { + cloth_idx = 0x100 + mNW_get_image_no(submenu, submenu->overlay->tag_ovl->get_table_idx_proc(tag)); + } else { + cloth_idx = ITEM_IS_CLOTH(cloth_p->item) ? (cloth_p->item - ITM_CLOTH_START) : 0; + } + + cloth_p->idx = cloth_idx; + mPlib_change_player_cloth(gamePT, Now_Private->cloth.idx); + } + } else if (category == ITEM1_CAT_FRUIT) { + submenu->overlay->inventory_ovl->food_idx = (u8)(item - ITM_FOOD_START); + mHD_drop_item(submenu, tag, NULL, NULL); + } else if (category == ITEM1_CAT_KABU) { + submenu->overlay->inventory_ovl->food_idx = 8; // TODO: needs enum + mHD_drop_item(submenu, tag, NULL, NULL); + } else { + mHD_drop_item(submenu, tag, &Now_Private->equipment, NULL); + } +} + +static void mHD_open_end_proc_item_type4(Submenu* submenu, int idx, int table) { + mHD_Ovl_c* hand_ovl = submenu->overlay->hand_ovl; + mTG_tag_c* tag = &submenu->overlay->tag_ovl->tags[0]; + + mPr_SetItemCollectBit(Now_Private->backgound_texture); + mHD_drop_item(submenu, tag, &Now_Private->backgound_texture, NULL); + mHD_change_iv_back_segment(); +} + +static void mHD_open_end_proc_item_type6(Submenu* submenu, int idx, int table) { + mHD_Ovl_c* hand_ovl = submenu->overlay->hand_ovl; + mTG_tag_c* tag = &submenu->overlay->tag_ovl->tags[0]; + mSM_MenuInfo_c* menu_info = &submenu->overlay->menu_info[submenu->menu_type]; + int flag; + + if (hand_ovl->info.ret_flag) { + flag = FALSE; + } else { + flag = TRUE; + } + + mHD_drop_item(submenu, tag, &Save_Get(homes[menu_info->data1]).haniwa.items[idx].item, NULL); + if (flag == TRUE) { + submenu->overlay->tag_ovl->item_name_wait_time = 0; + submenu->overlay->tag_ovl->chg_tag_func_proc(submenu, tag->table, mTG_TYPE_HANIWA_PUT_ITEM, 0, tag->pos[0], + tag->pos[1]); + } +} + +static void mHD_open_end_proc_item_type17(Submenu* submenu, int idx, int table) { + mTG_tag_c* tag = &submenu->overlay->tag_ovl->tags[0]; + mHD_Ovl_c* hand_ovl = submenu->overlay->hand_ovl; + int folder; + mActor_name_t tmp_item; + mActor_name_t hand_item; + mActor_name_t cur_item; + + if (ITEM_IS_RSVNWORG(hand_ovl->info.item) || ITEM_IS_RSVCPORG(hand_ovl->info.item) || + ITEM_IS_RSVGBAORG(hand_ovl->info.item)) { + switch (table) { + case mTG_TABLE_NEEDLEWORK: + case mTG_TABLE_CPORIGINAL_NW: + if (mNW_check_hide_flg(submenu, idx)) { + tmp_item = EMPTY_NO; + } else { + tmp_item = RSV_NW_ORIGINAL0 + idx; + } + break; + case mTG_TABLE_GBA_NW: + case mTG_TABLE_GBA_NW2: + tmp_item = RSV_NW_ORIGINAL0 + idx; + break; + case mTG_TABLE_CPORIGINAL: + folder = mCO_top_folder(submenu); + + if (mCO_check_hide_flg(submenu, folder, idx)) { + tmp_item = EMPTY_NO; + } else { + tmp_item = RSV_CPORIGINAL_FLD0_00 + folder * 12 + idx; + } + break; + case mTG_TABLE_GBA: + case mTG_TABLE_CARD: + tmp_item = EMPTY_NO; + break; + } + + hand_item = hand_ovl->info.item; + cur_item = tmp_item; + + mHD_drop_item(submenu, tag, &tmp_item, NULL); + + if (hand_item == tmp_item && cur_item == hand_ovl->info.item) { + if (tmp_item == EMPTY_NO) { + if (table == mTG_TABLE_CPORIGINAL) { + mCO_on_hide_flg(submenu, folder, idx); + } else { + mNW_on_hide_flg(submenu, idx); + } + } + + if (hand_ovl->info.item == EMPTY_NO) { + if (table == mTG_TABLE_CPORIGINAL) { + mCO_clear_hide_flg(submenu); + } else { + mNW_clear_hide_flg(submenu); + } + + submenu->overlay->tag_ovl->init_tag_data_item_win_proc(submenu); + } + } + } +} + +typedef void (*mHD_OPEN_END_PROC)(Submenu*, int, int); + +static void mHD_open_end_proc_item(Submenu* submenu) { + static mHD_OPEN_END_PROC proc_table[] = { + &mHD_open_end_proc_item_type0, /* mTG_TABLE_ITEM */ + &mHD_open_end_proc_item_type1, /* mTG_TABLE_MAIL */ + &mHD_open_end_proc_item_type2, /* mTG_TABLE_MONEY */ + &mHD_open_end_proc_item_type3, /* mTG_TABLE_PLAYER */ + &mHD_open_end_proc_item_type4, /* mTG_TABLE_BG */ + (mHD_OPEN_END_PROC)&none_proc1, /* mTG_TABLE_MBOX */ + &mHD_open_end_proc_item_type6, /* mTG_TABLE_HANIWA */ + (mHD_OPEN_END_PROC)&none_proc1, /* mTG_TABLE_COLLECT */ + (mHD_OPEN_END_PROC)&none_proc1, /* mTG_TABLE_WCHANGE */ + (mHD_OPEN_END_PROC)&none_proc1, /* mTG_TABLE_CPMAIL */ + (mHD_OPEN_END_PROC)&none_proc1, /* mTG_TABLE_CPMAIL_WC */ + (mHD_OPEN_END_PROC)&none_proc1, /* mTG_TABLE_CPMAIL_TI */ + (mHD_OPEN_END_PROC)&none_proc1, /* mTG_TABLE_CPEDIT */ + (mHD_OPEN_END_PROC)&none_proc1, /* mTG_TABLE_CPEDIT_END */ + (mHD_OPEN_END_PROC)&none_proc1, /* mTG_TABLE_CATALOG */ + (mHD_OPEN_END_PROC)&none_proc1, /* mTG_TABLE_CATALOG_WC */ + (mHD_OPEN_END_PROC)&none_proc1, /* mTG_TABLE_MUSIC_MAIN */ + &mHD_open_end_proc_item_type17, /* mTG_TABLE_NEEDLEWORK */ + &mHD_open_end_proc_item_type17, /* mTG_TABLE_CPORIGINAL */ + (mHD_OPEN_END_PROC)&none_proc1, /* mTG_TABLE_INVENTORY_WC_ORG */ + &mHD_open_end_proc_item_type17, /* mTG_TABLE_CPORIGINAL_NW */ + (mHD_OPEN_END_PROC)&none_proc1, /* mTG_TABLE_CPORIGINAL_WC */ + (mHD_OPEN_END_PROC)&none_proc1, /* mTG_TABLE_CPORIGINAL_TI */ + &mHD_open_end_proc_item_type17, /* mTG_TABLE_GBA */ + &mHD_open_end_proc_item_type17, /* mTG_TABLE_GBA_NW */ + &mHD_open_end_proc_item_type17, /* mTG_TABLE_CARD */ + &mHD_open_end_proc_item_type17, /* mTG_TABLE_GBA_NW2 */ + }; + + mSM_MenuInfo_c* menu_info; + mHD_Ovl_c* hand_ovl = submenu->overlay->hand_ovl; + mTG_tag_c* tag = &submenu->overlay->tag_ovl->tags[0]; + int idx; + int table; + + if (hand_ovl->info.ret_flag) { + table = hand_ovl->info.hold_tbl; + idx = hand_ovl->info.hold_idx; + } else { + table = tag->table; + idx = submenu->overlay->tag_ovl->get_table_idx_proc(tag); + } + + if (hand_ovl->info.item_cond == mPr_ITEM_COND_NORMAL) { + mPr_SetItemCollectBit(hand_ovl->info.item); + } + + (*proc_table[table])(submenu, idx, table); + + if (table == mTG_TABLE_HANIWA) { + s16 tmp_cond = hand_ovl->info.haniwa_item_cond; + u32 tmp_price = hand_ovl->info.haniwa_item_price; + + menu_info = &submenu->overlay->menu_info[submenu->menu_type]; + hand_ovl->info.haniwa_item_cond = Save_Get(homes[menu_info->data1]).haniwa.items[idx].exchange_type; + hand_ovl->info.haniwa_item_price = Save_Get(homes[menu_info->data1]).haniwa.items[idx].extra_data; + Save_Get(homes[menu_info->data1]).haniwa.items[idx].exchange_type = tmp_cond; + Save_Get(homes[menu_info->data1]).haniwa.items[idx].extra_data = tmp_price; + } else { + hand_ovl->info.haniwa_item_cond = mHm_HANIWA_TRADE_1; + hand_ovl->info.haniwa_item_price = 0; + } +} + +static void mHD_open_end_proc_mail(Submenu* submenu) { + mHD_Ovl_c* hand_ovl = submenu->overlay->hand_ovl; + Mail_c* mail; + + if (hand_ovl->info.ret_flag) { + mail = submenu->overlay->tag_ovl->get_mail_pointer_proc(submenu, hand_ovl); + } else { + mail = submenu->overlay->tag_ovl->get_mail_pointer_proc(submenu, NULL); + } + + mHD_drop_mail(submenu, mail); +} + +static void mHD_open_end_proc(Submenu* submenu) { + mHD_Ovl_c* hand_ovl = submenu->overlay->hand_ovl; + + if (hand_ovl->info.item != EMPTY_NO) { + mHD_open_end_proc_item(submenu); + } else if (mMl_check_not_used_mail(&hand_ovl->info.mail) != TRUE) { + mHD_open_end_proc_mail(submenu); + } + + hand_ovl->info.ret_flag = FALSE; +} + +static void mHD_close_move(Submenu* submenu) { + mHD_Ovl_c* hand_ovl = submenu->overlay->hand_ovl; + + if (hand_ovl->info.keyframe_state == cKF_STATE_STOPPED) { + hand_ovl->info.move_flag = mHD_MOVE_NORMAL; + hand_ovl->info.next_act = mHD_ACTION_CLOSE_KEEP; + } +} + +static void mHD_open_move(Submenu* submenu) { + mHD_Ovl_c* hand_ovl = submenu->overlay->hand_ovl; + mTG_tag_c* tag = &submenu->overlay->tag_ovl->tags[0]; + + if (hand_ovl->info.keyframe_state == cKF_STATE_STOPPED) { + switch (tag->table) { + case mTG_TABLE_CPMAIL_WC: + case mTG_TABLE_CPORIGINAL_WC: + hand_ovl->info.next_act = mHD_ACTION_SASU; + hand_ovl->info.move_flag = mHD_MOVE_NORMAL; + break; + default: + mHD_open_end_proc(submenu); + break; + } + } else if (hand_ovl->info.ret_flag) { + switch (tag->table) { + case mTG_TABLE_CPMAIL_WC: + case mTG_TABLE_CPORIGINAL_WC: + mHD_open_end_proc(submenu); + break; + default: + break; + } + } +} + +static void mHD_sasu2_move(Submenu* submenu) { + mHD_Ovl_c* hand_ovl = submenu->overlay->hand_ovl; + mTG_tag_c* tag = &submenu->overlay->tag_ovl->tags[0]; + int category = ITEM_NAME_GET_CAT(hand_ovl->info.item); + + if (hand_ovl->info.item == RSV_CLOTH || ITEM_IS_CLOTH(hand_ovl->info.item)) { + if (cKF_FrameControl_passCheck_now(&submenu->overlay->inventory_ovl->player_keyframe0.frame_control, 36.0f)) { + mPr_cloth_c* cloth_p = &Now_Private->cloth; + u16 cloth_idx; + + mHD_drop_item(submenu, tag, &cloth_p->item, NULL); + if (cloth_p->item == RSV_CLOTH) { + cloth_idx = 0x100 + mNW_get_image_no(submenu, submenu->overlay->tag_ovl->get_table_idx_proc(tag)); + } else { + cloth_idx = ITEM_IS_CLOTH(cloth_p->item) ? (cloth_p->item - ITM_CLOTH_START) : 0; + } + + cloth_p->idx = cloth_idx; + mPlib_change_player_cloth(gamePT, Now_Private->cloth.idx); + hand_ovl->info.next_act = mHD_ACTION_SASU; + hand_ovl->info.move_flag = mHD_MOVE_NORMAL; + } + } else if (category == ITEM1_CAT_FRUIT) { + // nothing + } else if (category == ITEM1_CAT_KABU) { + // nothing + } else { + if (hand_ovl->info.wait_timer <= 0) { + mHD_drop_item(submenu, tag, &Now_Private->equipment, NULL); + hand_ovl->info.next_act = mHD_ACTION_SASU; + hand_ovl->info.move_flag = mHD_MOVE_NORMAL; + } + } +} + +typedef void (*mHD_OVL_MOVE_PROC)(Submenu*); + +static void mHD_hand_ovl_move(Submenu* submenu) { + static mHD_OVL_MOVE_PROC process[mHD_ACTION_NUM] = { + (mHD_OVL_MOVE_PROC)&none_proc1, + (mHD_OVL_MOVE_PROC)&none_proc1, + &mHD_close_move, + (mHD_OVL_MOVE_PROC)&none_proc1, + &mHD_open_move, + &mHD_close_move, + &mHD_sasu2_move, + }; + + mHD_Ovl_c* hand_ovl = submenu->overlay->hand_ovl; + + if (hand_ovl->info.type != 0) { + mHD_hand_shape_move(submenu); + mHD_hand_position_move(submenu); + mHD_calc_hand_offset(submenu); + + (*process[hand_ovl->info.act])(submenu); + if (hand_ovl->info.act != hand_ovl->info.next_act) { + hand_ovl->info.act = hand_ovl->info.next_act; + mHD_set_anime(submenu, &hand_ovl->info.keyframe); + } + } +} + +extern Gfx inv_item_shadow_mode[]; +extern Gfx inv_item_mode[]; + +static void mHD_draw_item(Submenu* submenu, GRAPH* graph, f32* pos) { + mHD_Ovl_c* hand_ovl = submenu->overlay->hand_ovl; + + if (hand_ovl->info.item != EMPTY_NO && + (!ITEM_IS_RSVCLOTH(hand_ovl->info.item) && + !(hand_ovl->info.item >= ITM_MY_ORG_UMBRELLA0 && hand_ovl->info.item <= ITM_MY_ORG_UMBRELLA7) && + !ITEM_IS_RSVNWORG(hand_ovl->info.item) && /* Needlework designs */ + !ITEM_IS_RSVCPORG(hand_ovl->info.item) && /* Stored original designs */ + !ITEM_IS_RSVGBAORG(hand_ovl->info.item) /* GBA designs */ + )) { + int present_flag = hand_ovl->info.item_cond & mPr_ITEM_COND_PRESENT; + Gfx* gfx; + + /* Draw item shadow */ + OPEN_DISP(graph); + gfx = NOW_POLY_OPA_DISP; + gSPDisplayList(gfx++, inv_item_shadow_mode); + SET_POLY_OPA_DISP(gfx); + CLOSE_DISP(graph); + submenu->overlay->draw_item_proc(graph, pos[0] + 4.0f, pos[1] - 4.0f, 1.0f, hand_ovl->info.item, present_flag, + TRUE, 0, TRUE, FALSE); + + /* Draw item icon */ + OPEN_DISP(graph); + gfx = NOW_POLY_OPA_DISP; + gSPDisplayList(gfx++, inv_item_mode); + SET_POLY_OPA_DISP(gfx); + CLOSE_DISP(graph); + submenu->overlay->draw_item_proc(graph, pos[0], pos[1], 1.0f, hand_ovl->info.item, present_flag, TRUE, 0, FALSE, + FALSE); + } +} + +static void mHD_draw_mail(Submenu* submenu, GRAPH* graph, f32* pos) { + mHD_Ovl_c* hand_ovl = submenu->overlay->hand_ovl; + Mail_c* mail = &hand_ovl->info.mail; + + if (mMl_check_not_used_mail(mail) != TRUE) { + Gfx* gfx; + + /* Draw item shadow */ + OPEN_DISP(graph); + gfx = NOW_POLY_OPA_DISP; + gSPDisplayList(gfx++, inv_item_shadow_mode); + SET_POLY_OPA_DISP(gfx); + CLOSE_DISP(graph); + submenu->overlay->draw_mail_proc(graph, pos[0] + 4.0f, pos[1] - 4.0f, 1.0f, mail, TRUE, TRUE, FALSE); + + /* Draw item icon */ + OPEN_DISP(graph); + gfx = NOW_POLY_OPA_DISP; + gSPDisplayList(gfx++, inv_item_mode); + SET_POLY_OPA_DISP(gfx); + CLOSE_DISP(graph); + submenu->overlay->draw_mail_proc(graph, pos[0], pos[1], 1.0f, mail, TRUE, FALSE, FALSE); + } +} + +static void mHD_draw_original(Submenu* submenu, GRAPH* graph, f32* pos) { + mHD_Ovl_c* hand_ovl = submenu->overlay->hand_ovl; + + if (ITEM_IS_RSVNWORG(hand_ovl->info.item) || /* Needlework designs */ + ITEM_IS_RSVCPORG(hand_ovl->info.item) || /* Stored original designs */ + ITEM_IS_RSVGBAORG(hand_ovl->info.item) /* GBA designs */ + ) { + Gfx* gfx; + + /* Draw item shadow */ + OPEN_DISP(graph); + gfx = NOW_POLY_OPA_DISP; + gSPDisplayList(gfx++, inv_item_shadow_mode); + SET_POLY_OPA_DISP(gfx); + CLOSE_DISP(graph); + mSM_draw_original(submenu, graph, pos[0] + 4.0f, pos[1] - 4.0f, 1.0f, hand_ovl->info.item, TRUE); + + /* Draw item icon */ + OPEN_DISP(graph); + gfx = NOW_POLY_OPA_DISP; + gSPDisplayList(gfx++, inv_item_mode); + SET_POLY_OPA_DISP(gfx); + CLOSE_DISP(graph); + mSM_draw_original(submenu, graph, pos[0], pos[1], 1.0f, hand_ovl->info.item, FALSE); + } +} + +#define mHD_ROT_X DEG2SHORT_ANGLE(-135.0f) +#define mHD_ROT_Y DEG2SHORT_ANGLE(0.0f) +#define mHD_ROT_Z DEG2SHORT_ANGLE(70.3125f) + +static void mHD_hand_shape_draw(Submenu* submenu, GAME* game, int shadow_flag) { + mHD_Ovl_c* hand_ovl = submenu->overlay->hand_ovl; + GRAPH* graph = game->graph; + Mtx* mtx = (Mtx*)GRAPH_ALLOC_TYPE(graph, Mtx, hand_ovl->info.keyframe.skeleton->num_shown_joints); + + if (mtx != NULL) { + if (shadow_flag) { + Matrix_translate(0.0f, 0.0f, 76.4f, 0); + } else { + Matrix_translate(0.0f, 0.0f, 77.0f, 0); + } + + if (shadow_flag) { + Matrix_scale(0.042f, 0.042f, 0.0f, 1); + } else { + Matrix_scale(0.04f, 0.04f, 0.04f, 1); + } + + Matrix_scale(0.01f, 0.01f, 0.01f, 1); + Matrix_rotateXYZ(mHD_ROT_X, mHD_ROT_Y, mHD_ROT_Z, 1); + + OPEN_DISP(graph); + + gDPPipeSync(NEXT_POLY_OPA_DISP); + gSPMatrix(NEXT_POLY_OPA_DISP, _Matrix_to_Mtx_new(graph), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + _texture_z_light_fog_prim(game->graph); + gDPSetPrimColor(NEXT_POLY_OPA_DISP, 0, 128, 255, 255, 255, 255); + gSPLoadGeometryMode(NEXT_POLY_OPA_DISP, + G_ZBUFFER | G_SHADE | G_CULL_BACK | G_FOG | G_LIGHTING | G_SHADING_SMOOTH); + + if (shadow_flag) { + gSPLoadGeometryMode(NEXT_POLY_OPA_DISP, G_ZBUFFER | G_CULL_BACK | G_FOG); + gDPSetPrimColor(NEXT_POLY_OPA_DISP, 0, 0, 0, 0, 0, 128); + gDPSetRenderMode(NEXT_POLY_OPA_DISP, + AA_EN | Z_CMP | Z_UPD | IM_RD | CLR_ON_CVG | CVG_DST_WRAP | ZMODE_XLU | FORCE_BL | + G_RM_FOG_SHADE_A, + AA_EN | Z_CMP | Z_UPD | IM_RD | CLR_ON_CVG | CVG_DST_WRAP | ZMODE_XLU | FORCE_BL | + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)); + gDPSetCombineLERP(NEXT_POLY_OPA_DISP, 0, 0, 0, PRIMITIVE, 0, 0, 0, 0, 0, 0, 0, COMBINED, 0, 0, 0, + PRIMITIVE); + } + + cKF_Si3_draw_R_SV(game, &hand_ovl->info.keyframe, mtx, NULL, NULL, NULL); + + CLOSE_DISP(graph); + } +} + +static void mHD_hand_ovl_draw(Submenu* submenu, GAME* game) { + mHD_Ovl_c* hand_ovl = submenu->overlay->hand_ovl; + GRAPH* graph = game->graph; + + if (hand_ovl->info.type != 0) { + f32 cos_x = cos_s(mHD_ROT_X); + f32 sin_z = sin_s(mHD_ROT_Z); + f32 cos_z = cos_s(mHD_ROT_Z); + f32 target_pos[2]; + f32 pos[3]; + f32 pos_adj; + mTG_tag_c* tag; + + target_pos[0] = + (hand_ovl->info.pos[0] + hand_ovl->info.ofs[0] * cos_z + hand_ovl->info.ofs[1] * (-cos_x * sin_z)) + 4.0f; + target_pos[1] = + (hand_ovl->info.pos[1] + hand_ovl->info.ofs[0] * sin_z + hand_ovl->info.ofs[1] * (cos_x * cos_z)) - 4.0f; + + /* Draw hand shadow first */ + Matrix_push(); + submenu->overlay->change_view_proc(graph, 80.0f, 0.0f, ((target_pos[0] + 160.0f) - 4.0f - 12.0f) * 4.0f, + (120.0f - target_pos[1] + 4.0f - 20.0f) * 4.0f, 0, 64, 64); + mHD_hand_shape_draw(submenu, game, TRUE); + submenu->overlay->setup_view_proc(submenu, graph, 0); + Matrix_pull(); + + tag = &submenu->overlay->tag_ovl->tags[0]; + target_pos[0] -= 2.5f; + target_pos[1] += 2.5f; + + // is this an xyz_t? + pos[0] = target_pos[0] + (cos_z * -6.9f + 7.0f * (-cos_x * sin_z)); + pos[1] = target_pos[1] + (sin_z * -6.9f + 7.0f * (cos_x * cos_z) - 10.0f); + pos[2] = 0.0f; + + switch (tag->table) { + case mTG_TABLE_CPMAIL: + case mTG_TABLE_CPMAIL_WC: + case mTG_TABLE_CPORIGINAL: + case mTG_TABLE_CPORIGINAL_WC: + if (hand_ovl->info.act == mHD_ACTION_SASU || hand_ovl->info.act == mHD_ACTION_SASU2) { + pos_adj = 1.0f; + } else if (hand_ovl->info.act == mHD_ACTION_CLOSE2 || + (hand_ovl->info.act == mHD_ACTION_OPEN && + (tag->table == mTG_TABLE_CPMAIL_WC || tag->table == mTG_TABLE_CPORIGINAL_WC))) { + pos_adj = 1.0f - hand_ovl->info.keyframe.frame_control.current_frame / + mHD_animeTable[mHD_ACTION_CLOSE].end_frame; + } else { + pos_adj = 0.0f; + } + + pos[0] += pos_adj * 5.0f; + pos[1] += pos_adj * 15.0f; + break; + } + + /* Draw hand items next */ + mHD_draw_item(submenu, graph, pos); + mHD_draw_mail(submenu, graph, pos); + mHD_draw_original(submenu, graph, pos); + + /* Draw hand model last */ + Matrix_push(); + submenu->overlay->change_view_proc(graph, 80.0f, 0.0f, ((target_pos[0] + 160.0f) - 4.0f - 12.0f) * 4.0f, + (120.0f - target_pos[1] + 4.0f - 20.0f) * 4.0f, 0, 64, 64); + mHD_hand_shape_draw(submenu, game, FALSE); + submenu->overlay->setup_view_proc(submenu, graph, 0); + Matrix_pull(); + } +} + +static void mHD_nop_hand_func(Submenu* submenu) { + submenu->overlay->menu_control.hand_move_func = (mSM_HAND_MOVE_FUNC)&none_proc1; + submenu->overlay->menu_control.hand_draw_func = (mSM_HAND_DRAW_FUNC)&none_proc1; +} + +static void mHD_set_hand_func(Submenu* submenu) { + submenu->overlay->menu_control.hand_move_func = &mHD_hand_ovl_move; + submenu->overlay->menu_control.hand_draw_func = &mHD_hand_ovl_draw; +} + +extern void mHD_hand_ovl_construct(Submenu* submenu) { + mSM_MenuInfo_c* menu_info = &submenu->overlay->menu_info[submenu->menu_type]; + Submenu_Overlay_c* overlay = submenu->overlay; + mHD_Ovl_c* hand_ovl; + + if (overlay->hand_ovl != NULL) { + return; + } + + mem_clear((u8*)&hand_ovl_data, sizeof(mHD_Ovl_c), 0); + overlay->menu_control.hand_move_func = &mHD_hand_ovl_move; + overlay->menu_control.hand_draw_func = &mHD_hand_ovl_draw; + overlay->hand_ovl = &hand_ovl_data; + + submenu->overlay->hand_ovl->nop_hand_func = &mHD_nop_hand_func; + submenu->overlay->hand_ovl->set_hand_func = &mHD_set_hand_func; + hand_ovl = &hand_ovl_data; + + hand_ovl->info.type = 0; + hand_ovl->info.move_flag = mHD_MOVE_NONE; + mMl_clear_mail(&hand_ovl->info.mail); + hand_ovl->info.item_cond = mPr_ITEM_COND_NORMAL; + + if (menu_info->menu_type == mSM_OVL_INVENTORY && menu_info->data0 == mSM_IV_OPEN_EXCHANGE) { + mActor_name_t item; + int item_cond; + + switch (menu_info->data1) { + case ITM_PRESENT: + item = mPr_DummyPresentToTruePresent(); + item_cond = mPr_ITEM_COND_PRESENT; + break; + case ITM_GOLDEN_NET_PRESENT: + item = ITM_GOLDEN_NET; + item_cond = mPr_ITEM_COND_PRESENT; + break; + case ITM_GOLDEN_AXE_PRESENT: + item = ITM_GOLDEN_AXE; + item_cond = mPr_ITEM_COND_PRESENT; + break; + case ITM_GOLDEN_SHOVEL_PRESENT: + item = ITM_GOLDEN_SHOVEL; + item_cond = mPr_ITEM_COND_PRESENT; + break; + case ITM_GOLDEN_ROD_PRESENT: + item = ITM_GOLDEN_ROD; + item_cond = mPr_ITEM_COND_PRESENT; + break; + default: + item = (mActor_name_t)menu_info->data1; + item_cond = hand_ovl->info.item_cond; + break; + } + + hand_ovl->info.item = item; + hand_ovl->info.item_cond = item_cond; + hand_ovl->info.act = mHD_ACTION_CLOSE_KEEP; + hand_ovl->info.next_act = mHD_ACTION_CLOSE_KEEP; + } else { + hand_ovl->info.item = EMPTY_NO; + hand_ovl->info.act = mHD_ACTION_SASU; + hand_ovl->info.next_act = mHD_ACTION_SASU; + } + + hand_ovl->info.ofs[0] = mHD_hand_offsetX_table[hand_ovl->info.act]; + hand_ovl->info.ofs[1] = mHD_hand_offsetY_table[hand_ovl->info.act]; + mHD_hand_shape_init(submenu); + mHD_hand_shape_move(submenu); + mHD_set_hand_func(submenu); +} + +extern void mHD_hand_ovl_destruct(Submenu* submenu) { + cKF_SkeletonInfo_R_dt(&submenu->overlay->hand_ovl->info.keyframe); + mHD_nop_hand_func(submenu); + submenu->overlay->hand_ovl = NULL; +}