From 80c63841ea7cdd05007eb1965bd871bcd7f6ef8b Mon Sep 17 00:00:00 2001 From: Hexalotl <15166449+Hexalotl@users.noreply.github.com> Date: Fri, 22 Mar 2024 13:44:48 -0700 Subject: [PATCH] Implement & link ac_post_office (#312) --- config/rel_slices.yml | 4 + include/ac_post_office.h | 2 +- include/m_name_table.h | 1 + src/ac_post_office.c | 117 ++++++++++++++ src/ac_post_office_draw.c_inc | 165 +++++++++++++++++++ src/ac_post_office_move.c_inc | 293 ++++++++++++++++++++++++++++++++++ 6 files changed, 581 insertions(+), 1 deletion(-) create mode 100644 src/ac_post_office.c create mode 100644 src/ac_post_office_draw.c_inc create mode 100644 src/ac_post_office_move.c_inc diff --git a/config/rel_slices.yml b/config/rel_slices.yml index 43837485..aef920db 100644 --- a/config/rel_slices.yml +++ b/config/rel_slices.yml @@ -798,6 +798,10 @@ ac_needlework_shop.c: .text: [0x805B65C4, 0x805B7338] .rodata: [0x8064AAA0, 0x8064AAE8] .data: [0x806C6138, 0x806C62D0] +ac_post_office.c: + .text: [0x805B7B0C, 0x805B887C] + .rodata: [0x8064AB18, 0x8064AB58] + .data: [0x806C63C0, 0x806C6558] ac_radio.c: .text: [0x805B887C, 0x805B8C7C] .rodata: [0x8064AB58, 0x8064AB68] diff --git a/include/ac_post_office.h b/include/ac_post_office.h index fc270101..4fffdd8c 100644 --- a/include/ac_post_office.h +++ b/include/ac_post_office.h @@ -2,7 +2,7 @@ #define AC_POST_OFFICE_H #include "types.h" -#include "m_actor.h" +#include "ac_structure.h" #ifdef __cplusplus extern "C" { diff --git a/include/m_name_table.h b/include/m_name_table.h index dde35fab..9935fa74 100644 --- a/include/m_name_table.h +++ b/include/m_name_table.h @@ -2712,6 +2712,7 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define DUMMY_HANIWA1 (DUMMY_HANIWA0 + 1) #define DUMMY_HANIWA2 (DUMMY_HANIWA1 + 1) #define DUMMY_HANIWA3 (DUMMY_HANIWA2 + 1) +#define DUMMY_POST_OFFICE 0xF0FF #define DUMMY_NEEDLEWORK_SHOP 0xF0FF #define DUMMY_RESERVE 0xF102 #define DUMMY_SHRINE 0xF103 diff --git a/src/ac_post_office.c b/src/ac_post_office.c new file mode 100644 index 00000000..d7623b4c --- /dev/null +++ b/src/ac_post_office.c @@ -0,0 +1,117 @@ +#include "ac_post_office.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 { + aPOFF_ACTION_WAIT, + aPOFF_ACTION_OPEN_DOOR_WAIT, + aPOFF_ACTION_OPEN_DOOR, + aPOFF_ACTION_OPEN_UNKNOWN, + + aPOFF_ACTION_NUM +}; + +static void aPOFF_actor_ct(ACTOR* actor, GAME* game); +static void aPOFF_actor_dt(ACTOR* actor, GAME* game); +static void aPOFF_actor_init(ACTOR* actor, GAME* game); +static void aPOFF_actor_draw(ACTOR* actor, GAME* game); + +// clang-format off +ACTOR_PROFILE Post_Office_Profile = { + mAc_PROFILE_POST_OFFICE, + ACTOR_PART_ITEM, + ACTOR_STATE_NONE, + POST_OFFICE, + ACTOR_OBJ_BANK_KEEP, + sizeof(STRUCTURE_ACTOR), + &aPOFF_actor_ct, + &aPOFF_actor_dt, + &aPOFF_actor_init, + &aPOFF_actor_draw, + NULL +}; +// clang-format on + +// clang-format off +static u8 aPOFF_shadow_vtx_fix_flg_table[] = { + TRUE, FALSE, FALSE, TRUE, + FALSE, TRUE, FALSE, TRUE, + TRUE, FALSE, TRUE, FALSE, + FALSE, TRUE, FALSE, FALSE +}; +// clang-format on + +extern Vtx obj_s_yubinkyoku_shadow_v[]; +extern Gfx obj_s_yubinkyoku_shadow_2_model[]; + +// clang-format off +static bIT_ShadowData_c aPOFF_shadow_data = { + 14, + aPOFF_shadow_vtx_fix_flg_table, + 60.0f, + obj_s_yubinkyoku_shadow_v, + obj_s_yubinkyoku_shadow_2_model +}; +// clang-format on + +extern cKF_Skeleton_R_c cKF_bs_r_obj_s_yubinkyoku; +extern cKF_Skeleton_R_c cKF_bs_r_obj_w_yubinkyoku; + +static void aPOFF_set_bgOffset(STRUCTURE_ACTOR* office, int idx); +static void aPOFF_setup_animation(STRUCTURE_ACTOR* office, f32 speed); +static void aPOFF_setup_action(STRUCTURE_ACTOR* office, int action); +static int aPOFF_ctrl_light(STRUCTURE_ACTOR* office); + +static void aPOFF_actor_ct(ACTOR* actor, GAME* game) { + static cKF_Skeleton_R_c* skl[] = { &cKF_bs_r_obj_s_yubinkyoku, &cKF_bs_r_obj_w_yubinkyoku }; + + STRUCTURE_ACTOR* office; + + office = (STRUCTURE_ACTOR*)actor; + office->season = Common_Get(time.season); + cKF_SkeletonInfo_R_ct(&office->keyframe, skl[office->season == mTM_SEASON_WINTER], NULL, office->work_area, + office->morph_area); + + aPOFF_set_bgOffset(office, 1); + + actor->world.position.x = actor->world.position.x + -20.0f; + actor->world.position.z = actor->world.position.z + 20.0f; + actor->cull_width = 500.0f; + actor->cull_distance = 500.0f; + + office->request_type = 0; + aPOFF_setup_animation(office, 0.0f); + aPOFF_setup_action(office, aPOFF_ACTION_WAIT); + + office->keyframe_state = cKF_SkeletonInfo_R_play(&office->keyframe); + office->keyframe_saved_keyframe = 1; + + if (aPOFF_ctrl_light(office)) { + office->action = DEG2SHORT_ANGLE(90.0f) - 1; // 0x3FFF + } else { + office->action = DEG2SHORT_ANGLE(0.0f); + } +} + +static void aPOFF_actor_dt(ACTOR* actor, GAME* game) { + STRUCTURE_ACTOR* office; + + office = (STRUCTURE_ACTOR*)actor; + cKF_SkeletonInfo_R_dt(&office->keyframe); + actor->world.position.x -= -20.0f; + actor->world.position.z -= 20.0f; +} + +#include "../src/ac_post_office_move.c_inc" + +#include "../src/ac_post_office_draw.c_inc" diff --git a/src/ac_post_office_draw.c_inc b/src/ac_post_office_draw.c_inc new file mode 100644 index 00000000..5a627800 --- /dev/null +++ b/src/ac_post_office_draw.c_inc @@ -0,0 +1,165 @@ +extern Gfx obj_s_yubinkyoku_window_model[]; +extern Gfx obj_w_yubinkyoku_window_model[]; + +static int aPOFF_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) { + GRAPH* graph; + STRUCTURE_ACTOR* office; + f32 inter; + int angle; + int r; + int g; + int b; + Gfx* gfx; + + graph = game->graph; + office = (STRUCTURE_ACTOR*)arg; + if (joint_idx == 1) { + angle = office->action; + if (angle == DEG2SHORT_ANGLE(90.0f) - 1) { // 0x3FFF + r = 255; + g = 255; + b = 150; + } else if (angle == DEG2SHORT_ANGLE(0.0f)) { + r = 0; + g = 0; + b = 0; + } else { + inter = (1.0f / (DEG2SHORT_ANGLE(90.0f) - 1)) * angle; + r = (255.0f * inter); + g = (255.0f * inter); + b = (150.0f * inter); + } + + OPEN_DISP(graph); + gfx = NOW_POLY_OPA_DISP; + + gDPSetPrimColor(gfx++, 0, 0, r, g, b, 255); + + SET_POLY_OPA_DISP(gfx); + CLOSE_DISP(graph); + } + + if (joint_idx == 7) { + *joint_shape = NULL; + } + + return TRUE; +} + +static int aPOFF_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) { + static Gfx* mdl[] = { obj_s_yubinkyoku_window_model, obj_w_yubinkyoku_window_model }; + + STRUCTURE_ACTOR* office; + GRAPH* graph; + Mtx* mtx; + int angle; + int winter; + int l; + int r; + int g; + int b; + Gfx* gfx; + + office = (STRUCTURE_ACTOR*)arg; + graph = game->graph; + + if (joint_idx == 7) { + mtx = _Matrix_to_Mtx_new(graph); + if (mtx != NULL) { + angle = office->action; + if (angle == DEG2SHORT_ANGLE(90.0f) - 1) { // 0x3FFF + l = 120; + r = 255; + g = 255; + b = 150; + } else if (angle == DEG2SHORT_ANGLE(0.0f)) { + l = 0; + r = 0; + g = 0; + b = 0; + } else { + r = 255; + g = 255; + b = 150; + l = (1.0f / (DEG2SHORT_ANGLE(90.0f) - 1)) * angle * 120.0f; + } + + winter = office->season == mTM_SEASON_WINTER; + + _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); + gSPDisplayList(gfx++, mdl[winter]); + + SET_SHADOW_DISP(gfx); + CLOSE_DISP(graph); + } + } + + return TRUE; +} + +static void aPOFF_actor_draw_ta_set(STRUCTURE_ACTOR* office, GAME_PLAY* play) { + GRAPH* graph = play->game.graph; + + OPEN_DISP(graph); + + gDPSetTexEdgeAlpha(NEXT_POLY_OPA_DISP, 32); + gDPSetTexEdgeAlpha(NEXT_SHADOW_DISP, 32); + + CLOSE_DISP(graph); +} + +static void aPOFF_actor_draw_ta_clr(STRUCTURE_ACTOR* office, GAME_PLAY* play) { + GRAPH* graph = play->game.graph; + + OPEN_DISP(graph); + + gDPSetTexEdgeAlpha(NEXT_POLY_OPA_DISP, 144); + gDPSetTexEdgeAlpha(NEXT_SHADOW_DISP, 144); + + CLOSE_DISP(graph); +} + +static void aPOFF_actor_draw(ACTOR* actor, GAME* game) { + GRAPH* graph; + cKF_SkeletonInfo_R_c* keyframe; + Mtx* mtx; + Gfx* gfx; + u16* pal; + GAME_PLAY* play; + STRUCTURE_ACTOR* office; + + graph = game->graph; + play = (GAME_PLAY*)game; + office = (STRUCTURE_ACTOR*)actor; + keyframe = &office->keyframe; + + mtx = GRAPH_ALLOC_TYPE(graph, Mtx, (u32)keyframe->skeleton->num_shown_joints); + if (mtx != NULL) { + pal = Common_Get(clip).structure_clip->get_pal_segment_proc(aSTR_PAL_POST_OFFICE); + + _texture_z_light_fog_prim(graph); + + aPOFF_actor_draw_ta_set(office, play); + + OPEN_DISP(graph); + gfx = NOW_POLY_OPA_DISP; + + gSPSegment(gfx++, 8, pal); + + SET_POLY_OPA_DISP(gfx); + CLOSE_DISP(graph); + + cKF_Si3_draw_R_SV(game, keyframe, mtx, &aPOFF_actor_draw_before, &aPOFF_actor_draw_after, actor); + (*Common_Get(clip).bg_item_clip->draw_shadow_proc)(game, &aPOFF_shadow_data, FALSE); + + aPOFF_actor_draw_ta_clr(office, play); + } +} diff --git a/src/ac_post_office_move.c_inc b/src/ac_post_office_move.c_inc new file mode 100644 index 00000000..b9d9ffc3 --- /dev/null +++ b/src/ac_post_office_move.c_inc @@ -0,0 +1,293 @@ +// clang-format off +static Door_data_c aPOFF_post_office_door_data = { + SCENE_POST_OFFICE, + 4, + FALSE, + 0, + {160, 0, 300}, + EMPTY_NO, + 1, + {0, 0, 0}, +}; +// clang-format on + +extern cKF_Animation_R_c cKF_ba_r_obj_s_yubinkyoku; +extern cKF_Animation_R_c cKF_ba_r_obj_s_yubinkyoku_out; +extern cKF_Animation_R_c cKF_ba_r_obj_w_yubinkyoku; +extern cKF_Animation_R_c cKF_ba_r_obj_w_yubinkyoku_out; + +static void aPOFF_set_door_SE_sub(STRUCTURE_ACTOR* office, u16 se_no) { + sAdo_OngenTrgStart(se_no, &office->actor_class.world.position); +} + +static void aPOFF_set_doorSE(STRUCTURE_ACTOR* office) { + static f32 chk_pat_in[4] = { 10.0f, 14.0f, 35.0f, 50.0f }; + static f32 chk_pat_out[4] = { 2.0f, 8.0f, 33.0f, 40.0f }; + static u16 se_no[4] = { 6, 7, 8, 9 }; + + f32* chk_pat_p; + int i; + + switch (office->request_type) { + case 1: + case 3: + 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(&office->keyframe.frame_control, *chk_pat_p) != FALSE) { + aPOFF_set_door_SE_sub(office, se_no[i]); + break; + } + } +} + +static void aPOFF_rewrite_out_data(STRUCTURE_ACTOR* office, 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) { + door_data->next_scene_id = Save_Get(scene_no); + door_data->exit_orientation = mSc_DIRECT_SOUTH_WEST; + door_data->exit_type = 0; + door_data->extra_data = 2; + + pos.x = office->actor_class.world.position.x - 64.0f; + pos.z = office->actor_class.world.position.z + 64.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 = POST_OFFICE; + + door_data->wipe_type = 1; + } +} + +static int aPOFF_check_player(ACTOR* actor, GAME_PLAY* play) { + u16 y; + f32 xOffs; + f32 zOffs; + f32 t; + int res; + PLAYER_ACTOR* player; + + player = GET_PLAYER_ACTOR(play); + res = 0; + + if (player == NULL) { + return 0; + } + + y = player->actor_class.shape_info.rotation.y; + xOffs = SQ(player->actor_class.world.position.x - (actor->world.position.x - 40.0f)); + zOffs = SQ(player->actor_class.world.position.z - (actor->world.position.z + 50.0f)); + t = (xOffs) + (zOffs); + + if ((y > 0x4000) && (y < 0x8000) && (t < 360.0f) && chkTrigger(BUTTON_A) != 0) { + res = 2; + } + + return res; +} + +static int aPOFF_check_open(STRUCTURE_ACTOR* office, GAME_PLAY* play) { + static int cond[] = { 1, 1, 2, 3 }; + + switch (office->request_type) { + case 0: + return aPOFF_check_player(&office->actor_class, play); + case 5: + return 0; + default: + return cond[office->request_type - 1]; + } +} + +static void aPOFF_set_bgOffset(STRUCTURE_ACTOR* office, int idx) { + // clang-format off + static mCoBG_OffsetTable_c height_table_ct[] = { + { mCoBG_ATTRIBUTE_NONE, 0, 0, 0, 0, 0, 0 }, + { mCoBG_ATTRIBUTE_NONE, 13, 13, 0, 13, 13, 1 }, + { mCoBG_ATTRIBUTE_NONE, 13, 13, 13, 0, 13, 1 }, + { mCoBG_ATTRIBUTE_NONE, 0, 0, 0, 0, 0, 0 }, + { mCoBG_ATTRIBUTE_NONE, 13, 13, 0, 13, 13, 1 }, + { mCoBG_ATTRIBUTE_NONE, 13, 13, 13, 13, 14, 0 }, + { mCoBG_ATTRIBUTE_NONE, 13, 14, 13, 13, 13, 0 }, + { mCoBG_ATTRIBUTE_NONE, 13, 13, 13, 0, 13, 1 }, + { mCoBG_ATTRIBUTE_NONE, 13, 0, 13, 13, 13, 1 }, + { mCoBG_ATTRIBUTE_NONE, 13, 13, 13, 14, 13, 0 }, + { mCoBG_ATTRIBUTE_NONE, 13, 13, 14, 13, 13, 0 }, + { mCoBG_ATTRIBUTE_NONE, 13, 13, 13, 13, 0, 1 }, + { mCoBG_ATTRIBUTE_NONE, 0, 0, 0, 0, 0, 0 }, + { mCoBG_ATTRIBUTE_NONE, 13, 0, 13, 13, 13, 1 }, + { mCoBG_ATTRIBUTE_NONE, 13, 13, 13, 13, 0, 1 }, + { mCoBG_ATTRIBUTE_NONE, 0, 0, 0, 0, 0, 0 } + }; + // clang-format on + + static mCoBG_OffsetTable_c* height_table[] = { height_table_ct, height_table_ct }; + + static f32 addX[] = { -80.0f, -40.0f, 0.0f, 40.0f }; + static f32 addZ[] = { 80.0f, 40.0f, 0.0f, -40.0f }; + + mCoBG_OffsetTable_c* offset; + int i; + int j; + xyz_t pos; + + offset = height_table[idx]; + for (i = 0; i < 4; i++) { + pos.z = office->actor_class.home.position.z + addZ[i]; + + for (j = 0; j < 4; j++) { + if (j + i * 4 != 0 && j + i * 4 != 3 && j + i * 4 != 12 && j + i * 4 != 15) { + pos.x = office->actor_class.home.position.x + addX[j]; + mCoBG_SetPluss5PointOffset_file(pos, *offset, __FILE__, 337); + } + + offset++; + } + } +} + +static void aPOFF_setup_animation(STRUCTURE_ACTOR* office, f32 speed) { + // clang-format off + static cKF_Animation_R_c* animation[2][2] = { + { &cKF_ba_r_obj_s_yubinkyoku, &cKF_ba_r_obj_s_yubinkyoku_out }, + { &cKF_ba_r_obj_w_yubinkyoku, &cKF_ba_r_obj_w_yubinkyoku_out } + }; + // clang-format on + + static f32 start_idx[] = { 1.0f, 25.0f, 1.0f, 1.0f }; + static f32 end_idx[] = { 51.0f, 51.0f, 51.0f, 51.0f }; + + int winter; + int idx; + + winter = office->season == mTM_SEASON_WINTER; + switch (office->request_type) { + case 2: + idx = 2; + break; + case 4: + idx = 1; + break; + default: + idx = 0; + break; + } + + cKF_SkeletonInfo_R_init(&office->keyframe, office->keyframe.skeleton, animation[winter][idx != 0], start_idx[idx], + end_idx[idx], start_idx[idx], speed, 0.0f, cKF_FRAMECONTROL_STOP, NULL); +} + +static void aPOFF_open_door_demo_ct() { + mDemo_Set_house_info(40.0f, 5); + mDemo_Set_camera(CAMERA2_PROCESS_DOOR); +} + +static int aPOFF_ctrl_light(STRUCTURE_ACTOR* office) { + int now_sec = Common_Get(time.now_sec); + return !(now_sec < (64800) && now_sec > (18000)); +} + +static void aPOFF_wait(STRUCTURE_ACTOR* office, GAME_PLAY* play) { + ACTOR* actor; + int request_type; + int check_open; + + actor = (ACTOR*)office; + request_type = office->request_type; + + if (mDemo_Check(mDemo_TYPE_DOOR, actor) != FALSE) { + if (request_type == 4) { + aPOFF_setup_animation(office, 0.5f); + } + + aPOFF_setup_action(office, aPOFF_ACTION_OPEN_DOOR_WAIT); + } else { + check_open = aPOFF_check_open(office, play); + if (check_open == 2) { + mDemo_Request(mDemo_TYPE_DOOR, actor, &aPOFF_open_door_demo_ct); + } else if (check_open == 3) { + if (request_type == 4) { + aPOFF_setup_animation(office, 0.5f); + } + + aPOFF_setup_action(office, aPOFF_ACTION_OPEN_DOOR); + } + } +} + +static void aPOFF_open_door_wait(STRUCTURE_ACTOR* office, GAME_PLAY* play) { + if (office == GET_PLAYER_ACTOR_NOW()->get_door_label_proc(gamePT)) { + office->request_type = 3; + aPOFF_setup_animation(office, 0.5f); + aPOFF_setup_action(office, aPOFF_ACTION_OPEN_DOOR); + mBGMPsComp_make_ps_wipe(0x249); // TODO: enum/define + } +} + +static void aPOFF_open_door(STRUCTURE_ACTOR* office, GAME_PLAY* play) { + if (cKF_SkeletonInfo_R_play(&office->keyframe) == TRUE) { + if (office->request_type == 3) { + aPOFF_rewrite_out_data(office, play); + goto_other_scene(play, &aPOFF_post_office_door_data, FALSE); + aPOFF_setup_action(office, aPOFF_ACTION_OPEN_UNKNOWN); + mDemo_End((ACTOR*)office); + } else { + aPOFF_setup_action(office, aPOFF_ACTION_WAIT); + } + + office->request_type = 0; + } +} + +static void aPOFF_setup_action(STRUCTURE_ACTOR* office, int action) { + // clang-format off + static aSTR_MOVE_PROC process[] = { + &aPOFF_wait, + &aPOFF_open_door_wait, + &aPOFF_open_door, + (aSTR_MOVE_PROC)&none_proc1 + }; + // clang-format on + + office->action_proc = process[action]; +} + +static void aPOFF_actor_move(ACTOR* actor, GAME* game) { + STRUCTURE_ACTOR* office; + GAME_PLAY* play; + s16 target; + + office = (STRUCTURE_ACTOR*)actor; + play = (GAME_PLAY*)game; + + aPOFF_set_doorSE(office); + + (*office->action_proc)(office, play); + + target = (s16)office->action; + if (aPOFF_ctrl_light(office)) { + chase_s(&target, DEG2SHORT_ANGLE(90.0f) - 1, 320); // 0x3FFF + } else { + chase_s(&target, DEG2SHORT_ANGLE(0.0f), 320); + } + + office->action = target; +} + +static void aPOFF_actor_init(ACTOR* actor, GAME* game) { + mFI_SetFG_common(DUMMY_POST_OFFICE, actor->home.position, FALSE); + aPOFF_actor_move(actor, game); + actor->mv_proc = aPOFF_actor_move; +}