diff --git a/config/rel_slices.yml b/config/rel_slices.yml index f0d9fef0..83dea615 100644 --- a/config/rel_slices.yml +++ b/config/rel_slices.yml @@ -414,6 +414,10 @@ ac_boxMove.c: ac_boxTrick01.c: .text: [0x80415BF8, 0x80415C04] .data: [0x806818F0, 0x80681918] +ac_cottage.c: + .text: [0x80415F04, 0x804174C4] + .rodata: [0x80643BA0, 0x80643DB0] + .data: [0x80681958, 0x80681A98] ac_field_draw.c: .text: [0x80422DA8, 0x80423E20] .rodata: [0x80643F00, 0x80643F88] diff --git a/include/ac_cottage.h b/include/ac_cottage.h index 01b13749..9ad8141f 100644 --- a/include/ac_cottage.h +++ b/include/ac_cottage.h @@ -2,14 +2,43 @@ #define AC_COTTAGE_H #include "types.h" -#include "m_actor.h" +#include "m_common_data.h" +#include "ac_structure.h" #ifdef __cplusplus extern "C" { #endif +typedef void (*COTTAGE_REWRITE_DOOR_PROC)(ACTOR*, GAME_PLAY*); +typedef void (*COTTAGE_SET_BG_OFFSET_PROC)(STRUCTURE_ACTOR*, int); +typedef int (*COTTAGE_CHECK_DOOR_IN_PROC)(STRUCTURE_ACTOR*, GAME_PLAY*); +typedef int (*COTTAGE_CHECK_DOOR_OUT_PROC)(STRUCTURE_ACTOR*, GAME_PLAY*); +typedef void (*COTTAGE_DEMO_DOOR_OPEN_PROC)(ACTOR*); +typedef f32 (*COTTAGE_LIGHT_AIM_PROC)(STRUCTURE_ACTOR*); +typedef void (*COTTAGE_LIGHT_CONTROL_PROC)(STRUCTURE_ACTOR*); + +typedef struct t_cottage_data_s { + cKF_Skeleton_R_c* skl; + cKF_Animation_R_c* in_anim; + cKF_Animation_R_c* out_anim; + s16 structure_type; + s16 structure_palette; + Gfx* model; + bIT_ShadowData_c* shadow_data; + mActor_name_t actor_name; + Door_data_c* door_data; + COTTAGE_REWRITE_DOOR_PROC rewrite_door_proc; // Checked? + COTTAGE_SET_BG_OFFSET_PROC set_bg_offset_proc; // Checked + COTTAGE_CHECK_DOOR_IN_PROC check_door_in_proc; // Maybe actor? + COTTAGE_CHECK_DOOR_OUT_PROC check_door_out_proc; // Maybe actor? + COTTAGE_DEMO_DOOR_OPEN_PROC demo_door_open_proc; // Checked + COTTAGE_LIGHT_AIM_PROC light_aim_proc; // Checked? + COTTAGE_LIGHT_CONTROL_PROC light_control_proc; // Checked +} COTTAGE_DATA; + extern ACTOR_PROFILE Cottage_My_Profile; extern ACTOR_PROFILE Cottage_Npc_Profile; + #ifdef __cplusplus } #endif diff --git a/include/m_common_data.h b/include/m_common_data.h index 589853d4..144a3ba7 100644 --- a/include/m_common_data.h +++ b/include/m_common_data.h @@ -348,6 +348,11 @@ extern common_data_t common_data; #define Able_Sisters_Umbrella_Palette_Get(idx) (Able_Sisters_Palette_Get(idx + mNW_CLOTH_DESIGN_NUM)) #define Able_Sisters_Umbrella_Design_Get(idx) (Able_Sisters_Design_Get(idx + mNW_CLOTH_DESIGN_NUM)) +#define Get_Villager(idx) (Save_Get(animals[idx])) + +#define Get_Island() (Save_Get(island)) +#define Get_Island_Villager() (Get_Island().animal) + extern void common_data_reinit(); extern void common_data_init(); extern void common_data_clear(); diff --git a/include/m_name_table.h b/include/m_name_table.h index 8309f383..c4831acd 100644 --- a/include/m_name_table.h +++ b/include/m_name_table.h @@ -2735,6 +2735,8 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define DUMMY_NAMEPLATE 0xF11F #define DUMMY_MUSEUM 0xF120 #define DUMMY_FLAG 0xF122 +#define DUMMY_COTTAGE_MY 0xF123 +#define DUMMY_COTTAGE_NPC 0xF124 #define DUMMY_TENT 0xF127 #define DUMMY_BOAT 0xF128 #define RSV_POLICE_ITEM_0 0xF128 // why is this duplicated? diff --git a/src/ac_cottage.c b/src/ac_cottage.c new file mode 100644 index 00000000..72456676 --- /dev/null +++ b/src/ac_cottage.c @@ -0,0 +1,982 @@ +#include "ac_cottage.h" + +#include "m_name_table.h" +#include "bg_item_h.h" +#include "m_common_data.h" +#include "m_house.h" +#include "m_player_lib.h" +#include "m_demo.h" +#include "ac_intro_demo.h" +#include "m_bgm.h" +#include "sys_matrix.h" +#include "m_rcp.h" +#include "libforest/gbi_extensions.h" + +enum { + Cottage_DATA_PLAYER_STANDARD, + Cottage_DATA_PLAYER_WINTER, + + Cottage_DATA_NPC_STANDARD, + Cottage_DATA_NPC_WINTER, + + Cottage_DATA_NUM +}; + +enum { + Cottage_ACTION_NONE, + Cottage_ACTION_DOOR_OPEN, + Cottage_ACTION_OPEN_PL_OUT_INIT, + Cottage_ACTION_OPEN_IN_INIT, + Cottage_ACTION_NPC_OUT_INIT, + Cottage_ACTION_SPEAK_GO_OUT, + + Cottage_ACTION_NUM +}; + +static void Cottage_my_actor_ct(ACTOR* actor, GAME* game); +static void Cottage_my_actor_dt(ACTOR* actor, GAME* game); + +static void Cottage_npc_actor_ct(ACTOR* actor, GAME* game); +static void Cottage_npc_actor_dt(ACTOR* actor, GAME* game); + +static void Cottage_actor_init(ACTOR* actor, GAME* game); +static void Cottage_actor_draw(ACTOR* actor, GAME* game); + +// clang-format off +ACTOR_PROFILE Cottage_My_Profile = { + mAc_PROFILE_COTTAGE_MY, + ACTOR_PART_ITEM, + ACTOR_STATE_TA_SET, + COTTAGE_MY, + ACTOR_OBJ_BANK_KEEP, + sizeof(STRUCTURE_ACTOR), + &Cottage_my_actor_ct, + &Cottage_my_actor_dt, + &Cottage_actor_init, + &Cottage_actor_draw, + NULL +}; +// clang-format on + +// clang-format off +ACTOR_PROFILE Cottage_Npc_Profile = { + mAc_PROFILE_COTTAGE_NPC, + ACTOR_PART_ITEM, + ACTOR_STATE_NONE, + COTTAGE_NPC, + ACTOR_OBJ_BANK_KEEP, + sizeof(STRUCTURE_ACTOR), + &Cottage_npc_actor_ct, + &Cottage_npc_actor_dt, + &Cottage_actor_init, + &Cottage_actor_draw, + NULL +}; +// clang-format on + +// clang-format off +static u8 Shadow_vtx_fix_flg_cottage_my[] = { + FALSE, FALSE, TRUE, TRUE, + FALSE, FALSE, TRUE, TRUE, + TRUE, TRUE, FALSE, FALSE, + FALSE, FALSE, TRUE, TRUE, + TRUE, FALSE, TRUE, FALSE, + FALSE, TRUE, FALSE, FALSE +}; +// clang-format on + +extern Vtx obj_s_myhome_i_shadow_v[]; +extern Gfx obj_s_myhome_i_shadowT_model[]; + +// clang-format off +static bIT_ShadowData_c bIT_DR_SHADOW_c_cottage_my = { + 22, + Shadow_vtx_fix_flg_cottage_my, + 60.0f, + obj_s_myhome_i_shadow_v, + obj_s_myhome_i_shadowT_model +}; +// clang-format on + +// clang-format off +static u8 Shadow_vtx_fix_flg_cottage_npc[] = { + TRUE, FALSE, FALSE, TRUE, + FALSE, FALSE, TRUE, TRUE, + TRUE, FALSE, FALSE, TRUE, + TRUE, FALSE, FALSE, TRUE, + TRUE, TRUE, FALSE, FALSE, + TRUE, TRUE, FALSE, FALSE, + TRUE, FALSE, FALSE, TRUE +}; +// clang-format on + +extern Vtx obj_s_house_i_shadow_v[]; +extern Gfx obj_s_house_i_shadowT_model[]; + +// clang-format off +static bIT_ShadowData_c bIT_DR_SHADOW_c_cottage_npc = { + 28, + Shadow_vtx_fix_flg_cottage_npc, + 60.0f, + obj_s_house_i_shadow_v, + obj_s_house_i_shadowT_model +}; +// clang-format on + +// clang-format off +static Door_data_c Door_data_cottage_my = { + SCENE_COTTAGE_MY, + mSc_DIRECT_NORTH, + FALSE, + 0, + {200, 0, 380}, + EMPTY_NO, + 1, + {0, 0, 0}, +}; +// clang-format on + +// clang-format off +static Door_data_c Door_data_cottage_npc = { + SCENE_COTTAGE_NPC, + mSc_DIRECT_NORTH, + FALSE, + 0, + {160, 0, 300}, + EMPTY_NO, + 1, + {0, 0, 0}, +}; +// clang-format on + +// My cottage +static void Cottage_my_rewrite_door(ACTOR* actor, GAME_PLAY* play); +static void Cottage_my_set_bgOffset(STRUCTURE_ACTOR* cottage, int offs); +static int Cottage_my_check_door_pl_in(STRUCTURE_ACTOR* cottage, GAME_PLAY* play); +static int Cottage_my_check_go_out(STRUCTURE_ACTOR* cottage, GAME_PLAY* play); +static void Cottage_my_demo_door_open(ACTOR* actor); +static f32 Cottage_my_light_aim(STRUCTURE_ACTOR* cottage); +static void Cottage_my_ctrl_light(STRUCTURE_ACTOR* cottage); + +extern cKF_Skeleton_R_c cKF_bs_r_obj_s_myhome_i; +extern cKF_Animation_R_c cKF_ba_r_obj_s_myhome_i; +extern cKF_Animation_R_c cKF_ba_r_obj_s_myhome_i_out; +extern Gfx obj_s_myhome_i_window_model[]; + +// NPC cottage +static void Cottage_npc_rewrite_door(ACTOR* actor, GAME_PLAY* play); +static void Cottage_npc_set_bgOffset(STRUCTURE_ACTOR* cottage, int offs); +static int Cottage_npc_check_door_pl_in(STRUCTURE_ACTOR* cottage, GAME_PLAY* play); +static int Cottage_npc_check_go_out(STRUCTURE_ACTOR* cottage, GAME_PLAY* play); +static void Cottage_npc_demo_door_open(ACTOR* actor); +static f32 Cottage_npc_light_aim(STRUCTURE_ACTOR* cottage); +static void Cottage_npc_ctrl_light(STRUCTURE_ACTOR* cottage); + +extern cKF_Skeleton_R_c cKF_bs_r_obj_s_house_i; +extern cKF_Animation_R_c cKF_ba_r_obj_s_house_i; +extern cKF_Animation_R_c cKF_ba_r_obj_s_house_i_out; +extern Gfx obj_s_house_i_window_model[]; + +// clang-format off +static const COTTAGE_DATA Cottage_data[4] = { + { + &cKF_bs_r_obj_s_myhome_i, // skl + &cKF_ba_r_obj_s_myhome_i, // in_anim + &cKF_ba_r_obj_s_myhome_i_out, // out_anim + aSTR_TYPE_COTTAGE_MY, // structure_type + aSTR_PAL_MYHOME_ISLAND, // structure_palette + obj_s_myhome_i_window_model, // model + &bIT_DR_SHADOW_c_cottage_my, // shadow_data + DUMMY_COTTAGE_MY, // actor_name + &Door_data_cottage_my, // door_data + &Cottage_my_rewrite_door, // rewrite_door_proc + &Cottage_my_set_bgOffset, // set_bg_offset_proc + &Cottage_my_check_door_pl_in, // check_door_in_proc + &Cottage_my_check_go_out, // check_door_out_proc + &Cottage_my_demo_door_open, // demo_door_open_proc + &Cottage_my_light_aim, // light_aim_proc + &Cottage_my_ctrl_light // light_control_proc + }, + + { + &cKF_bs_r_obj_s_myhome_i, // skl + &cKF_ba_r_obj_s_myhome_i, // in_anim + &cKF_ba_r_obj_s_myhome_i_out, // out_anim + aSTR_TYPE_COTTAGE_MY, // structure_type + aSTR_PAL_MYHOME_ISLAND, // structure_palette + obj_s_myhome_i_window_model, // model + &bIT_DR_SHADOW_c_cottage_my, // shadow_data + DUMMY_COTTAGE_MY, // actor_name + &Door_data_cottage_my, // door_data + &Cottage_my_rewrite_door, // rewrite_door_proc + &Cottage_my_set_bgOffset, // set_bg_offset_proc + &Cottage_my_check_door_pl_in, // check_door_in_proc + &Cottage_my_check_go_out, // check_door_out_proc + &Cottage_my_demo_door_open, // demo_door_open_proc + &Cottage_my_light_aim, // light_aim_proc + &Cottage_my_ctrl_light // light_control_proc + }, + + { + &cKF_bs_r_obj_s_house_i, // skl + &cKF_ba_r_obj_s_house_i, // in_anim + &cKF_ba_r_obj_s_house_i_out, // out_anim + aSTR_TYPE_COTTAGE_NPC, // structure_type + aSTR_PAL_HOUSE_I, // structure_palette + obj_s_house_i_window_model, // model + &bIT_DR_SHADOW_c_cottage_npc, // shadow_data + DUMMY_COTTAGE_NPC, // actor_name + &Door_data_cottage_npc, // door_data + &Cottage_npc_rewrite_door, // rewrite_door_proc + &Cottage_npc_set_bgOffset, // set_bg_offset_proc + &Cottage_npc_check_door_pl_in, // check_door_in_proc + &Cottage_npc_check_go_out, // check_door_out_proc + &Cottage_npc_demo_door_open, // demo_door_open_proc + &Cottage_npc_light_aim, // light_aim_proc + &Cottage_npc_ctrl_light // light_control_proc + }, + + { + &cKF_bs_r_obj_s_house_i, // skl + &cKF_ba_r_obj_s_house_i, // in_anim + &cKF_ba_r_obj_s_house_i_out, // out_anim + aSTR_TYPE_COTTAGE_NPC, // structure_type + aSTR_PAL_HOUSE_I, // structure_palette + obj_s_house_i_window_model, // model + &bIT_DR_SHADOW_c_cottage_npc, // shadow_data + DUMMY_COTTAGE_NPC, // actor_name + &Door_data_cottage_npc, // door_data + &Cottage_npc_rewrite_door, // rewrite_door_proc + &Cottage_npc_set_bgOffset, // set_bg_offset_proc + &Cottage_npc_check_door_pl_in, // check_door_in_proc + &Cottage_npc_check_go_out, // check_door_out_proc + &Cottage_npc_demo_door_open, // demo_door_open_proc + &Cottage_npc_light_aim, // light_aim_proc + &Cottage_npc_ctrl_light // light_control_proc + } +}; +// clang-format on + +static const COTTAGE_DATA* Cottage_data_get(STRUCTURE_ACTOR* cottage) { + return &Cottage_data[cottage->arg0]; +} + +static f32 Cottage_my_light_aim(STRUCTURE_ACTOR* cottage) { + return mRmTp_Index2LightSwitchStatus(mRmTp_LIGHT_SWITCH_COTTAGE_MY) ? 1.0f : 0.0f; +} + +static f32 Cottage_npc_light_aim(STRUCTURE_ACTOR* cottage) { + int now_sec; + Animal_c* island_villager; + mNPS_schedule_c* schedule; + + island_villager = &Get_Island_Villager(); + schedule = mNPS_get_schedule_area(&island_villager->id); + now_sec = Common_Get(time.now_sec); + + if (schedule != NULL && schedule->current_type == mNPS_SCHED_IN_HOUSE && island_villager->is_home != FALSE && + (now_sec >= (18 * mTM_SECONDS_IN_HOUR) || now_sec <= (5 * mTM_SECONDS_IN_HOUR)) && cottage->request_type != Cottage_ACTION_OPEN_PL_OUT_INIT) { + return 1.0f; + } + + return 0.0f; +} + +static void Cottage_my_ctrl_light(STRUCTURE_ACTOR* cottage) { + cottage->arg0_f = Cottage_my_light_aim(cottage); +} + +static void Cottage_npc_ctrl_light(STRUCTURE_ACTOR* cottage) { + f32 target; + target = Cottage_npc_light_aim(cottage); + chase_f(&cottage->arg0_f, target, 0.019532442f); +} + +static void Cottage_set_doorSE(STRUCTURE_ACTOR* cottage) { + static const f32 chk_pat_in[] = { 10.0f, 14.0f, 35.0f, 50.0f }; + static const f32 chk_pat_out[] = { 2.0f, 8.0f, 33.0f, 40.0f }; + + static const u16 se_no[] = { 6, 7, 8, 9 }; + + const f32* chk_pat_p; + int i; + + switch (cottage->request_type) { + case Cottage_ACTION_DOOR_OPEN: + case Cottage_ACTION_OPEN_IN_INIT: + chk_pat_p = chk_pat_in; + break; + default: + chk_pat_p = chk_pat_out; + break; + } + + for (i = 0; i < 4; ++i, chk_pat_p++) { + if (cKF_FrameControl_passCheck_now(&cottage->keyframe.frame_control, *chk_pat_p) != FALSE) { + sAdo_OngenTrgStart(se_no[i], &cottage->actor_class.world.position); + break; + } + } +} + +static int Cottage_my_check_door_pl_in(STRUCTURE_ACTOR* cottage, GAME_PLAY* play) { + f32 xOffs; + f32 zOffs; + int y; + PLAYER_ACTOR* player; + + player = GET_PLAYER_ACTOR(play); + + if (player != NULL) { + xOffs = (player->actor_class.world.position.x - (cottage->actor_class.world.position.x + 20.0f)); + zOffs = (player->actor_class.world.position.z - (cottage->actor_class.world.position.z + 20.0f)); + + if ((SQ(xOffs) + SQ(zOffs)) < 1600.0f && (xOffs + zOffs) < 40.0f) { + y = player->actor_class.shape_info.rotation.y; + if (y > -DEG2SHORT_ANGLE(180.0f) && y < -DEG2SHORT_ANGLE(90.0f) && chkTrigger(BUTTON_A) != FALSE) { + return TRUE; + } + } + } + + return FALSE; +} + +static int Cottage_npc_check_door_pl_in(STRUCTURE_ACTOR* cottage, GAME_PLAY* play) { + PLAYER_ACTOR* player; + const COTTAGE_DATA* cottage_data; + + player = GET_PLAYER_ACTOR(play); + cottage_data = Cottage_data_get(cottage); + + return (player != NULL && player->item_in_front == cottage_data->actor_name && chkTrigger(BUTTON_A) != FALSE); +} + +static int Cottage_my_check_go_out(STRUCTURE_ACTOR* cottage, GAME_PLAY* play) { + return FALSE; +} + +static int Cottage_npc_check_go_out(STRUCTURE_ACTOR* cottage, GAME_PLAY* play) { + Animal_c* island_villager; + mNPS_schedule_c* schedule; + int res; + + island_villager = &Get_Island_Villager(); + schedule = mNPS_get_schedule_area(&island_villager->id); + res = FALSE; + + if (island_villager->is_home != FALSE && schedule != NULL && schedule->current_type == mNPS_SCHED_SLEEP) { + res = TRUE; + } + + return res; +} + +static int Cottage_check_door_action(STRUCTURE_ACTOR* cottage, GAME_PLAY* play) { + const COTTAGE_DATA* cottage_data; + int res; + int request_type; + + GET_PLAYER_ACTOR(play); + res = Cottage_ACTION_NONE; + cottage_data = Cottage_data_get(cottage); + + request_type = cottage->request_type; + if ((*cottage_data->check_door_in_proc)(cottage, play) != FALSE) { + if ((*cottage_data->check_door_out_proc)(cottage, play) != FALSE) { + res = Cottage_ACTION_SPEAK_GO_OUT; + } else { + res = Cottage_ACTION_DOOR_OPEN; + cottage->request_type = Cottage_ACTION_OPEN_IN_INIT; + } + } else { + if (request_type == Cottage_ACTION_DOOR_OPEN) { + res = Cottage_ACTION_OPEN_IN_INIT; + } else if (request_type == Cottage_ACTION_OPEN_PL_OUT_INIT) { + res = Cottage_ACTION_NPC_OUT_INIT; + } else if (request_type == Cottage_ACTION_NPC_OUT_INIT && mPlib_check_player_outdoor_start(&play->game) != FALSE) { + res = Cottage_ACTION_OPEN_PL_OUT_INIT; + } + } + + return res; +} + +static void Cottage_reset_door_action(STRUCTURE_ACTOR* cottage) { + cottage->request_type = Cottage_ACTION_NONE; + cottage->arg1 = Cottage_ACTION_NONE; +} + +static void Cottage_my_set_bgOffset(STRUCTURE_ACTOR* cottage, int offs) { + // clang-format off + static const s_xz unit_offset[] = { + { -1, -1 }, + { 0, -1 }, + { 1, -1 }, + { 2, -1 }, + { -1, 0 }, + { 0, 0 }, + { 1, 0 }, + { 2, 0 }, + { -1, 1 }, + { 0, 1 }, + { 1, 1 }, + { 2, 1 }, + { -1, 2 }, + { 0, 2 }, + { 1, 2 }, + { 2, 2 } + }; + // clang-format on + + // clang-format off + static const mCoBG_OffsetTable_c rewrite_data[] = { + { mCoBG_ATTRIBUTE_NONE, 4, 4, 4, 4, 4, 0 }, + { mCoBG_ATTRIBUTE_NONE, 10, 4, 10, 10, 10, 1 }, + { mCoBG_ATTRIBUTE_NONE, 10, 10, 10, 10, 4, 1 }, + { mCoBG_ATTRIBUTE_NONE, 4, 4, 4, 4, 4, 0 }, + { mCoBG_ATTRIBUTE_NONE, 10, 4, 10, 10, 10, 1 }, + { mCoBG_ATTRIBUTE_NONE, 10, 10, 10, 10, 10, 0 }, + { mCoBG_ATTRIBUTE_NONE, 10, 10, 10, 10, 10, 0 }, + { mCoBG_ATTRIBUTE_NONE, 4, 4, 4, 4, 4, 0 }, + { mCoBG_ATTRIBUTE_NONE, 10, 10, 4, 10, 10, 1 }, + { mCoBG_ATTRIBUTE_NONE, 10, 10, 10, 10, 10, 0 }, + { mCoBG_ATTRIBUTE_NONE, 10, 10, 10, 0, 10, 1 }, + { mCoBG_ATTRIBUTE_NONE, 0, 0, 0, 0, 0, 0 }, + { mCoBG_ATTRIBUTE_NONE, 4, 4, 4, 4, 4, 0 }, + { mCoBG_ATTRIBUTE_NONE, 4, 4, 4, 4, 4, 0 }, + { mCoBG_ATTRIBUTE_NONE, 0, 0, 0, 0, 0, 0 }, + { mCoBG_ATTRIBUTE_NONE, 0, 0, 0, 0, 0, 0 } + }; + // clang-format on + + xyz_t pos; + int i; + + pos.y = 0.0f; + for (i = 0; i < 16; i++) { + pos.x = cottage->actor_class.home.position.x + ((mFI_UT_WORLDSIZE_X_F * (f32)unit_offset[i].x)); + pos.z = cottage->actor_class.home.position.z + ((mFI_UT_WORLDSIZE_Z_F * (f32)unit_offset[i].z)); + + mCoBG_SetPluss5PointOffset_file(pos, rewrite_data[i], __FILE__, 787); + } +} + +static void Cottage_npc_set_bgOffset(STRUCTURE_ACTOR* cottage, int offs) { + // clang-format off + static mCoBG_OffsetTable_c height_table_ct[] = { + { mCoBG_ATTRIBUTE_NONE, 7, 7, 7, 7, 7, 0 }, + { mCoBG_ATTRIBUTE_NONE, 0, 0, 0, 0, 0, 0 }, + { mCoBG_ATTRIBUTE_NONE, 7, 7, 7, 7, 7, 0 }, + { mCoBG_ATTRIBUTE_NONE, 7, 7, 7, 7, 7, 0 }, + { mCoBG_ATTRIBUTE_NONE, 7, 7, 7, 7, 7, 0 }, + { mCoBG_ATTRIBUTE_NONE, 7, 7, 7, 7, 7, 0 }, + { mCoBG_ATTRIBUTE_NONE, 7, 7, 7, 7, 7, 0 }, + { mCoBG_ATTRIBUTE_NONE, 7, 7, 7, 7, 7, 0 }, + { mCoBG_ATTRIBUTE_NONE, 7, 7, 7, 7, 7, 0 } + }; + // clang-format on + + static mCoBG_OffsetTable_c* height_table[] = { height_table_ct, height_table_ct }; + + static f32 addX[] = { -mFI_UT_WORLDSIZE_X_F, 0.0f, mFI_UT_WORLDSIZE_X_F }; + static f32 addZ[] = { mFI_UT_WORLDSIZE_Z_F, 0.0f, -mFI_UT_WORLDSIZE_Z_F }; + + mCoBG_OffsetTable_c* offset; + int i; + xyz_t pos; + + offset = height_table[offs]; + for (i = 0; i < 3; i++) { + pos.z = cottage->actor_class.home.position.z + addZ[i]; + + pos.x = cottage->actor_class.home.position.x + addX[0]; + mCoBG_SetPluss5PointOffset_file(pos, offset[0], __FILE__, 836); + + pos.x = cottage->actor_class.home.position.x + addX[1]; + mCoBG_SetPluss5PointOffset_file(pos, offset[1], __FILE__, 840); + + pos.x = cottage->actor_class.home.position.x + addX[2]; + mCoBG_SetPluss5PointOffset_file(pos, offset[2], __FILE__, 844); + + offset += 3; + } +} + +static void Cottage_change_FGUnit(ACTOR* actor, int type) { + xyz_t pos; + + xyz_t_move(&pos, &actor->world.position); + pos.z += 80.0f; + + if (type == 0) { + return; + } + + mFI_SetFG_common(RSV_NO, pos, TRUE); +} + +static void Cottage_my_rewrite_door(ACTOR* actor, GAME_PLAY* play) { + Door_data_c* door_data; + xyz_t pos; + + door_data = Common_GetPointer(structure_exit_door_data); + if (play->fb_wipe_mode != 0) { + return; + } + + door_data->next_scene_id = Save_Get(scene_no); + door_data->exit_orientation = mSc_DIRECT_SOUTH_EAST; + door_data->exit_type = 0; + door_data->extra_data = 2; + + pos.x = actor->world.position.x + 48.29f; + pos.z = actor->world.position.z + 48.29f; + pos.y = mCoBG_GetBgY_OnlyCenter_FromWpos2(pos, 0.0f); + + door_data->exit_position.x = pos.x; + door_data->exit_position.y = pos.y; + door_data->exit_position.z = pos.z; + + door_data->door_actor_name = actor->npc_id; + + door_data->wipe_type = 1; + + Common_Get(house_owner_name) = 0; +} + +static void Cottage_npc_rewrite_door(ACTOR* actor, GAME_PLAY* play) { + Door_data_c* door_data; + xyz_t pos; + + door_data = Common_GetPointer(structure_exit_door_data); + if (play->fb_wipe_mode != 0) { + return; + } + + door_data->next_scene_id = Save_Get(scene_no); + door_data->exit_orientation = mSc_DIRECT_SOUTH; + door_data->exit_type = 0; + door_data->extra_data = 2; + + pos.x = actor->home.position.x; + pos.z = actor->home.position.z + 60.0f; + pos.y = mCoBG_GetBgY_OnlyCenter_FromWpos2(pos, 0.0f); + + door_data->exit_position.x = pos.x; + door_data->exit_position.y = pos.y; + door_data->exit_position.z = pos.z; + + door_data->door_actor_name = actor->npc_id; + + door_data->wipe_type = 1; + + Common_Get(house_owner_name) = 0; +} + +static void Cottage_my_demo_door_open(ACTOR* actor) { + mDemo_Set_house_info(0.0f, 3); + mDemo_Set_camera(CAMERA2_PROCESS_DOOR); +} + +static void Cottage_npc_demo_door_open(ACTOR* actor) { + mDemo_Set_house_info(40.0f, 4); + mDemo_Set_camera(CAMERA2_PROCESS_DOOR); +} + +static void Cottage_demo_speak_go_out(ACTOR* actor) { + static rgba_t window_color = { 145, 60, 40, 255 }; + + Animal_c* island_villager; + u8 looks; + + island_villager = &Get_Island_Villager(); + + looks = mNpc_GetLooks(island_villager->id.npc_id); + mDemo_Set_msg_num((looks & 0xFF) + 0x2AFF); + mDemo_Set_talk_display_name(FALSE); + mDemo_Set_camera(TRUE); + mPlib_Set_able_hand_all_item_in_demo(TRUE); + mDemo_Set_ListenAble(); + mDemo_Set_talk_window_color(&window_color); +} + +static void Cottage_actor_ct(ACTOR* actor, GAME* game) { + STRUCTURE_ACTOR* cottage; + cKF_SkeletonInfo_R_c* keyframe; + const COTTAGE_DATA* cottage_data; + + cottage = (STRUCTURE_ACTOR*)actor; + keyframe = &cottage->keyframe; + cottage_data = Cottage_data_get(cottage); + cKF_SkeletonInfo_R_ct(keyframe, cottage_data->skl, NULL, cottage->work_area, cottage->morph_area); + cKF_SkeletonInfo_R_init(keyframe, keyframe->skeleton, cottage_data->in_anim, 1.0f, 51.0f, 1.0f, 0.5f, 0.0f, cKF_FRAMECONTROL_STOP, + NULL); + cKF_SkeletonInfo_R_play(keyframe); + (*cottage_data->set_bg_offset_proc)(cottage, 1); + cottage->arg0_f = (*cottage_data->light_aim_proc)(cottage); +} + +static void Cottage_move_closed_init(STRUCTURE_ACTOR* cottage); + +static void Cottage_my_actor_ct(ACTOR* actor, GAME* game) { + STRUCTURE_ACTOR* cottage; + + cottage = (STRUCTURE_ACTOR*)actor; + + if (Common_Get(time.season) == mTM_SEASON_WINTER) { + cottage->arg0 = Cottage_DATA_PLAYER_WINTER; + } else { + cottage->arg0 = Cottage_DATA_PLAYER_STANDARD; + } + + actor->world.position.x += 20.0f; + actor->world.position.z += 20.0f; + + Cottage_actor_ct(actor, game); + Cottage_move_closed_init(cottage); +} + +static void Cottage_npc_actor_ct(ACTOR* actor, GAME* game) { + STRUCTURE_ACTOR* cottage; + + cottage = (STRUCTURE_ACTOR*)actor; + + if (Common_Get(time.season) == mTM_SEASON_WINTER) { + cottage->arg0 = Cottage_DATA_NPC_WINTER; + } else { + cottage->arg0 = Cottage_DATA_NPC_STANDARD; + } + + Cottage_actor_ct(actor, game); + Cottage_change_FGUnit(actor, 1); + Cottage_move_closed_init(cottage); +} + +static void Cottage_actor_dt(ACTOR* actor, GAME* game) { + STRUCTURE_ACTOR* cottage; + + cottage = (STRUCTURE_ACTOR*)actor; + cKF_SkeletonInfo_R_dt(&cottage->keyframe); +} + +static void Cottage_my_actor_dt(ACTOR* actor, GAME* game) { + Cottage_actor_dt(actor, game); +} + +static void Cottage_npc_actor_dt(ACTOR* actor, GAME* game) { + Cottage_change_FGUnit(actor, 0); + Cottage_actor_dt(actor, game); +} + +static void Cottage_move_closed(STRUCTURE_ACTOR* cottage, GAME_PLAY* play); + +static void Cottage_move_closed_init(STRUCTURE_ACTOR* cottage) { + Cottage_reset_door_action(cottage); + cottage->action_proc = &Cottage_move_closed; +} + +static void Cottage_move_wait_pl_in_init(STRUCTURE_ACTOR* cottage); +static void Cottage_move_wait_pl_out_init(STRUCTURE_ACTOR* cottage); +static void Cottage_move_open_in_init(STRUCTURE_ACTOR* cottage); +static void Cottage_move_open_pl_out_init(STRUCTURE_ACTOR* cottage); +static void Cottage_move_open_npc_out_init(STRUCTURE_ACTOR* cottage); + +static void Cottage_move_closed(STRUCTURE_ACTOR* cottage, GAME_PLAY* play) { + int door_action; + const COTTAGE_DATA* cottage_data; + + if (mDemo_Check(mDemo_TYPE_DOOR, &cottage->actor_class) != FALSE) { + if (cottage->arg1 == Cottage_ACTION_DOOR_OPEN) { + Cottage_move_wait_pl_in_init(cottage); + } else { + Cottage_move_wait_pl_out_init(cottage); + } + return; + } + + if (mDemo_Check(mDemo_TYPE_SPEAK, &cottage->actor_class) != FALSE) { + return; + } + + door_action = Cottage_check_door_action(cottage, play); + cottage_data = Cottage_data_get(cottage); + if (door_action != Cottage_ACTION_NONE) { + cottage->arg1 = door_action; + } + + if (door_action == Cottage_ACTION_DOOR_OPEN) { + mDemo_Request(mDemo_TYPE_DOOR, &cottage->actor_class, cottage_data->demo_door_open_proc); + } else if (door_action == Cottage_ACTION_OPEN_IN_INIT) { + Cottage_move_open_in_init(cottage); + } else if (door_action == Cottage_ACTION_OPEN_PL_OUT_INIT) { + Cottage_move_open_pl_out_init(cottage); + } else if (door_action == Cottage_ACTION_NPC_OUT_INIT) { + Cottage_move_open_npc_out_init(cottage); + } else if (door_action == Cottage_ACTION_SPEAK_GO_OUT) { + mDemo_Request(mDemo_TYPE_SPEAK, &cottage->actor_class, &Cottage_demo_speak_go_out); + } +} + +static void Cottage_move_wait_pl_in(STRUCTURE_ACTOR* cottage, GAME_PLAY* play); + +static void Cottage_move_wait_pl_in_init(STRUCTURE_ACTOR* cottage) { + cottage->action_proc = &Cottage_move_wait_pl_in; +} + +static void Cottage_move_wait_pl_in(STRUCTURE_ACTOR* cottage, GAME_PLAY* play) { + if ((*GET_PLAYER_ACTOR_NOW()->get_door_label_proc)(gamePT) != cottage) { + return; + } + + mBGMPsComp_make_ps_wipe(0x249); + Cottage_move_open_in_init(cottage); +} + +static void Cottage_move_wait_pl_out(STRUCTURE_ACTOR* cottage, GAME_PLAY* play); + +static void Cottage_move_wait_pl_out_init(STRUCTURE_ACTOR* cottage) { + cottage->action_proc = &Cottage_move_wait_pl_out; +} + +static void Cottage_move_wait_pl_out(STRUCTURE_ACTOR* cottage, GAME_PLAY* play) { + if (mPlib_check_player_outdoor_start(&play->game) == FALSE) { + return; + } + + Cottage_move_open_pl_out_init(cottage); +} + +static void Cottage_move_open_in(STRUCTURE_ACTOR* cottage, GAME_PLAY* play); + +static void Cottage_move_open_in_init(STRUCTURE_ACTOR* cottage) { + const COTTAGE_DATA* cottage_data; + cKF_SkeletonInfo_R_c* keyframe; + + keyframe = &cottage->keyframe; + cottage_data = Cottage_data_get(cottage); + + cKF_SkeletonInfo_R_init(keyframe, keyframe->skeleton, cottage_data->in_anim, 1.0f, 51.0f, 1.0f, 0.5f, 0.0f, cKF_FRAMECONTROL_STOP, + NULL); + cottage->action_proc = &Cottage_move_open_in; +} + +static void Cottage_move_next_init(STRUCTURE_ACTOR* cottage); + +static void Cottage_move_open_in(STRUCTURE_ACTOR* cottage, GAME_PLAY* play) { + const COTTAGE_DATA* cottage_data; + + Cottage_set_doorSE(cottage); + if (cKF_SkeletonInfo_R_play(&cottage->keyframe) != cKF_STATE_STOPPED) { + return; + } + + if (cottage->arg1 == Cottage_ACTION_DOOR_OPEN) { + cottage_data = Cottage_data_get(cottage); + + (*cottage_data->rewrite_door_proc)(&cottage->actor_class, play); + + goto_other_scene(play, cottage_data->door_data, FALSE); + + play->fb_fade_type = 9; + mDemo_End(&cottage->actor_class); + + Cottage_move_next_init(cottage); + } else { + Cottage_move_closed_init(cottage); + } +} + +static void Cottage_move_open_out(STRUCTURE_ACTOR* cottage, GAME_PLAY* play); + +static void Cottage_move_open_pl_out_init(STRUCTURE_ACTOR* cottage) { + const COTTAGE_DATA* cottage_data; + cKF_SkeletonInfo_R_c* keyframe; + + keyframe = &cottage->keyframe; + cottage_data = Cottage_data_get(cottage); + cKF_SkeletonInfo_R_init(keyframe, keyframe->skeleton, cottage_data->out_anim, 25.0f, 51.0f, 25.0f, 0.5f, 0.0f, + cKF_FRAMECONTROL_STOP, NULL); + cottage->action_proc = Cottage_move_open_out; +} + +static void Cottage_move_open_npc_out_init(STRUCTURE_ACTOR* cottage) { + const COTTAGE_DATA* cottage_data; + cKF_SkeletonInfo_R_c* keyframe; + + keyframe = &cottage->keyframe; + cottage_data = Cottage_data_get(cottage); + cKF_SkeletonInfo_R_init(keyframe, keyframe->skeleton, cottage_data->out_anim, 1.0f, 51.0f, 1.0f, 0.5f, 0.0f, + cKF_FRAMECONTROL_STOP, NULL); + cottage->action_proc = Cottage_move_open_out; +} + +static void Cottage_move_open_out(STRUCTURE_ACTOR* cottage, GAME_PLAY* play) { + Cottage_set_doorSE(cottage); + if (cKF_SkeletonInfo_R_play(&cottage->keyframe) != cKF_STATE_STOPPED) { + return; + } + + Cottage_move_closed_init(cottage); +} + +static void Cottage_move_next(STRUCTURE_ACTOR* cottage, GAME_PLAY* play); + +static void Cottage_move_next_init(STRUCTURE_ACTOR* cottage) { + cottage->action_proc = &Cottage_move_next; +} + +static void Cottage_move_next(STRUCTURE_ACTOR* cottage, GAME_PLAY* play) { +} + +static void Cottage_actor_move(ACTOR* actor, GAME* game) { + const COTTAGE_DATA* cottage_data; + STRUCTURE_ACTOR* cottage; + GAME_PLAY* play; + + cottage = (STRUCTURE_ACTOR*)actor; + play = (GAME_PLAY*)game; + + cottage_data = Cottage_data_get(cottage); + (*cottage->action_proc)(cottage, play); + (*cottage_data->light_control_proc)(cottage); +} + +static void Cottage_actor_init(ACTOR* actor, GAME* game) { + const COTTAGE_DATA* cottage_data; + STRUCTURE_ACTOR* cottage; + xyz_t pos; + + cottage = (STRUCTURE_ACTOR*)actor; + + cottage_data = Cottage_data_get(cottage); + + pos = actor->home.position; + mFI_SetFG_common(cottage_data->actor_name, pos, FALSE); + + Cottage_actor_move(actor, game); + actor->mv_proc = Cottage_actor_move; +} + +static int Cottage_actor_draw_before(GAME* game, cKF_SkeletonInfo_R_c* keyframe, int joint_idx, Gfx** joint_shape, + u8* joint_flags, void* arg, s_xyz* joint_rot, xyz_t* joint_pos) { + STRUCTURE_ACTOR* cottage; + GRAPH* graph; + f32 color; + Gfx* gfx; + + cottage = (STRUCTURE_ACTOR*)arg; + graph = game->graph; + + if (joint_idx == 5) { + OPEN_DISP(graph); + color = cottage->arg0_f; + gfx = NOW_POLY_OPA_DISP; + + gDPSetPrimColor(gfx++, 0, 0, (int)(0.5f + (255.0f * color)), (int)(0.5f + (255.0f * color)), + (int)(0.5f + (150.0f * color)), 255); + + SET_POLY_OPA_DISP(gfx); + CLOSE_DISP(graph); + } + + if (joint_idx == 6) { + *joint_shape = NULL; + } + + return TRUE; +} + +static int Cottage_actor_draw_after(GAME* game, cKF_SkeletonInfo_R_c* keyframe, int joint_idx, Gfx** joint_shape, + u8* joint_flags, void* arg, s_xyz* joint_rot, xyz_t* joint_pos) { + + GRAPH* graph; + Mtx* mtx; + const COTTAGE_DATA* cottage_data; + int l; + int r; + int g; + int b; + STRUCTURE_ACTOR* cottage; + Gfx* gfx; + + cottage = (STRUCTURE_ACTOR*)arg; + graph = game->graph; + + if (joint_idx == 6) { + mtx = _Matrix_to_Mtx_new(graph); + + if (mtx != NULL) { + cottage_data = Cottage_data_get(cottage); + if (cottage->arg0_f > 0.0f) { + r = 255; + g = 255; + b = 150; + l = (0.5f + (120.0f * cottage->arg0_f)); + } else { + l = 0; + r = 0; + g = 0; + b = 0; + } + + _texture_z_light_fog_prim_shadow(graph); + + OPEN_DISP(graph); + gfx = NOW_SHADOW_DISP; + + gDPSetPrimColor(gfx++, 0, l, r, g, b, 0); + gSPMatrix(gfx++, mtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + + gSPLoadGeometryMode(gfx++, G_ZBUFFER | G_SHADE | G_CULL_BACK | G_FOG | G_SHADING_SMOOTH | 0x00000050); + gSPDisplayList(gfx++, cottage_data->model); + + gSPLoadGeometryMode(gfx++, G_ZBUFFER | G_SHADE | G_CULL_BACK | G_FOG | G_SHADING_SMOOTH | 0x00000040); + gSPDisplayList(gfx++, cottage_data->model); + + gSPClearGeometryMode(gfx++, 0x00000050); + + SET_SHADOW_DISP(gfx); + CLOSE_DISP(graph); + } + } + + return TRUE; +} + +static void Cottage_actor_draw(ACTOR* actor, GAME* game) { + GRAPH* graph; + cKF_SkeletonInfo_R_c* keyframe; + Mtx* mtx; + const COTTAGE_DATA* cottage_data; + Gfx* gfx; + u16* pal; + GAME_PLAY* play; + STRUCTURE_ACTOR* cottage; + + graph = game->graph; + play = (GAME_PLAY*)game; + cottage = (STRUCTURE_ACTOR*)actor; + cottage_data = Cottage_data_get(cottage); + keyframe = &cottage->keyframe; + + mtx = GRAPH_ALLOC_TYPE(graph, Mtx, (u32)keyframe->skeleton->num_shown_joints); + if (mtx == NULL) { + return; + } + + pal = Common_Get(clip).structure_clip->get_pal_segment_proc(cottage_data->structure_palette); + + _texture_z_light_fog_prim_npc(graph); + + OPEN_DISP(graph); + gfx = NOW_POLY_OPA_DISP; + + gSPSegment(gfx++, G_MWO_SEGMENT_8, pal); + + SET_POLY_OPA_DISP(gfx); + CLOSE_DISP(graph); + + cKF_Si3_draw_R_SV(game, keyframe, mtx, &Cottage_actor_draw_before, &Cottage_actor_draw_after, actor); + (*Common_Get(clip).bg_item_clip->draw_shadow_proc)(game, cottage_data->shadow_data, TRUE); +}