From 9b2bb6cc9973950382a1148f0c1e0da7a14ea8c7 Mon Sep 17 00:00:00 2001 From: Hexalotl <15166449+Hexalotl@users.noreply.github.com> Date: Sun, 24 Mar 2024 10:36:55 -0700 Subject: [PATCH] Implement & link ac_buggy --- config/rel_slices.yml | 4 + include/ac_buggy.h | 2 +- include/m_name_table.h | 1 + src/ac_buggy.c | 129 ++++++++++++++++ src/ac_buggy_draw.c_inc | 124 +++++++++++++++ src/ac_buggy_move.c_inc | 331 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 590 insertions(+), 1 deletion(-) create mode 100644 src/ac_buggy.c create mode 100644 src/ac_buggy_draw.c_inc create mode 100644 src/ac_buggy_move.c_inc diff --git a/config/rel_slices.yml b/config/rel_slices.yml index dc05fc08..1f820f7e 100644 --- a/config/rel_slices.yml +++ b/config/rel_slices.yml @@ -755,6 +755,10 @@ ac_br_shop.c: .text: [0x805A856C, 0x805A9474] .rodata: [0x8064A630, 0x8064A660] .data: [0x806C4560, 0x806C4688] +ac_buggy.c: + .text: [0x805A9CA0, 0x805AAB3C] + .rodata: [0x8064A6D0, 0x8064A708] + .data: [0x806C4730, 0x806C4858] ac_douzou.c: .text: [0x805AD6D8, 0x805AE704] .rodata: [0x8064A7C0, 0x8064A7E8] diff --git a/include/ac_buggy.h b/include/ac_buggy.h index 66921c9c..8007a194 100644 --- a/include/ac_buggy.h +++ b/include/ac_buggy.h @@ -2,7 +2,7 @@ #define AC_BUGGY_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 37023042..1eeebd5c 100644 --- a/include/m_name_table.h +++ b/include/m_name_table.h @@ -2718,6 +2718,7 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define DUMMY_RESERVE 0xF102 #define DUMMY_SHRINE 0xF103 #define DUMMY_BROKER_SHOP 0xF104 +#define DUMMY_BUGGY 0xF105 #define DUMMY_CAR 0xF106 #define DUMMY_RADIO 0xF109 #define DUMMY_YATAI 0xF10A diff --git a/src/ac_buggy.c b/src/ac_buggy.c new file mode 100644 index 00000000..d2179637 --- /dev/null +++ b/src/ac_buggy.c @@ -0,0 +1,129 @@ +#include "ac_buggy.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" + +// clang-format off +enum { + aBGY_ACTION_WAIT, + aBGY_ACTION_OPEN_WAIT, + aBGY_ACTION_CLOSE_DOOR, + aBGY_ACTION_OPEN_DOOR, + + aBGY_ACTION_NUM +}; +// clang-format on + +static void aBGY_actor_ct(ACTOR* actor, GAME* game); +static void aBGY_actor_dt(ACTOR* actor, GAME* game); +static void aBGY_actor_init(ACTOR* actor, GAME* game); +static void aBGY_actor_draw(ACTOR* actor, GAME* game); + +// clang-format off +ACTOR_PROFILE Buggy_Profile = { + mAc_PROFILE_BUGGY, + ACTOR_PART_ITEM, + ACTOR_STATE_TA_SET, + FORTUNE_TENT, + ACTOR_OBJ_BANK_KEEP, + sizeof(STRUCTURE_ACTOR), + &aBGY_actor_ct, + &aBGY_actor_dt, + &aBGY_actor_init, + &aBGY_actor_draw, + NULL +}; +// clang-format on + +// clang-format off +static u8 aBGY_shadow_vtx_fix_flg_table[] = { + TRUE, TRUE, FALSE, TRUE, + FALSE, FALSE, TRUE, FALSE, + FALSE, TRUE, TRUE, FALSE, + TRUE, FALSE, FALSE, FALSE +}; +// clang-format on + +extern Vtx obj_uranai_shadow_v[]; +extern Gfx obj_uranai_shadowT_model[]; + +// clang-format off +static bIT_ShadowData_c aBGY_shadow_data = { + 14, + aBGY_shadow_vtx_fix_flg_table, + 60.0f, + obj_uranai_shadow_v, + obj_uranai_shadowT_model +}; +// clang-format on + +extern cKF_Skeleton_R_c cKF_bs_r_obj_s_uranai; +extern cKF_Skeleton_R_c cKF_bs_r_obj_w_uranai; + +static void change_FGUnit(STRUCTURE_ACTOR* buggy, int type); +static void aBGY_set_bgOffset(STRUCTURE_ACTOR* buggy, int offs); +static void aBGY_setup_action(STRUCTURE_ACTOR* buggy, int action); +static int aBGY_ctrl_light(STRUCTURE_ACTOR* buggy); + +static void aBGY_actor_ct(ACTOR* actor, GAME* game) { + static cKF_Skeleton_R_c* skl[] = { &cKF_bs_r_obj_s_uranai, &cKF_bs_r_obj_w_uranai }; + + STRUCTURE_ACTOR* buggy; + GAME_PLAY* play; + PLAYER_ACTOR* player; + int winter; + int action; + int x; + int z; + f32 speed; + + buggy = (STRUCTURE_ACTOR*)actor; + play = (GAME_PLAY*)game; + player = get_player_actor_withoutCheck(play); + + buggy->season = Common_Get(time.season); + winter = buggy->season == mTM_SEASON_WINTER; + + cKF_SkeletonInfo_R_ct(&buggy->keyframe, skl[winter], NULL, buggy->work_area, buggy->morph_area); + + aBGY_set_bgOffset(buggy, 1); + change_FGUnit(buggy, 1); + + x = (int)buggy->actor_class.world.position.x; + z = (int)(buggy->actor_class.world.position.z + 100.0f); + + action = aBGY_ACTION_WAIT; + + if ((int)player->actor_class.world.position.x == x && (int)player->actor_class.world.position.z == z) { + action = aBGY_ACTION_OPEN_WAIT; + } + + aBGY_setup_action(buggy, action); + + buggy->actor_class.talk_distance = 80.0; + + cKF_SkeletonInfo_R_play(&buggy->keyframe); + + buggy->arg0_f = aBGY_ctrl_light(buggy) ? 1.0f : 0.0f; +} + +static void aBGY_actor_dt(ACTOR* actor, GAME* game) { + STRUCTURE_ACTOR* buggy; + buggy = (STRUCTURE_ACTOR*)actor; + + change_FGUnit(buggy, 0); + cKF_SkeletonInfo_R_dt(&buggy->keyframe); +} + +#include "../src/ac_buggy_move.c_inc" + +#include "../src/ac_buggy_draw.c_inc" diff --git a/src/ac_buggy_draw.c_inc b/src/ac_buggy_draw.c_inc new file mode 100644 index 00000000..35ddf87b --- /dev/null +++ b/src/ac_buggy_draw.c_inc @@ -0,0 +1,124 @@ +extern Gfx obj_s_uranai_window_model[]; +extern Gfx obj_w_uranai_window_model[]; + +static int aBGY_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* actor = (STRUCTURE_ACTOR*)arg; + GRAPH* graph = game->graph; + f32 color; + Gfx* gfx; + + if (joint_idx == 1) { + OPEN_DISP(graph); + color = actor->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); + } else if (joint_idx == 7) { + *joint_shape = NULL; + } + + return TRUE; +} + +static int aBGY_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_uranai_window_model, + obj_w_uranai_window_model, + }; + + STRUCTURE_ACTOR* buggy; + GRAPH* graph; + Mtx* mtx; + int winter; + int l; + int r; + int g; + int b; + Gfx* gfx; + + buggy = (STRUCTURE_ACTOR*)arg; + graph = game->graph; + + if (joint_idx == 7) { + mtx = _Matrix_to_Mtx_new(graph); + + if (mtx != NULL) { + if (buggy->arg0_f > 0.0f) { + r = 255; + g = 255; + b = 150; + l = (0.5f + (120.0f * buggy->arg0_f)); + } else { + l = 0; + r = 0; + g = 0; + b = 0; + } + + winter = buggy->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 aBGY_actor_draw(ACTOR* actor, GAME* game) { + STRUCTURE_ACTOR* buggy; + GRAPH* graph; + cKF_SkeletonInfo_R_c* keyframe; + Mtx* mtx; + Gfx* poly_opa; + Gfx* poly_xlu; + + buggy = (STRUCTURE_ACTOR*)actor; + graph = game->graph; + keyframe = &buggy->keyframe; + + mtx = GRAPH_ALLOC_TYPE(graph, Mtx, (u32)keyframe->skeleton->num_shown_joints); + + if (mtx != NULL) { + u16* pal; + + pal = Common_Get(clip).structure_clip->get_pal_segment_proc(aSTR_PAL_BUGGY); + + OPEN_DISP(graph); + { + _texture_z_light_fog_prim(graph); + poly_opa = NOW_POLY_OPA_DISP; + + gSPSegment(poly_opa++, 8, pal); + + SET_POLY_OPA_DISP(poly_opa); + } + { + _texture_z_light_fog_prim_xlu(graph); + + poly_xlu = NOW_POLY_XLU_DISP; + gSPSegment(poly_xlu++, 8, pal); + + SET_POLY_XLU_DISP(poly_xlu); + } + CLOSE_DISP(graph); + + cKF_Si3_draw_R_SV(game, keyframe, mtx, &aBGY_actor_draw_before, &aBGY_actor_draw_after, actor); + (*Common_Get(clip).bg_item_clip->draw_shadow_proc)(game, &aBGY_shadow_data, FALSE); + } +} diff --git a/src/ac_buggy_move.c_inc b/src/ac_buggy_move.c_inc new file mode 100644 index 00000000..ad2a442c --- /dev/null +++ b/src/ac_buggy_move.c_inc @@ -0,0 +1,331 @@ +extern cKF_Animation_R_c cKF_ba_r_obj_s_uranai; +extern cKF_Animation_R_c cKF_ba_r_obj_w_uranai; + +// clang-format off +static Door_data_c aBGY_buggy_door_data = { + SCENE_BUGGY, + mSc_DIRECT_NORTH, + FALSE, + 0, + {160,0,300}, + EMPTY_NO, + 1, + {0,0,0}, +}; +// clang-format on + +static void change_FGUnit(STRUCTURE_ACTOR* buggy, int type) { + int dug; + xyz_t pos; + mActor_name_t* unit_fg; + + xyz_t_move(&pos, &buggy->actor_class.world.position); + pos.z += 80.0f; + + if (type == FALSE) { + mFI_SetFG_common(EMPTY_NO, pos, TRUE); + return; + } + + unit_fg = mFI_GetUnitFG(pos); + if (unit_fg == NULL) { + return; + } + + if (mSN_ClearSnowman(unit_fg) == FALSE) { + dug = FALSE; + if ((((*unit_fg >= BURIED_PITFALL_START) && (*unit_fg <= BURIED_PITFALL_END)) || (*unit_fg == SHINE_SPOT))) { + dug = TRUE; + } + + if (dug == TRUE) { + mPB_keep_item(bg_item_fg_sub_dig2take_conv(*unit_fg)); + mFI_SetFG_common(RSV_NO, pos, 1); + mFI_Wpos2DepositOFF(pos); + } else { + mFI_Wpos2DepositOFF(pos); + mPB_keep_item(*unit_fg); + mFI_SetFG_common(RSV_NO, pos, 1); + } + } else { + mFI_SetFG_common(RSV_NO, pos, 1); + } +} + +static void aBGY_set_bgOffset(STRUCTURE_ACTOR* buggy, int offs) { + // clang-format off + static mCoBG_OffsetTable_c height_table_ct[] = { + { mCoBG_ATTRIBUTE_NONE, 8, 8, 0, 8, 8, 1}, + { mCoBG_ATTRIBUTE_NONE, 8, 8, 8, 8, 8, 0}, + { mCoBG_ATTRIBUTE_NONE, 8, 8, 8, 0, 8, 1}, + { mCoBG_ATTRIBUTE_NONE, 8, 8, 8, 8, 8, 0}, + { mCoBG_ATTRIBUTE_NONE, 8, 8, 8, 8, 8, 0}, + { mCoBG_ATTRIBUTE_NONE, 8, 8, 8, 8, 8, 0}, + { mCoBG_ATTRIBUTE_NONE, 8, 0, 8, 8, 8, 1}, + { mCoBG_ATTRIBUTE_NONE, 8, 8, 8, 8, 8, 0}, + { mCoBG_ATTRIBUTE_NONE, 8, 8, 8, 8, 0, 1} + }; + // 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 = buggy->actor_class.home.position.z + addZ[i]; + + pos.x = buggy->actor_class.home.position.x + addX[0]; + mCoBG_SetPluss5PointOffset_file(pos, offset[0], __FILE__, 225); + + pos.x = buggy->actor_class.home.position.x + addX[1]; + mCoBG_SetPluss5PointOffset_file(pos, offset[1], __FILE__, 229); + + pos.x = buggy->actor_class.home.position.x + addX[2]; + mCoBG_SetPluss5PointOffset_file(pos, offset[2], __FILE__, 233); + + offset += 3; + } +} + +static void aBGY_rewrite_out_data(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 = 3; + + pos.x = actor->world.position.x; + pos.y = actor->world.position.y; + pos.z = actor->world.position.z + 100.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 = FORTUNE_TENT; + + door_data->wipe_type = 1; + + mBGMPsComp_make_ps_wipe(0x2168); +} + +static int aBGY_check_player2(GAME_PLAY* play) { + PLAYER_ACTOR* player; + u16 y; + int res; + + player = GET_PLAYER_ACTOR(play); + y = player->actor_class.world.angle.y; + + res = 0; + if ((y > DEG2SHORT_ANGLE2(135.0f)) && (y < DEG2SHORT_ANGLE2(225.0f)) && (player->actor_class.speed > 0.0f)) { // 0x6000 && 0xA000 + res = 1; + } + + return res; +} + +static int aBGY_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); + zOffs = SQ(player->actor_class.world.position.z - (actor->world.position.z + 60.0f)); + + t = (xOffs) + (zOffs); + + if ((y > DEG2SHORT_ANGLE2(135.0f)) && (y < DEG2SHORT_ANGLE2(225.0f)) && (t < 480.0f)) { // 0x6000 && 0xA000 + res = 2; + } else if (t < 1200.0f) { + res = 1; + } + + return res; +} + +static int aBGY_open_check() { + int res; + + res = mEv_CheckEvent(mEv_SPNPC_GYPSY); + res = (res != FALSE) + 1; + + return res; +} + +static void aBGY_set_talk_info_close_wait(ACTOR* actor) { + rgba_t window_color; + + mDemo_Set_msg_num(0x7D5); + mDemo_Set_talk_display_name(FALSE); + mDemo_Set_ListenAble(); + + window_color.r = 145; + window_color.g = 60; + window_color.b = 40; + window_color.a = 255; + mDemo_Set_talk_window_color(&window_color); +} + +static void aBGY_close_wait(STRUCTURE_ACTOR* buggy, GAME_PLAY* play) { + ACTOR* actor; + + actor = (ACTOR*)buggy; + if (mDemo_Check(mDemo_TYPE_TALK, actor) == TRUE) { + return; + } + + if (aBGY_open_check() == 2) { + if (aBGY_check_player(actor, play) == FALSE) { + return; + } + + aBGY_setup_action(buggy, aBGY_ACTION_OPEN_DOOR); + return; + } + + if (ABS(actor->player_angle_y) >= DEG2SHORT_ANGLE(45.0f)) { // 0x2000 + return; + } + + mDemo_Request(mDemo_TYPE_TALK, actor, &aBGY_set_talk_info_close_wait); +} + +static void aBGY_open_wait(STRUCTURE_ACTOR* buggy, GAME_PLAY* play) { + ACTOR* actor; + GAME* game; + xyz_t pos; + + actor = (ACTOR*)buggy; + game = &play->game; + + if (buggy == GET_PLAYER_ACTOR_NOW()->get_door_label_proc(gamePT)) { + aBGY_rewrite_out_data(actor, play); + goto_other_scene(play, &aBGY_buggy_door_data, TRUE); + return; + } + + if (mPlib_check_player_actor_main_index_OutDoorMove(play) != FALSE) { + return; + } + + if ((aBGY_check_player(actor, play) == 0) || (aBGY_open_check() != 2)) { + aBGY_setup_action(buggy, aBGY_ACTION_CLOSE_DOOR); + return; + } + + if ((aBGY_check_player(actor, play) == 2) && (aBGY_check_player2(play) != 0)) { + pos.x = actor->world.position.x; + pos.y = GET_PLAYER_ACTOR(play)->actor_class.world.position.y; + pos.z = actor->world.position.z + 64.0f; + mPlib_request_main_door_type1(game, &pos, -DEG2SHORT_ANGLE(180.0f), TRUE, actor); // 0x8000 + } +} + +static void aBGY_close_door(STRUCTURE_ACTOR* buggy, GAME_PLAY* play) { + if (buggy->keyframe_state != 1) { + return; + } + + aBGY_setup_action(buggy, aBGY_ACTION_WAIT); +} + +static void aBGY_open_door(STRUCTURE_ACTOR* buggy, GAME_PLAY* play) { + if (buggy->keyframe_state != 1) { + return; + } + + aBGY_setup_action(buggy, aBGY_ACTION_OPEN_WAIT); +} + +static void aBGY_setup_action(STRUCTURE_ACTOR* buggy, int action) { + static aSTR_MOVE_PROC process[] = { + &aBGY_close_wait, + &aBGY_open_wait, + &aBGY_close_door, + &aBGY_open_door + }; + + static cKF_Animation_R_c* animation[] = { &cKF_ba_r_obj_s_uranai, &cKF_ba_r_obj_w_uranai }; + static f32 start_idx[] = { 1.0f, 17.0f, 17.0f, 1.0f }; + static f32 end_idx[] = { 1.0f, 17.0f, 1.0f, 17.0f }; + static f32 framespeed[] = { 0.0f, 0.0f, 0.5f, 0.5f }; + + int winter; + + winter = buggy->season == mTM_SEASON_WINTER; + + cKF_SkeletonInfo_R_init(&buggy->keyframe, buggy->keyframe.skeleton, animation[winter], start_idx[action], + end_idx[action], start_idx[action], framespeed[action], 0.0f, cKF_FRAMECONTROL_STOP, NULL); + + buggy->action_proc = process[action]; + buggy->action = action; +} + +static int aBGY_ctrl_light(STRUCTURE_ACTOR* buggy) { + int now_sec = Common_Get(time.now_sec); + return !(now_sec < (64800) && now_sec >= (18000)); +} + +static void aBGY_actor_move(ACTOR* actor, GAME* game) { + GAME_PLAY* play; + STRUCTURE_ACTOR* buggy; + PLAYER_ACTOR* player; + int bx1; + int bz1; + int bx2; + int bz2; + f32 window; + + play = (GAME_PLAY*)game; + buggy = (STRUCTURE_ACTOR*)actor; + player = GET_PLAYER_ACTOR(play); + + mFI_Wpos2BlockNum(&bx1, &bz1, actor->world.position); + mFI_Wpos2BlockNum(&bx2, &bz2, player->actor_class.world.position); + + if ((mDemo_Check(mDemo_TYPE_SCROLL, &player->actor_class) == FALSE) && + (mDemo_Check(mDemo_TYPE_SCROLL2, &player->actor_class) == FALSE) && + (mDemo_Check(mDemo_TYPE_SCROLL3, &player->actor_class) == FALSE) && ((bx1 != bx2) || (bz1 != bz2))) { + Actor_delete(actor); + } else { + + buggy->keyframe_state = cKF_SkeletonInfo_R_play(&buggy->keyframe); + + buggy->action_proc(buggy, play); + + window = (aBGY_ctrl_light(buggy) != 0) ? 1.0f : 0.0f; + chase_f(&buggy->arg0_f, window, 0.019532442f); + } +} + +static void aBGY_actor_init(ACTOR* actor, GAME* game) { + mFI_SetFG_common(DUMMY_BUGGY, actor->home.position, FALSE); + aBGY_actor_move(actor, game); + actor->mv_proc = &aBGY_actor_move; +}