From 011c898e11ca021e121806cac325904839070513 Mon Sep 17 00:00:00 2001 From: Cuyler36 Date: Thu, 29 Jun 2023 19:24:16 -0400 Subject: [PATCH] Implement & link ac_haniwa.c --- config/rel_slices.yml | 4 + include/ac_haniwa.h | 69 +++ include/ac_intro_demo.h | 20 + include/ac_my_house.h | 23 + include/m_actor.h | 4 +- include/m_bgm.h | 2 + include/m_choice.h | 28 ++ include/m_clip.h | 6 +- include/m_collision_obj.h | 25 + include/m_common_data.h | 4 +- include/m_demo.h | 17 + include/m_field_info.h | 1 + include/m_msg.h | 9 + include/m_name_table.h | 20 + include/m_needlework_ovl.h | 17 + include/m_npc.h | 2 + include/m_player.h | 4 +- include/m_player_lib.h | 3 + include/m_private.h | 8 +- include/m_private_h.h | 16 + include/m_submenu.h | 2 + rel/ac_haniwa.c | 975 +++++++++++++++++++++++++++++++++++++ 22 files changed, 1253 insertions(+), 6 deletions(-) create mode 100644 include/m_choice.h create mode 100644 include/m_needlework_ovl.h create mode 100644 include/m_private_h.h create mode 100644 rel/ac_haniwa.c diff --git a/config/rel_slices.yml b/config/rel_slices.yml index d04b04c9..af9a0653 100644 --- a/config/rel_slices.yml +++ b/config/rel_slices.yml @@ -166,6 +166,10 @@ ac_boxMove.c: ac_boxTrick01.c: .text: [0x80415BF8, 0x80415C04] .data: [0x806818F0, 0x80681918] +ac_haniwa.c: + .text: [0x80427624, 0x80428F64] + .rodata: [0x806440B8, 0x806440F8] + .data: [0x80683D08, 0x80683E98] ac_set_manager.c: .text: [0x80496AB8, 0x80496F50] .rodata: [0x80644DB8, 0x80644DC8] diff --git a/include/ac_haniwa.h b/include/ac_haniwa.h index a46dbfd3..9f873902 100644 --- a/include/ac_haniwa.h +++ b/include/ac_haniwa.h @@ -3,11 +3,80 @@ #include "types.h" #include "m_actor.h" +#include "c_keyframe.h" +#include "m_collision_obj.h" #ifdef __cplusplus extern "C" { #endif +typedef struct actor_haniwa_s HANIWA_ACTOR; + +typedef void (*HANIWA_ACTOR_PROC)(ACTOR*, GAME*); + +enum haniwa_msg { + aHNW_MSG_NO_OWNER, + aHNW_MSG_PROCEEDS, + aHNW_MSG_NORMAL, + aHNW_MSG_OTHER_OWNER, + aHNW_MSG_NEED_FRIEND, + + aHNW_MSG_NUM +}; + +enum haniwa_handover { + aHNW_HANDOVER_YES, + aHNW_HANDOVER_NO, + + aHNW_HANDOVER_NUM +}; + +enum haniwa_action { + aHNW_ACTION_WAIT, + aHNW_ACTION_DANCE, + aHNW_ACTION_CHECK_PROCEEDS, + aHNW_ACTION_TALK_WITH_MASTER, + aHNW_ACTION_TALK_WITH_MASTER2, + aHNW_ACTION_TALK_END_WAIT, + aHNW_ACTION_MENU_OPEN_WAIT, + aHNW_ACTION_MENU_END_WAIT, + aHNW_ACTION_TALK_WITH_GUEST, + aHNW_ACTION_MENU_OPEN_WAIT_FOR_GUEST, + aHNW_ACTION_MENU_END_WAIT_FOR_GUEST, + aHNW_ACTION_ROOF_CHECK, + aHNW_ACTION_SAVE_CHECK, + aHNW_ACTION_SAVE_END_WAIT, + aHNW_ACTION_PL_APPROACH_DOOR, + aHNW_ACTION_DOOR_OPEN_WAIT, + aHNW_ACTION_DOOR_OPEN_TIMER, + + aHNW_ACTION_NUM +}; + +struct actor_haniwa_s { + ACTOR actor_class; + + int saved_current_frame; + int keyframe_state; + + cKF_SkeletonInfo_R_c keyframe; + int animation_state; + + ClObjPipe_c col_pipe; + + int action; + char* bank_ram_start; + s_xyz keyframe_work_area[8]; + s_xyz keyframe_morph_area[8]; + HANIWA_ACTOR_PROC action_proc; + f32 anim_frame_speed; + int player_approach_door_stage; + u16 door_approach_frame; + u8 submenu_type; + u8 house_idx; + u8 playing_save_bgm; +}; + extern ACTOR_PROFILE Haniwa_Profile; #ifdef __cplusplus diff --git a/include/ac_intro_demo.h b/include/ac_intro_demo.h index c61c65c2..1d30cc19 100644 --- a/include/ac_intro_demo.h +++ b/include/ac_intro_demo.h @@ -8,6 +8,26 @@ extern "C" { #endif +typedef struct actor_intor_demo_s INTRO_DEMO_ACTOR; + +struct actor_intor_demo_s { + ACTOR actor_class; + int action; + int rcn_action; + void (*action_proc)(ACTOR*, GAME*); + void* train1_actor_p; // TODO: correct type + void* station_master_actor_p; // TODO: correct type + void* rcn_guide_actor_p; // TODO: correct type + int player_in_intro_demo; + int player_intro_demo_state; + int selected_house; + int _198; + u8 first_field_bgm_state; + int _1A0; + int _1A4; + int _1A8; +}; + extern ACTOR_PROFILE Intro_Demo_Profile; #ifdef __cplusplus diff --git a/include/ac_my_house.h b/include/ac_my_house.h index bd6c485a..cbb272c5 100644 --- a/include/ac_my_house.h +++ b/include/ac_my_house.h @@ -8,6 +8,29 @@ extern "C" { #endif +typedef struct actor_my_house_s MY_HOUSE_ACTOR; + +struct actor_my_house_s { + ACTOR actor_class; + int _174; + cKF_SkeletonInfo_R_c keyframe; + int _1E8; + s_xyz work_area[15]; + s_xyz morph_area[15]; + u8 _2A0[0x2B0 - 0x2A0]; + int door_rotation_speed_idx; + int house_no; + int house_shape; + int _2BC; + int _2C0; + int intro_flag; + f32 door_pos_x; + f32 door_poz_z; + f32 door_rotation_speed; + f32 _2D4; + int season; +}; + extern ACTOR_PROFILE MyHouse_Profile; #ifdef __cplusplus diff --git a/include/m_actor.h b/include/m_actor.h index 100fc2b5..5f419771 100644 --- a/include/m_actor.h +++ b/include/m_actor.h @@ -7,6 +7,8 @@ #include "m_lib.h" #include "m_lights.h" #include "m_collision_bg.h" +#include "m_collision_obj.h" +#include "libforest/gbi_extensions.h" #ifdef __cplusplus extern "C" { @@ -356,7 +358,7 @@ struct actor_s { /* 0x0B8 */ f32 player_distance; /* distance between actor and player actor (squared magnitude) */ /* 0x0BC */ f32 player_distance_xz; /* distance between actor and player actor on XZ plane (magnitude) */ /* 0x0C0 */ f32 player_distance_y; /* distance between actor and player actor on Y plane */ - /* 0x0C4 */ u8 status_data[0xDC-0xC4]; /* TODO: implement, see m_collision_obj */ + /* 0x0C4 */ Status_c status_data; /* collider info, lots of leftover stuff from OoT */ /* 0x0DC */ Shape_Info shape_info; /* 0x124 */ xyz_t camera_position; /* camera position relative to actor position */ /* 0x130 */ f32 camera_w; /* camera projection W value */ diff --git a/include/m_bgm.h b/include/m_bgm.h index 3c783e86..bb33f220 100644 --- a/include/m_bgm.h +++ b/include/m_bgm.h @@ -12,6 +12,8 @@ extern void mBGM_reset(); extern void mBGMPsComp_make_ps_lost_fanfare(u8 bgm_no, u16 unk); extern void mBGMPsComp_scene_mode(int scene_mode); extern void mBGMPsComp_make_ps_wipe(u16 ps_wipe); +extern void mBGMPsComp_delete_ps_demo(u8 bgm_num, u16 stop_type); +extern void mBGMPsComp_make_ps_demo(u8 bgm_no, u16 stop_type); #ifdef __cplusplus } diff --git a/include/m_choice.h b/include/m_choice.h new file mode 100644 index 00000000..1f0ac58b --- /dev/null +++ b/include/m_choice.h @@ -0,0 +1,28 @@ +#ifndef M_CHOICE_H +#define M_CHOICE_H + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct choice_s mChoice_c; // TODO + +enum choice { + mChoice_CHOICE0, + mChoice_CHOICE1, + mChoice_CHOICE2, + mChoice_CHOICE3, + + mChoice_CHOICE_NUM +}; + +extern mChoice_c* mChoice_Get_base_window_p(); +extern int mChoice_Get_ChoseNum(mChoice_c* choice); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/m_clip.h b/include/m_clip.h index 46249122..f9062c73 100644 --- a/include/m_clip.h +++ b/include/m_clip.h @@ -7,6 +7,7 @@ #include "ac_structure.h" #include "ac_animal_logo.h" #include "ef_effect_control.h" +#include "m_demo.h" #ifdef __cplusplus extern "C" { @@ -19,7 +20,10 @@ typedef struct clip_s { /* 0x080 */ void* _080[(0x08C - 0x080) / sizeof(void*)]; /* 0x08C */ aSTR_Clip_c* structure_clip; /* 0x090 */ eEC_EffectControl_Clip_c* effect_clip; - /* 0x094 */ void* _094[(0x0AC - 0x094) / sizeof(void*)]; + /* 0x094 */ void* _094[(0x0A0 - 0x094) / sizeof(void*)]; + /* 0x0A0 */ mDemo_Clip_c* demo_clip; /* can be multiple clip classes */ + /* 0x0A4 */ void* demo_clip2; /* can be multiple clip classes */ + /* 0x0A8 */ void* _0A8; /* 0x0AC */ aGYO_Clip_c* gyo_clip; /* 0x0B0 */ void* _0B0[(0x0DC - 0x0B0) / sizeof(void*)]; /* 0x0DC */ aAL_Clip_c* animal_logo_clip; diff --git a/include/m_collision_obj.h b/include/m_collision_obj.h index 4d40a603..a48ad3bb 100644 --- a/include/m_collision_obj.h +++ b/include/m_collision_obj.h @@ -71,11 +71,36 @@ typedef struct collision_check_s { ClObj_c* collider_table[Cl_COLLIDER_NUM]; } CollisionCheck_c; +/* This appears to again be copy-paste from OoT? */ +typedef struct status_s { + xyz_t collision_vec; + s16 radius; + s16 height; + s16 offset; + + u8 weight; + u8 hp; + u8 damage; + + u8 damage_effect; + u8 at_hit_effect; + u8 ac_hit_effect; +} Status_c; + +typedef struct status_data_s { + u8 health; // assuming this is inherited from OoT, seems largely unused + s16 radius; + s16 height; + s16 offset; + u8 weight; +} StatusData_c; + extern void ClObjPipe_ct(GAME_PLAY* play, ClObjPipe_c* pipe); extern void ClObjPipe_dt(GAME_PLAY* play, ClObjPipe_c* pipe); extern void ClObjPipe_set5(GAME_PLAY* play, ClObjPipe_c* pipe, ACTOR* owner, ClObjPipeData_c* data); extern void CollisionCheck_Uty_ActorWorldPosSetPipeC(ACTOR* actor, ClObjPipe_c* col_pipe); extern int CollisionCheck_setOC(GAME_PLAY* play, CollisionCheck_c* collision_check, ClObj_c* col_obj); +extern void CollisionCheck_Status_set3(Status_c* status, StatusData_c* data); #ifdef __cplusplus } diff --git a/include/m_common_data.h b/include/m_common_data.h index 40d99266..6a0976fb 100644 --- a/include/m_common_data.h +++ b/include/m_common_data.h @@ -200,7 +200,9 @@ typedef struct common_data_s { /* 0x028860 */ f32 unused_028860; /* 0x028864 */ u16 unused_028864; /* 0x028866 */ u16 unused_028866; - /* 0x028868 */ u8 _028868[0x028879 - 0x028868]; + /* 0x028868 */ u8 reset_flag; + /* 0x028869 */ u8 reset_type; + /* 0x02886A */ u8 _02886A[0x028879 - 0x02886A]; /* 0x028879 */ u8 auto_nwrite_count; /* 0x02887A */ lbRTC_year_t auto_nwrite_year; /* 0x02887C */ u8 save_error_type; /* set to one of the mFRm_ERROR_* states when save is invalid */ diff --git a/include/m_demo.h b/include/m_demo.h index 37bb07e5..bb2dd07e 100644 --- a/include/m_demo.h +++ b/include/m_demo.h @@ -10,12 +10,29 @@ extern "C" { typedef void (*mDemo_REQUEST_PROC)(ACTOR*); +typedef struct demo_clip_s { + void* class; + int type; /* 0 = none?, 1 = intro_demo, 2 = ride_off_demo */ +} mDemo_Clip_c; + +enum demo_clip_type { + mDemo_CLIP_TYPE_NONE, + mDemo_CLIP_TYPE_INTRO_DEMO, + mDemo_CLIP_TYPE_RIDE_OFF_DEMO, + + mDemo_CLIP_TYPE_NUM +}; + extern int mDemo_Request(int type, ACTOR* actor, mDemo_REQUEST_PROC request_proc); extern void mDemo_Set_msg_num(int msg_num); extern int mDemo_Check(int type, ACTOR* actor); extern int mDemo_Check_DiffAngle_forTalk(s16 angle); extern int mDemo_Check_ListenAble(); extern void mDemo_Set_ListenAble(); +extern ACTOR* mDemo_Get_talk_actor(); +extern void mDemo_Set_OrderValue(int type, int idx, u16 value); +extern u16 mDemo_Get_OrderValue(int type, int idx); +extern void mDemo_Set_talk_return_demo_wait(u8 value); #ifdef __cplusplus } diff --git a/include/m_field_info.h b/include/m_field_info.h index c5a306c1..8996574d 100644 --- a/include/m_field_info.h +++ b/include/m_field_info.h @@ -138,6 +138,7 @@ extern u8 mFI_BkNum2BlockType(); extern mFI_sound_source_info_c* mFI_GetSoundSourcePBlockNum(int block_x,int block_z); extern int mFI_Wpos2UtNum(int* ut_x, int* ut_z, xyz_t wpos); extern void mFI_ClearFieldData(); +extern int mFI_SetFG_common(mActor_name_t item, xyz_t wpos, int update); extern void mFI_PrintNowBGNum(gfxprint_t* gfxprint); extern void mFI_PrintFgAttr(gfxprint_t* gfxprint); diff --git a/include/m_msg.h b/include/m_msg.h index ec107a61..5e91eb61 100644 --- a/include/m_msg.h +++ b/include/m_msg.h @@ -19,6 +19,15 @@ extern void mMsg_aram_init(); extern int mMsg_Check_MainHide(mMsg_Window_c* msg); extern void mMsg_Set_item_str(mMsg_Window_c* msg_win, int str_no, u8* item_str, int str_len); extern void mMsg_Set_mail_str(mMsg_Window_c* msg_win, int str_no, u8* str, int str_len); +extern void mMsg_Set_continue_msg_num(mMsg_Window_c* msg_win, int continue_msg_num); +extern int mMsg_Check_MainNormalContinue(mMsg_Window_c* msg_win); +extern int mMsg_Check_main_wait(mMsg_Window_c* msg_win); +extern int mMsg_ChangeMsgData(mMsg_Window_c* msg_win, int msg_no); +extern void mMsg_Set_ForceNext(mMsg_Window_c* msg_win); +extern int mMsg_Check_not_series_main_wait(mMsg_Window_c* msg_win); +extern int mMsg_Check_MainDisappear(mMsg_Window_c* msg_win); +extern void mMsg_request_main_disappear_wait_type1(mMsg_Window_c* msg_win); +extern void mMsg_request_main_appear_wait_type1(mMsg_Window_c* msg_win); #ifdef __cplusplus } diff --git a/include/m_name_table.h b/include/m_name_table.h index a27b77eb..67a2723d 100644 --- a/include/m_name_table.h +++ b/include/m_name_table.h @@ -468,6 +468,11 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define EXIT_DOOR 0x4080 +#define STRUCTURE_START 0x5800 +#define HOUSE0 (STRUCTURE_START) +#define HOUSE1 (HOUSE0 + 1) +#define HOUSE2 (HOUSE1 + 1) +#define HOUSE3 (HOUSE2 + 1) #define TRAIN_STATION 0x5809 #define TRAIN0 0x580A #define TRAIN1 0x580B @@ -480,6 +485,15 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define MISC_ACTOR_START 0x9000 #define MISC_ACTOR_SAMPLE MISC_ACTOR_START +#define ACTOR_PROP_START 0xA000 +#define ACTOR_PROP_MAILBOX0 (ACTOR_PROP_START) +#define ACTOR_PROP_MAILBOX1 (ACTOR_PROP_MAILBOX0 + 1) +#define ACTOR_PROP_MAILBOX2 (ACTOR_PROP_MAILBOX1 + 1) +#define ACTOR_PROP_MAILBOX3 (ACTOR_PROP_MAILBOX2 + 1) +#define ACTOR_PROP_HANIWA0 (ACTOR_PROP_MAILBOX3 + 1) +#define ACTOR_PROP_HANIWA1 (ACTOR_PROP_HANIWA0 + 1) +#define ACTOR_PROP_HANIWA2 (ACTOR_PROP_HANIWA1 + 1) +#define ACTOR_PROP_HANIWA3 (ACTOR_PROP_HANIWA2 + 1) #define TRAIN_DOOR 0xA011 #define SP_NPC_START 0xD000 @@ -575,6 +589,12 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define NPC_LOBO 0xE0B9 #define NPC_BIFF 0xE0C2 +#define DUMMY_START 0xF000 +#define DUMMY_HANIWA0 0xF0FB +#define DUMMY_HANIWA1 (DUMMY_HANIWA0 + 1) +#define DUMMY_HANIWA2 (DUMMY_HANIWA2 + 1) +#define DUMMY_HANIWA3 (DUMMY_HANIWA2 + 1) + #define RSV_DOOR 0xFE1B #define RSV_WALL_NO 0xFFFE /* interior wall item, no collision */ #define RSV_NO 0xFFFF /* reserved space, can't interact but no collision */ diff --git a/include/m_needlework_ovl.h b/include/m_needlework_ovl.h new file mode 100644 index 00000000..cd80e58b --- /dev/null +++ b/include/m_needlework_ovl.h @@ -0,0 +1,17 @@ +#ifndef M_NEEDLEWORK_OVL_H +#define M_NEEDLEWORK_OVL_H + +#include "types.h" +#include "m_submenu.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern u8 mNW_get_image_no(Submenu* submenu, int slot_no); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/m_npc.h b/include/m_npc.h index 386e1220..dbac37ab 100644 --- a/include/m_npc.h +++ b/include/m_npc.h @@ -11,6 +11,7 @@ #include "m_personal_id.h" #include "m_quest.h" #include "m_lib.h" +#include "m_private_h.h" #ifdef __cplusplus extern "C" { @@ -199,6 +200,7 @@ extern void mNpc_ClearAnimalInfo(Animal_c* animal_p); extern Animal_c* mNpc_GetInAnimalP(); extern int mNpc_GetLooks2Sex(int looks); extern int mNpc_CheckFreeAnimalInfo(Animal_c* animal); +extern int mNpc_GetFriendAnimalNum(Private_c* private_p); extern void mNpc_PrintRemoveInfo(gfxprint_t* gfxprint); extern void mNpc_PrintFriendship_fdebug(gfxprint_t* gfxprint); diff --git a/include/m_player.h b/include/m_player.h index cb5247e5..0c01210f 100644 --- a/include/m_player.h +++ b/include/m_player.h @@ -14,7 +14,9 @@ typedef struct player_actor_s PLAYER_ACTOR; /* sizeof(struct player_actor_s) == 0x13A8 */ struct player_actor_s { /* 0x0000 */ ACTOR actor_class; - /* 0x0174 */ u8 tmp0174[0x1318 - 0x0174]; + /* 0x0174 */ u8 tmp0174[0x1300 - 0x0174]; + /* 0x1300 */ void* (*get_door_label_proc)(GAME*); + /* 0x1304 */ u8 tmp1304[0x1318 - 0x1304]; /* 0x1318 */ int (*Get_WadeEndPos_proc)(GAME*, xyz_t*); /* 0x131C */ u8 tmp131C[0x13A8 - 0x131C]; /* TODO: finish */ diff --git a/include/m_player_lib.h b/include/m_player_lib.h index 1a467617..84ae0f78 100644 --- a/include/m_player_lib.h +++ b/include/m_player_lib.h @@ -16,6 +16,9 @@ extern mActor_name_t mPlib_Get_itemNo_forWindow(); extern int mPlib_check_able_change_camera_normal_index(); extern void mPlib_request_main_refuse_type1(GAME_PLAY* play); extern void mPlib_request_main_wait_type3(GAME_PLAY* play); +extern void mPlib_Set_able_force_speak_label(ACTOR* actor); +extern int mPlib_request_main_demo_walk_type1(GAME* game, f32 goal_x, f32 goal_z, f32 speed, int flag); +extern void mPlib_Set_goal_player_demo_walk(f32 goal_x, f32 goal_z, f32 speed); #ifdef __cplusplus } diff --git a/include/m_private.h b/include/m_private.h index 83c1a9ee..f5cea0af 100644 --- a/include/m_private.h +++ b/include/m_private.h @@ -2,6 +2,7 @@ #define M_PRIVATE_H #include "types.h" +#include "m_private_h.h" #include "libu64/gfxprint.h" #include "m_personal_id.h" #include "m_npc.h" @@ -18,6 +19,8 @@ extern "C" { #define FOREIGNER_NUM 1 #define TOTAL_PLAYER_NUM (PLAYER_NUM + FOREIGNER_NUM) +#define mPr_WALLET_MAX 99999 + enum { mPr_PLAYER_0, mPr_PLAYER_1, @@ -144,7 +147,7 @@ typedef struct player_ecard_data_s { /* 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; -typedef struct private_s { +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 */ @@ -212,7 +215,7 @@ typedef struct private_s { /* 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]; -} Private_c; +}; extern s16 mPr_GetGoodsPower(); extern s16 mPr_GetMoneyPower(); @@ -227,6 +230,7 @@ extern void mPr_ClearPrivateInfo(Private_c* private_data); extern int mPr_CheckCmpPlayerName(u8* str0, u8* str1); extern void mPr_RandomSetPlayerData_title_demo(); extern int mPr_GetPossessionItemSumWithCond(Private_c* priv, mActor_name_t item_no, u32 cond); +extern int mPr_SetFreePossessionItem(Private_c* priv, mActor_name_t item_no, u32 cond); extern void mPr_CopyPlayerName(u8* dst, Private_c* private_p); #ifdef __cplusplus diff --git a/include/m_private_h.h b/include/m_private_h.h new file mode 100644 index 00000000..3f6956aa --- /dev/null +++ b/include/m_private_h.h @@ -0,0 +1,16 @@ +#ifndef M_PRIVATE_H_H +#define M_PRIVATE_H_H + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct private_s Private_c; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/m_submenu.h b/include/m_submenu.h index 0745b0cc..10fcc3b9 100644 --- a/include/m_submenu.h +++ b/include/m_submenu.h @@ -103,6 +103,8 @@ 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); + #ifdef __cplusplus } #endif diff --git a/rel/ac_haniwa.c b/rel/ac_haniwa.c new file mode 100644 index 00000000..7d93a752 --- /dev/null +++ b/rel/ac_haniwa.c @@ -0,0 +1,975 @@ +#include "ac_haniwa.h" + +#include "m_play.h" +#include "m_bgm.h" +#include "m_rcp.h" +#include "m_name_table.h" +#include "m_house.h" +#include "m_font.h" +#include "m_msg.h" +#include "m_choice.h" +#include "m_demo.h" +#include "m_player.h" +#include "m_player_lib.h" +#include "m_clip.h" +#include "m_event.h" +#include "ac_intro_demo.h" +#include "ac_my_house.h" +#include "m_needlework_ovl.h" +#include "m_npc.h" +#include "m_submenu.h" +#include "m_field_info.h" +#include "m_common_data.h" + +extern cKF_Skeleton_R_c cKF_bs_r_hnw; +extern cKF_Animation_R_c cKF_ba_r_hnw_move; +extern u8 hnw_tmem_txt[]; +extern u8 hnw_face[]; + +// #include ac_haniwa_move_procs.c_inc + +static void aHNW_actor_ct(ACTOR* actor, GAME* game); +static void aHNW_actor_dt(ACTOR* actor, GAME* game); +static void aHNW_actor_init(ACTOR* actor, GAME* game); + +ACTOR_PROFILE Haniwa_Profile = { + mAc_PROFILE_HANIWA, + ACTOR_PART_BG, + ACTOR_STATE_NONE, + ACTOR_PROP_HANIWA0, + ACTOR_OBJ_BANK_12, + sizeof(HANIWA_ACTOR), + + &aHNW_actor_ct, + &aHNW_actor_dt, + &aHNW_actor_init, + (mActor_proc)&none_proc1, + NULL +}; + +static ClObjPipeData_c AcHaniwaCoInfoData = { + { 57, 32, ClObj_TYPE_PIPE }, + { 1 }, + { 20, 30, 0, { 0, 0, 0 } } +}; + +static StatusData_c AcHaniwaStatusData = { + 0, + 20, 30, 0, + 254 +}; + +/* TODO: ct, dt, & draw are in their own TU */ +static void aHNW_actor_ct(ACTOR* actor, GAME* game) { + HANIWA_ACTOR* haniwa = (HANIWA_ACTOR*)actor; + ClObjPipe_c* pipe; + cKF_SkeletonInfo_R_c* keyframe = &haniwa->keyframe; + GAME_PLAY* play = (GAME_PLAY*)game; + + cKF_SkeletonInfo_R_ct(keyframe, &cKF_bs_r_hnw, NULL, haniwa->keyframe_work_area, haniwa->keyframe_morph_area); + + pipe = &haniwa->col_pipe; + ClObjPipe_ct((GAME_PLAY*)game, pipe); + ClObjPipe_set5((GAME_PLAY*)game, pipe, actor, &AcHaniwaCoInfoData); + CollisionCheck_Status_set3(&haniwa->actor_class.status_data, &AcHaniwaStatusData); + + { + Object_Bank_c* bank = &play->object_exchange.banks[actor->data_bank_id]; + haniwa->bank_ram_start = bank->ram_start; + } + + haniwa->animation_state = 2; + haniwa->house_idx = actor->npc_id - ACTOR_PROP_HANIWA0; + actor->talk_distance = 43.0f; +} + +static void aHNW_actor_dt(ACTOR* actor, GAME* game) { + HANIWA_ACTOR* haniwa = (HANIWA_ACTOR*)actor; + GAME_PLAY* play = (GAME_PLAY*)game; + + if (haniwa->playing_save_bgm) { + mBGMPsComp_delete_ps_demo(0x41, 0x168); + } + + cKF_SkeletonInfo_R_dt(&haniwa->keyframe); + ClObjPipe_dt(play, &haniwa->col_pipe); +} + + +static Gfx hnw_tex_model[2]; + +static void aHNW_actor_draw(ACTOR* actor, GAME* game) { + // TODO: this should be fixed when possible. + // we need to add an additional TU for correct ordering + // but PPCdis does not work well with that + + /* + static Gfx hnw_tex_model[] = { + gsDPLoadTLUT_Dolphin(15, 16, 1, hnw_face), + gsSPEndDisplayList(), + }; + */ + + HANIWA_ACTOR* haniwa = (HANIWA_ACTOR*)actor; + cKF_SkeletonInfo_R_c* keyframe = &haniwa->keyframe; + GRAPH* g = game->graph; + Mtx* m; + + m = GRAPH_ALLOC_TYPE(g, Mtx, keyframe->skeleton->num_shown_joints); + + if (m != NULL) { + Gfx* gfx; + int house_idx = haniwa->house_idx; + _texture_z_light_fog_prim(g); + + OPEN_DISP(g); + gfx = NOW_POLY_OPA_DISP; + + gSPSegment(gfx++, G_MWO_SEGMENT_B, hnw_tmem_txt); + + if (mPr_NullCheckPersonalID(&Save_Get(homes[house_idx]).ownerID) != TRUE && + Common_Get(player_no) == mHS_get_pl_no(house_idx) + ) { + gDPSetPrimColor(gfx++, 0, 128, 255, 255, 255, 255); + } + else { + gDPSetPrimColor(gfx++, 0, 128, 255, 255, 255, 255); + } + + gSPDisplayList(gfx++, hnw_tex_model); + + SET_POLY_OPA_DISP(gfx); + CLOSE_DISP(g); + + cKF_Si3_draw_R_SV(game, keyframe, m, NULL, NULL, actor); + } +} + +static void aHNW_setupAction(ACTOR* actor, GAME* game, int action); + +static int aHNW_set_save_permission() { + u32 player_no = Common_Get(player_no); + PersonalID_c* pid; + mHm_hs_c* house; + int res = FALSE; + + if (player_no < PLAYER_NUM) { + int arrange_idx = mHS_get_arrange_idx(player_no); + house = Save_GetPointer(homes[arrange_idx]); + pid = &Save_Get(private[player_no]).player_ID; + + if (mPr_NullCheckPersonalID(pid) != TRUE && + mPr_CheckCmpPersonalID(pid, &house->ownerID) == TRUE + ) { + res = TRUE; + house->flags.has_saved = TRUE; + } + } + + return res; +} + +static void aHNW_search_player(ACTOR* actor) { + chase_angle(&actor->shape_info.rotation.y, actor->player_angle_y, 0x0600); +} + +static void aHNW_search_front(ACTOR* actor, int house_idx) { + s16 target_angle[mHS_HOUSE_NUM] = { 8000, -8000, 8000, -8000 }; + + chase_angle(&actor->shape_info.rotation.y, target_angle[house_idx], 0x0600); +} + +static int aHNW_check_keep_item(ACTOR* actor) { + HANIWA_ACTOR* haniwa = (HANIWA_ACTOR*)actor; + Haniwa_Item_c* haniwa_item = Save_Get(homes[haniwa->house_idx]).haniwa.items; + int i; + int res = FALSE; + + for (i = 0; i < HANIWA_ITEM_HOLD_NUM; i++) { + if (haniwa_item->item != EMPTY_NO) { + res = TRUE; + break; + } + + haniwa_item++; + } + + return res; +} + +static void aHNW_set_proceeds_str(Haniwa_c* haniwa) { + u8 str[7]; + + mFont_UnintToString(str, 7, haniwa->bells, 6, TRUE, FALSE, TRUE); + mMsg_Set_free_str(mMsg_Get_base_window_p(), 0, str, 7); +} + +static int aHNW_check_handOver_proceeds(Haniwa_c* haniwa) { + int handOver = FALSE; + u32 money = Common_Get(now_private)->inventory.wallet + haniwa->bells; + + if (money < mPr_WALLET_MAX) { + Common_Get(now_private)->inventory.wallet = money; + handOver = TRUE; + } + else { + u32 num_30k_bell_bags = (money - mPr_WALLET_MAX) / 30000 + 1; + + if (mPr_GetPossessionItemSumWithCond(Common_Get(now_private), EMPTY_NO, mPr_ITEM_COND_NORMAL) >= num_30k_bell_bags) { + handOver = TRUE; + + for (num_30k_bell_bags; num_30k_bell_bags != 0; num_30k_bell_bags--) { + mPr_SetFreePossessionItem(Common_Get(now_private), ITM_MONEY_30000, mPr_ITEM_COND_NORMAL); + money -= 30000; + } + + Common_Get(now_private)->inventory.wallet = money; + } + else { + u8 str[5]; + + mFont_UnintToString(str, 5, num_30k_bell_bags, 5, TRUE, FALSE, TRUE); + mMsg_Set_free_str(mMsg_Get_base_window_p(), 1, str, 5); + } + } + + return handOver; +} + +static int aHNW_check_house_door(ACTOR* actor, GAME* game) { + HANIWA_ACTOR* haniwa = (HANIWA_ACTOR*)actor; + int res = FALSE; + GAME_PLAY* play = (GAME_PLAY*)game; + + if (Common_Get(reset_flag) == TRUE) { + ACTOR* talk_actor = mDemo_Get_talk_actor(); + + if (talk_actor == NULL && chkTrigger(BUTTON_A)) { + PLAYER_ACTOR* player = get_player_actor_withoutCheck(play); + + if (mDemo_Check_DiffAngle_forTalk((actor->player_angle_y - player->actor_class.shape_info.rotation.y) - -0x8000) == TRUE) { + Common_Set(reset_type, 4); + } + } + + res = TRUE; + } + else { + mDemo_Clip_c* demo_clip = Common_Get(clip).demo_clip; + + if (demo_clip != NULL) { + INTRO_DEMO_ACTOR* demo_class = (INTRO_DEMO_ACTOR*)demo_clip->class; + if (demo_class != NULL && demo_clip->type == mDemo_CLIP_TYPE_INTRO_DEMO && + mEv_CheckFirstIntro() && demo_class->player_intro_demo_state != 0) { + res = TRUE; + } + } + } + + return res; +} + +static void aHNW_wait(ACTOR* actor, GAME* game) { + if (actor->player_distance_xz < 80.0f) { + aHNW_setupAction(actor, game, aHNW_ACTION_DANCE); + } +} + +static int aHNW_decide_msg_idx_dance(ACTOR* actor) { + HANIWA_ACTOR* haniwa = (HANIWA_ACTOR*)actor; + Haniwa_c* house_haniwa; + int house_idx = haniwa->house_idx; + int player_is_owner = Common_Get(player_no) == mHS_get_pl_no(haniwa->house_idx); + int res; + + + if (mPr_NullCheckPersonalID(&Save_Get(homes[house_idx]).ownerID) == TRUE) { + res = aHNW_MSG_NO_OWNER; /* no one owns this house */ + } + else if (player_is_owner == TRUE) { + Haniwa_c* house_haniwa = &Save_Get(homes[house_idx]).haniwa; + int house_arrange_idx = mHS_get_arrange_idx(Common_Get(player_no)); + mHm_hs_c* house = Save_GetPointer(homes[house_arrange_idx]); + if (house->flags.has_saved == FALSE && + mEv_CheckFirstJob() == TRUE && mNpc_GetFriendAnimalNum(Common_Get(now_private)) == 0 + ) { + res = aHNW_MSG_NEED_FRIEND; /* player owns this house, but is in intro and has not spoken to any villagers */ + } + else if (house_haniwa->bells != 0) { + res = aHNW_MSG_PROCEEDS; + } + else { + res = aHNW_MSG_NORMAL; + } + + /* player owns house but gyroid has bells from other players */ + } + else { + res = aHNW_MSG_OTHER_OWNER; /* another player owns house */ + } + + return res; +} + + +static void aHNW_set_talk_info_dance(ACTOR* actor) { + static int msg_no[aHNW_MSG_NUM] = { + 0x0934, /* aHNW_MSG_NO_OWNER */ + 0x0935, /* aHNW_MSG_PROCEEDS */ + 0x0925, /* aHNW_MSG_NORMAL */ + 0x0928, /* aHNW_MSG_OTHER_OWNER */ + 0x092E /* aHNW_MSG_NEED_FRIEND */ + }; + + HANIWA_ACTOR* haniwa = (HANIWA_ACTOR*)actor; + int house_idx = haniwa->house_idx; + Haniwa_c* house_haniwa = &Save_Get(homes[house_idx]).haniwa; + int msg_idx = aHNW_decide_msg_idx_dance(actor); + + switch (msg_idx) { + case aHNW_MSG_PROCEEDS: + { + aHNW_set_proceeds_str(house_haniwa); + break; + } + + case aHNW_MSG_OTHER_OWNER: + { + mMsg_Set_mail_str(mMsg_Get_base_window_p(), 0, house_haniwa->message, HANIWA_MESSAGE_LEN); + break; + } + } + + mDemo_Set_msg_num(msg_no[msg_idx]); +} + +static void aHNW_dance(ACTOR* actor, GAME* game) { + static int next_act_idx[aHNW_MSG_NUM] = { + aHNW_ACTION_TALK_END_WAIT, /* aHNW_MSG_NO_OWNER */ + aHNW_ACTION_CHECK_PROCEEDS, /* aHNW_MSG_PROCEEDS */ + aHNW_ACTION_TALK_WITH_MASTER, /* aHNW_MSG_NORMAL */ + aHNW_ACTION_TALK_WITH_GUEST, /* aHNW_MSG_OTHER_OWNER */ + aHNW_ACTION_TALK_END_WAIT /* aHNW_MSG_NEED_FRIEND */ + }; + + HANIWA_ACTOR* haniwa = (HANIWA_ACTOR*)actor; + + if (actor->player_distance_xz > 90.0f) { + aHNW_setupAction(actor, game, aHNW_ACTION_WAIT); + } + else { + if (mDemo_Check(7, (ACTOR*)haniwa) == TRUE && mDemo_Check_ListenAble() == FALSE) { + int msg_idx = aHNW_decide_msg_idx_dance(actor); + mDemo_Set_ListenAble(); + aHNW_setupAction(actor, game, next_act_idx[msg_idx]); + } + else if (aHNW_check_house_door((ACTOR*)haniwa, game) == FALSE) { + mDemo_Request(7, (ACTOR*)haniwa, &aHNW_set_talk_info_dance); + } + } +} + +static void aHNW_check_proceeds(ACTOR* actor, GAME* game) { + static int msg_no[aHNW_HANDOVER_NUM] = { + 0x0936, /* aHNW_HANDOVER_YES */ + 0x0937 /* aHNW_HANDOVER_NO */ + }; + + static int next_act_idx[aHNW_HANDOVER_NUM] = { + aHNW_ACTION_TALK_WITH_MASTER, /* aHNW_HANDOVER_YES */ + aHNW_ACTION_TALK_END_WAIT /* aHNW_HANDOVER_NO */ + }; + + HANIWA_ACTOR* haniwa = (HANIWA_ACTOR*)actor; + + if (mDemo_Get_OrderValue(4, 9)) { + int house_idx = haniwa->house_idx; + Haniwa_c* house_haniwa = &Save_Get(homes[house_idx]).haniwa; + int handover_state; + + if (aHNW_check_handOver_proceeds(house_haniwa) == TRUE) { + house_haniwa->bells = 0; + handover_state = aHNW_HANDOVER_YES; + } + else { + handover_state = aHNW_HANDOVER_NO; + } + + mMsg_Set_continue_msg_num(mMsg_Get_base_window_p(), msg_no[handover_state]); + aHNW_setupAction(actor, game, next_act_idx[handover_state]); + mDemo_Set_OrderValue(4, 9, 0); + } +} + +static void aHNW_talk_with_master(ACTOR* actor, GAME* game) { + HANIWA_ACTOR* haniwa = (HANIWA_ACTOR*)actor; + mMsg_Window_c* msg_win = mMsg_Get_base_window_p(); + + if (mDemo_Get_OrderValue(4, 9) && mMsg_Check_MainNormalContinue(msg_win) == TRUE) { + int action = -1; + + switch (mChoice_Get_ChoseNum(mChoice_Get_base_window_p())) { + case mChoice_CHOICE0: + { + action = aHNW_ACTION_SAVE_CHECK; + break; + } + + case mChoice_CHOICE1: + { + action = aHNW_ACTION_MENU_OPEN_WAIT; + haniwa->submenu_type = mSM_OVL_INVENTORY; + break; + } + + case mChoice_CHOICE2: + { + action = aHNW_ACTION_TALK_WITH_MASTER2; + break; + } + + case mChoice_CHOICE3: + { + action = aHNW_ACTION_TALK_END_WAIT; + break; + } + } + + if (action != -1) { + mDemo_Set_OrderValue(4, 9, 0); + aHNW_setupAction(actor, game, action); + } + } +} + +static void aHNW_talk_with_master2(ACTOR* actor, GAME* game) { + HANIWA_ACTOR* haniwa = (HANIWA_ACTOR*)actor; + mMsg_Window_c* msg_win = mMsg_Get_base_window_p(); + + if (mDemo_Get_OrderValue(4, 9) && mMsg_Check_MainNormalContinue(msg_win) == TRUE) { + int action = -1; + + switch (mChoice_Get_ChoseNum(mChoice_Get_base_window_p())) { + case mChoice_CHOICE0: + { + action = aHNW_ACTION_ROOF_CHECK; + break; + } + + case mChoice_CHOICE1: + { + action = aHNW_ACTION_MENU_OPEN_WAIT; + haniwa->submenu_type = mSM_OVL_HBOARD; + break; + } + + case mChoice_CHOICE2: + { + action = aHNW_ACTION_TALK_WITH_MASTER; + break; + } + + case mChoice_CHOICE3: + { + action = aHNW_ACTION_TALK_END_WAIT; + break; + } + } + + if (action != -1) { + mDemo_Set_OrderValue(4, 9, 0); + aHNW_setupAction(actor, game, action); + } + } +} + +static void aHNW_talk_end_wait(ACTOR* actor, GAME* game) { + if (mDemo_Check(7, actor) == FALSE) { + aHNW_setupAction(actor, game, aHNW_ACTION_DANCE); + } +} + +static void aHNW_menu_open_wait(ACTOR* actor, GAME* game) { + HANIWA_ACTOR* haniwa = (HANIWA_ACTOR*)actor; + GAME_PLAY* play = (GAME_PLAY*)game; + mMsg_Window_c* msg_win = mMsg_Get_base_window_p(); + + if (mMsg_Check_main_wait(msg_win) == TRUE) { + int submenu_type = haniwa->submenu_type; + Submenu* submenu = &play->submenu; + int arg1 = haniwa->house_idx; + + switch (submenu_type) { + case mSM_OVL_HBOARD: + { + mSM_open_submenu(submenu, mSM_OVL_HBOARD, 0, arg1); + break; + } + + case mSM_OVL_INVENTORY: + { + mSM_open_submenu(submenu, mSM_OVL_INVENTORY, 2, arg1); + break; + } + + case mSM_OVL_NEEDLEWORK: + { + mSM_open_submenu(submenu, mSM_OVL_NEEDLEWORK, 0, arg1); + break; + } + } + + mMsg_ChangeMsgData(msg_win, 0x0927); + mMsg_Set_ForceNext(msg_win); + aHNW_setupAction(actor, game, aHNW_ACTION_MENU_END_WAIT); + } +} + +static void aHNW_menu_end_wait(ACTOR* actor, GAME* game) { + HANIWA_ACTOR* haniwa = (HANIWA_ACTOR*)actor; + GAME_PLAY* play = (GAME_PLAY*)game; + Submenu* submenu = &play->submenu; + Submenu_Item_c* item; + + if (submenu->flag == FALSE) { + if (mMsg_Check_not_series_main_wait(mMsg_Get_base_window_p()) == TRUE) { + aHNW_setupAction(actor, game, aHNW_ACTION_TALK_WITH_MASTER); + switch (haniwa->submenu_type) { + case mSM_OVL_NEEDLEWORK: + { + Submenu_Item_c* item = submenu->item_p; + if (item->item == RSV_NO) { + Save_Get(homes[haniwa->house_idx]).door_original = mNW_get_image_no(submenu, item->slot_no); + sAdo_SysTrgStart(0x461); + } + + break; + } + } + + haniwa->submenu_type = mSM_OVL_NONE; + } + } +} + +static void aHNW_talk_with_guest(ACTOR* actor, GAME* game) { + HANIWA_ACTOR* haniwa = (HANIWA_ACTOR*)actor; + + if (mDemo_Get_OrderValue(4, 0)) { + mMsg_Window_c* msg_win = mMsg_Get_base_window_p(); + if (mMsg_Check_MainNormalContinue(msg_win) == TRUE) { + int action = -1; + + switch (mChoice_Get_ChoseNum(mChoice_Get_base_window_p())) { + case mChoice_CHOICE0: + { + if (aHNW_check_keep_item(actor) == FALSE) { + mMsg_Set_continue_msg_num(msg_win, 0x092C); + action = aHNW_ACTION_TALK_END_WAIT; + } + else { + action = aHNW_ACTION_MENU_OPEN_WAIT_FOR_GUEST; + } + break; + } + + case mChoice_CHOICE1: + { + mMsg_Set_continue_msg_num(msg_win, 0x092A); + action = aHNW_ACTION_TALK_END_WAIT; + break; + } + } + + if (action != -1) { + mDemo_Set_OrderValue(4, 0, 0); + aHNW_setupAction(actor, game, action); + } + } + } +} + +static void aHNW_menu_open_wait_for_guest(ACTOR* actor, GAME* game) { + HANIWA_ACTOR* haniwa = (HANIWA_ACTOR*)actor; + GAME_PLAY* play = (GAME_PLAY*)game; + mMsg_Window_c* msg_win = mMsg_Get_base_window_p(); + + if (mMsg_Check_main_wait(msg_win) == TRUE) { + mSM_open_submenu(&play->submenu, mSM_OVL_INVENTORY, 3, haniwa->house_idx); + mMsg_ChangeMsgData(msg_win, 0x092B); + aHNW_setupAction(actor, game, aHNW_ACTION_MENU_END_WAIT_FOR_GUEST); + } +} + +static void aHNW_menu_end_wait_for_guest(ACTOR* actor, GAME* game) { + HANIWA_ACTOR* haniwa = (HANIWA_ACTOR*)actor; + GAME_PLAY* play = (GAME_PLAY*)game; + + if (play->submenu.flag == FALSE && mMsg_Check_not_series_main_wait(mMsg_Get_base_window_p()) == TRUE) { + aHNW_setupAction(actor, game, aHNW_ACTION_TALK_END_WAIT); + } +} + +static void aHNW_save_check(ACTOR* actor, GAME* game) { + HANIWA_ACTOR* haniwa = (HANIWA_ACTOR*)actor; + mMsg_Window_c* msg_win = mMsg_Get_base_window_p(); + int order_value = mDemo_Get_OrderValue(4, 9); + int action = -1; + + if (order_value && mMsg_Check_MainNormalContinue(msg_win) == TRUE) { + switch (mChoice_Get_ChoseNum(mChoice_Get_base_window_p())) { + case mChoice_CHOICE0: + { + action = aHNW_ACTION_SAVE_END_WAIT; + mBGMPsComp_scene_mode(13); + mDemo_Set_talk_return_demo_wait(1); + mPlib_Set_able_force_speak_label(actor); + break; + } + + case mChoice_CHOICE1: + { + action = aHNW_ACTION_TALK_WITH_MASTER; + break; + } + } + + if (action != -1) { + mDemo_Set_OrderValue(4, 9, 0); + aHNW_setupAction(actor, game, action); + } + } +} + +static void aHNW_roof_check(ACTOR* actor, GAME* game) { + HANIWA_ACTOR* haniwa = (HANIWA_ACTOR*)actor; + mMsg_Window_c* msg_win = mMsg_Get_base_window_p(); + int order_value = mDemo_Get_OrderValue(4, 9); + int action = -1; + + if (order_value && mMsg_Check_MainNormalContinue(msg_win) == TRUE) { + switch (mChoice_Get_ChoseNum(mChoice_Get_base_window_p())) { + case mChoice_CHOICE0: + { + action = aHNW_ACTION_MENU_OPEN_WAIT; + haniwa->submenu_type = mSM_OVL_NEEDLEWORK; + break; + } + + case mChoice_CHOICE1: + { + Save_Get(homes[haniwa->house_idx]).door_original = 0xFF; + sAdo_SysTrgStart(0x461); + action = aHNW_ACTION_TALK_WITH_MASTER; + break; + } + + case mChoice_CHOICE2: + { + action = aHNW_ACTION_TALK_WITH_MASTER; + break; + } + } + + if (action != -1) { + mDemo_Set_OrderValue(4, 9, 0); + aHNW_setupAction(actor, game, action); + } + } +} + +static void aHNW_save_end_wait(ACTOR* actor, GAME* game) { + HANIWA_ACTOR* haniwa = (HANIWA_ACTOR*)actor; + + if (haniwa->playing_save_bgm == FALSE && mMsg_Check_MainDisappear(mMsg_Get_base_window_p())) { + haniwa->playing_save_bgm = TRUE; + mBGMPsComp_make_ps_demo(0x41, 0x168); + } + + if (mDemo_Check(7, actor) == FALSE) { + aHNW_setupAction(actor, game, aHNW_ACTION_PL_APPROACH_DOOR); + aHNW_set_save_permission(); + } +} + +#pragma pool_data on +static void aHNW_pl_approach_door(ACTOR* actor, GAME* game) { + static f32 chk_posX[mHS_HOUSE_NUM] = { 2095.0f, 2385.0f, 2095.0f, 2385.0f }; + static f32 chk_val[mHS_HOUSE_NUM] = { 1.0f, -1.0f, 1.0f, -1.0f }; + static xyz_t goal_pos[mHS_HOUSE_NUM][2] = { + { + { 2098.0f, 0.0f, 1540.0f }, + { 2110.0f, 0.0f, 1474.0f } + }, + { + { 2382.0f, 0.0f, 1540.0f }, + { 2369.0f, 0.0f, 1474.0f } + }, + { + { 2098.0f, 0.0f, 1820.0f }, + { 2110.0f, 0.0f, 1755.0f } + }, + { + { 2382.0f, 0.0f, 1820.0f }, + { 2369.0f, 0.0f, 1755.0f } + } + }; + + HANIWA_ACTOR* haniwa = (HANIWA_ACTOR*)actor; + GAME_PLAY* play = (GAME_PLAY*)game; + PLAYER_ACTOR* player = get_player_actor_withoutCheck((GAME_PLAY*)game); + + haniwa->door_approach_frame++; + + if (player != NULL) { + int house_idx = haniwa->house_idx; + int stage = ((chk_posX[house_idx] - player->actor_class.world_position.x) * chk_val[house_idx]) <= 0.0f; + xyz_t* goal = goal_pos[house_idx] + stage; + + if (haniwa->player_approach_door_stage != stage && mPlib_request_main_demo_walk_type1(game, goal->x, goal->z, 3.0f, FALSE)) { + haniwa->player_approach_door_stage = stage; + } + + mPlib_Set_goal_player_demo_walk(goal->x, goal->z, 3.0f); + + if (haniwa->door_approach_frame > 160) { + MY_HOUSE_ACTOR* house_actor = (MY_HOUSE_ACTOR*)Actor_info_fgName_search(&play->actor_info, HOUSE0 + haniwa->house_idx, ACTOR_PART_ITEM); + + if (house_actor != NULL) { + house_actor->actor_class.world_rotation.z = 1; + aHNW_setupAction(actor, game, aHNW_ACTION_WAIT); + } + } + else if (stage == 1 && search_position_distanceXZ(goal, &player->actor_class.world_position) < 3.0f) { + aHNW_setupAction(actor, game, aHNW_ACTION_DOOR_OPEN_WAIT); + } + } +} +#pragma pool_data reset + +static void aHNW_door_open_wait(ACTOR* actor, GAME* game) { + HANIWA_ACTOR* haniwa = (HANIWA_ACTOR*)actor; + GAME_PLAY* play = (GAME_PLAY*)game; + MY_HOUSE_ACTOR* house_actor = (MY_HOUSE_ACTOR*)Actor_info_fgName_search(&play->actor_info, HOUSE0 + haniwa->house_idx, ACTOR_PART_ITEM); + + if (house_actor != NULL) { + house_actor->door_rotation_speed_idx = 6; // TODO: this is probably an enum + if (house_actor != get_player_actor_withoutCheck((GAME_PLAY*)gamePT)->get_door_label_proc(gamePT)) { + aHNW_setupAction(actor, game, aHNW_ACTION_DOOR_OPEN_TIMER); + haniwa->door_approach_frame = 0; + } + else { + aHNW_setupAction(actor, game, aHNW_ACTION_WAIT); + } + } +} + +static void aHNW_door_open_timer(ACTOR* actor, GAME* game) { + HANIWA_ACTOR* haniwa = (HANIWA_ACTOR*)actor; + GAME_PLAY* play = (GAME_PLAY*)game; + MY_HOUSE_ACTOR* house_actor = (MY_HOUSE_ACTOR*)Actor_info_fgName_search(&play->actor_info, HOUSE0 + haniwa->house_idx, ACTOR_PART_ITEM); + + if (house_actor != NULL) { + if (house_actor == get_player_actor_withoutCheck((GAME_PLAY*)gamePT)->get_door_label_proc(gamePT)) { + aHNW_setupAction(actor, game, aHNW_ACTION_WAIT); + } + else { + haniwa->door_approach_frame++; + if (haniwa->door_approach_frame > 80) { + house_actor->actor_class.world_rotation.z = 1; + aHNW_setupAction(actor, game, aHNW_ACTION_WAIT); + } + } + } +} + +static void aHNW_menu_open_wait_init(ACTOR* actor, GAME* game) { + mMsg_request_main_disappear_wait_type1(mMsg_Get_base_window_p()); +} + +static void aHNW_menu_end_wait_init(ACTOR* actor, GAME* game) { + mMsg_request_main_appear_wait_type1(mMsg_Get_base_window_p()); +} + +static void aHNW_talk_with_guest_init(ACTOR* actor, GAME* game) { + HANIWA_ACTOR* haniwa = (HANIWA_ACTOR*)actor; + + mMsg_Set_free_str(mMsg_Get_base_window_p(), 2, Save_Get(homes[haniwa->house_idx]).ownerID.player_name, PLAYER_NAME_LEN); +} + +static void aHNW_pl_approach_door_init(ACTOR* actor, GAME* game) { + HANIWA_ACTOR* haniwa = (HANIWA_ACTOR*)actor; + + game->pad_initialized = FALSE; + haniwa->player_approach_door_stage = -1; + haniwa->door_approach_frame = 0; +} + +typedef void (*HANIWA_PROC)(ACTOR*, GAME*); + +static void aHNW_init_proc(ACTOR* actor, GAME* game, int action) { + static HANIWA_PROC init_proc[aHNW_ACTION_NUM] = { + (HANIWA_PROC)&none_proc1, + (HANIWA_PROC)&none_proc1, + (HANIWA_PROC)&none_proc1, + (HANIWA_PROC)&none_proc1, + (HANIWA_PROC)&none_proc1, + (HANIWA_PROC)&none_proc1, + &aHNW_menu_open_wait_init, + &aHNW_menu_end_wait_init, + &aHNW_talk_with_guest_init, + &aHNW_menu_open_wait_init, + &aHNW_menu_end_wait_init, + (HANIWA_PROC)&none_proc1, + (HANIWA_PROC)&none_proc1, + (HANIWA_PROC)&none_proc1, + &aHNW_pl_approach_door_init, + (HANIWA_PROC)&none_proc1, + (HANIWA_PROC)&none_proc1 + }; + + (*init_proc[action])(actor, game); +} + +static void aHNW_setupAction(ACTOR* actor, GAME* game, int action) { + static HANIWA_PROC process[aHNW_ACTION_NUM] = { + &aHNW_wait, + &aHNW_dance, + &aHNW_check_proceeds, + &aHNW_talk_with_master, + &aHNW_talk_with_master2, + &aHNW_talk_end_wait, + &aHNW_menu_open_wait, + &aHNW_menu_end_wait, + &aHNW_talk_with_guest, + &aHNW_menu_open_wait_for_guest, + &aHNW_menu_end_wait_for_guest, + &aHNW_roof_check, + &aHNW_save_check, + &aHNW_save_end_wait, + &aHNW_pl_approach_door, + &aHNW_door_open_wait, + &aHNW_door_open_timer + }; + + HANIWA_ACTOR* haniwa = (HANIWA_ACTOR*)actor; + + int house_idx = haniwa->house_idx; + int animation_state = haniwa->animation_state; + int no_owner = mPr_NullCheckPersonalID(&Save_Get(homes[house_idx]).ownerID); + int owner_is_player = mHS_get_pl_no(house_idx) == Common_Get(player_no); + + haniwa->action = action; + haniwa->action_proc = process[action]; + + if (action >= aHNW_ACTION_CHECK_PROCEEDS) { + haniwa->anim_frame_speed = 0.3f; + } + else { + if (no_owner) { + if (haniwa->anim_frame_speed != 0.0f) { + haniwa->anim_frame_speed = 0.075f; + } + } + else { + if (owner_is_player) { + if (action == aHNW_ACTION_WAIT || action == aHNW_ACTION_DOOR_OPEN_TIMER) { + haniwa->anim_frame_speed = 0.3f; + } + else { + haniwa->anim_frame_speed = 0.45f; + } + } + else { + haniwa->anim_frame_speed = 0.1f; + } + } + } + + if (animation_state == 2) { + cKF_SkeletonInfo_R_init( + &haniwa->keyframe, haniwa->keyframe.skeleton, &cKF_ba_r_hnw_move, + 1.0f, 9.0f, 1.0f, haniwa->anim_frame_speed, 0.0f, + cKF_FRAMECONTROL_REPEAT, + NULL + ); + haniwa->saved_current_frame = haniwa->keyframe.frame_control.current_frame; + } + + haniwa->animation_state = 0; + aHNW_init_proc(actor, game, action); + if (no_owner && action < aHNW_ACTION_CHECK_PROCEEDS) { + haniwa->keyframe.frame_control.mode = cKF_FRAMECONTROL_STOP; + } + else { + haniwa->keyframe.frame_control.mode = cKF_FRAMECONTROL_REPEAT; + } +} + +static void aHNW_common_process(ACTOR* actor, GAME* game) { + HANIWA_ACTOR* haniwa = (HANIWA_ACTOR*)actor; + cKF_SkeletonInfo_R_c* keyframe = &haniwa->keyframe; + int house_idx = haniwa->house_idx; + int no_owner = mPr_NullCheckPersonalID(&Save_Get(homes[house_idx]).ownerID); + f32 target; + + if (no_owner == FALSE && keyframe->frame_control.mode == cKF_FRAMECONTROL_STOP) { + aHNW_setupAction((ACTOR*)haniwa, game, haniwa->action); + keyframe->frame_control.mode = cKF_FRAMECONTROL_REPEAT; + } + else if (no_owner && haniwa->action < 2 && keyframe->frame_control.speed <= 0.1f) { + keyframe->frame_control.mode = cKF_FRAMECONTROL_STOP; + } + else { + keyframe->frame_control.mode = cKF_FRAMECONTROL_REPEAT; + } + + if (no_owner == FALSE || haniwa->action >= aHNW_ACTION_CHECK_PROCEEDS) { + aHNW_search_player((ACTOR*)haniwa); + } + else { + aHNW_search_front((ACTOR*)haniwa, house_idx); + } + + target = haniwa->anim_frame_speed; + + { + if (target > keyframe->frame_control.speed) { + chase_f(&keyframe->frame_control.speed, target, 0.05f); + } + else { + chase_f(&keyframe->frame_control.speed, target, 0.015f); + } + } +} + +static void aHNW_actor_move(ACTOR* actor, GAME* game) { + HANIWA_ACTOR* haniwa = (HANIWA_ACTOR*)actor; + GAME_PLAY* play = (GAME_PLAY*)game; + cKF_SkeletonInfo_R_c* keyframe = &haniwa->keyframe; + + haniwa->keyframe_state = cKF_SkeletonInfo_R_play(keyframe); + (*haniwa->action_proc)((ACTOR*)haniwa, game); + aHNW_common_process(actor, game); + CollisionCheck_Uty_ActorWorldPosSetPipeC(actor, &haniwa->col_pipe); + CollisionCheck_setOC(play, &play->collision_check, &haniwa->col_pipe.collision_obj); + Actor_world_to_eye(actor, 50.0f); +} + +static void aHNW_actor_init(ACTOR* actor, GAME* game) { + HANIWA_ACTOR* haniwa = (HANIWA_ACTOR*)actor; + int house_idx = haniwa->house_idx; + + mFI_SetFG_common((mActor_name_t)(house_idx + DUMMY_HANIWA0), actor->world_position, FALSE); + actor->mv_proc = &aHNW_actor_move; + actor->dw_proc = &aHNW_actor_draw; + aHNW_setupAction((ACTOR*)haniwa, game, aHNW_ACTION_WAIT); // weird that we have to re-cast to ACTOR so fequently for matches + haniwa->keyframe.morph_counter = 0.0f; + aHNW_actor_move(actor, game); +} + +/* TODO: hack */ +static Gfx hnw_tex_model[] = { + gsDPLoadTLUT_Dolphin(15, 16, 1, hnw_face), + gsSPEndDisplayList(), +};