From 1e380d8442493dbf8fe7ce4e6e237f1457b10075 Mon Sep 17 00:00:00 2001 From: Cuyler36 Date: Sun, 11 May 2025 02:31:12 -0400 Subject: [PATCH] Implement & link ac_countdown --- configure.py | 2 +- include/ac_countdown.h | 10 ++- include/ac_countdown_clip.h | 21 ++++++ include/m_clip.h | 3 +- include/m_name_table.h | 1 + src/actor/ac_countdown.c | 79 ++++++++++++++++++++ src/actor/ac_countdown_clip.c_inc | 17 +++++ src/actor/ac_countdown_draw.c_inc | 106 ++++++++++++++++++++++++++ src/actor/ac_countdown_move.c_inc | 119 ++++++++++++++++++++++++++++++ 9 files changed, 354 insertions(+), 4 deletions(-) create mode 100644 include/ac_countdown_clip.h create mode 100644 src/actor/ac_countdown.c create mode 100644 src/actor/ac_countdown_clip.c_inc create mode 100644 src/actor/ac_countdown_draw.c_inc create mode 100644 src/actor/ac_countdown_move.c_inc diff --git a/configure.py b/configure.py index 351e9e8b..195d1fa9 100644 --- a/configure.py +++ b/configure.py @@ -963,7 +963,7 @@ config.libs = [ Object(Matching, "actor/ac_conveni.c"), Object(Matching, "actor/ac_cottage.c"), Object(NonMatching, "actor/ac_count02.c"), - Object(NonMatching, "actor/ac_countdown.c"), + Object(Matching, "actor/ac_countdown.c"), Object(Matching, "actor/ac_depart.c"), Object(Matching, "actor/ac_douzou.c"), Object(Matching, "actor/ac_dummy.c"), diff --git a/include/ac_countdown.h b/include/ac_countdown.h index bf80b077..5c503ab5 100644 --- a/include/ac_countdown.h +++ b/include/ac_countdown.h @@ -2,12 +2,19 @@ #define AC_COUNTDOWN_H #include "types.h" -#include "m_actor.h" +#include "ac_structure.h" +#include "ac_countdown_clip.h" #ifdef __cplusplus extern "C" { #endif +typedef struct countdown_actor_s COUNT_ACTOR; + +struct countdown_actor_s { + /* 0x000 */ STRUCTURE_ACTOR structure_class; +}; + extern ACTOR_PROFILE Count_Profile; #ifdef __cplusplus @@ -15,4 +22,3 @@ extern ACTOR_PROFILE Count_Profile; #endif #endif - diff --git a/include/ac_countdown_clip.h b/include/ac_countdown_clip.h new file mode 100644 index 00000000..c30243cb --- /dev/null +++ b/include/ac_countdown_clip.h @@ -0,0 +1,21 @@ +#ifndef AC_COUNTDOWN_CLIP_H +#define AC_COUNTDOWN_CLIP_H + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*aCOU_ANIME_PLAY_PROC)(void); + +typedef struct countdown_clip_s { + aCOU_ANIME_PLAY_PROC anime_play_proc; + int anime_play_flag; +} aCOU_Clip_c; + +#ifdef __cplusplus +} +#endif + +#endif /* AC_COUNTDOWN_CLIP_H */ diff --git a/include/m_clip.h b/include/m_clip.h index 56c3668d..d7c6bf1a 100644 --- a/include/m_clip.h +++ b/include/m_clip.h @@ -36,6 +36,7 @@ #include "ac_station_clip.h" #include "ac_mikanbox_clip.h" #include "ac_needlework_indoor_clip.h" +#include "ac_countdown_clip.h" #ifdef __cplusplus extern "C" { @@ -90,7 +91,7 @@ typedef struct clip_s { /* 0x0C4 */ aHTMD_clip_c* hatumode_clip; /* 0x0C8 */ void* shrine_clip; /* 0x0CC */ void* _0CC; - /* 0x0D0 */ void* _0D0; + /* 0x0D0 */ aCOU_Clip_c* countdown_clip; /* 0x0D4 */ CLIP_NONE_PROC ball_redma_proc; /* removed in DnM+ */ /* 0x0D8 */ aMKBC_Clip_c* mikanbox_clip; /* 0x0DC */ aAL_Clip_c* animal_logo_clip; diff --git a/include/m_name_table.h b/include/m_name_table.h index b3721393..c552a3f0 100644 --- a/include/m_name_table.h +++ b/include/m_name_table.h @@ -3388,6 +3388,7 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define DUMMY_YATAI 0xF10A #define DUMMY_TUKIMI 0xF10A #define DUMMY_MIKUJI 0xF10D +#define DUMMY_COUNT 0xF10E #define DUMMY_TAMA 0xF110 #define DUMMY_TURI 0xF111 #define DUMMY_KOINOBORI 0xF114 diff --git a/src/actor/ac_countdown.c b/src/actor/ac_countdown.c new file mode 100644 index 00000000..070428ef --- /dev/null +++ b/src/actor/ac_countdown.c @@ -0,0 +1,79 @@ +#include "ac_countdown.h" + +#include "m_common_data.h" +#include "m_name_table.h" +#include "m_player_lib.h" +#include "m_rcp.h" +#include "sys_matrix.h" + +enum { + aCOU_ACT_WAIT, + aCOU_ACT_MOVE, + aCOU_ACT_HAPPY_NEW_YEAR, + + aCOU_ACT_NUM +}; + +static void aCOU_actor_ct(ACTOR* actorx, GAME* game); +static void aCOU_actor_dt(ACTOR* actorx, GAME* game); +static void aCOU_actor_draw(ACTOR* actorx, GAME* game); +static void aCOU_actor_init(ACTOR* actorx, GAME* game); + +ACTOR_PROFILE Count_Profile = { + // clang-format off + mAc_PROFILE_COUNT, + ACTOR_PART_ITEM, + ACTOR_STATE_TA_SET, + NEWYEAR_COUNTDOWN0, + ACTOR_OBJ_BANK_KEEP, + sizeof(COUNT_ACTOR), + aCOU_actor_ct, + aCOU_actor_dt, + aCOU_actor_init, + aCOU_actor_draw, + NULL, + // clang-format on +}; + +// @ 8056df2c +static u8 aCOU_shadow_vtx_fix_flg_table[4] = { 0x00, 0x01, 0x01, 0x00 }; + +extern Vtx obj_e_count_shadow_v[]; +extern Gfx obj_e_count_shadow_model[]; + +static bIT_ShadowData_c aCOU_shadow_data = { ARRAY_COUNT(aCOU_shadow_vtx_fix_flg_table), aCOU_shadow_vtx_fix_flg_table, + 60.0f, obj_e_count_shadow_v, obj_e_count_shadow_model }; + +static aCOU_Clip_c aCOU_clip; + +extern cKF_Skeleton_R_c cKF_bs_r_obj_e_count01; +extern cKF_Animation_R_c cKF_ba_r_obj_e_count01; + +static void aCOU_set_bgOffset(ACTOR* actorx, int idx); +static void aCOU_init_clip_area(void); +static void aCOU_free_clip_area(void); +static void aCOU_setup_action(COUNT_ACTOR* actor, int action); + +static void aCOU_actor_ct(ACTOR* actorx, GAME* game) { + COUNT_ACTOR* actor = (COUNT_ACTOR*)actorx; + + cKF_SkeletonInfo_R_ct(&actor->structure_class.keyframe, &cKF_bs_r_obj_e_count01, NULL, + actor->structure_class.work_area, actor->structure_class.morph_area); + aCOU_set_bgOffset(actorx, 1); + aCOU_setup_action(actor, aCOU_ACT_WAIT); + cKF_SkeletonInfo_R_play(&actor->structure_class.keyframe); + actor->structure_class.arg1 = 0; + actor->structure_class.arg2 = 0; + aCOU_init_clip_area(); +} + +static void aCOU_actor_dt(ACTOR* actorx, GAME* game) { + COUNT_ACTOR* actor = (COUNT_ACTOR*)actorx; + + cKF_SkeletonInfo_R_dt(&actor->structure_class.keyframe); + aCOU_free_clip_area(); +} + +#include "../src/actor/ac_countdown_clip.c_inc" +#include "../src/actor/ac_countdown_move.c_inc" +#include "../src/actor/ac_countdown_draw.c_inc" diff --git a/src/actor/ac_countdown_clip.c_inc b/src/actor/ac_countdown_clip.c_inc new file mode 100644 index 00000000..e8e3cedb --- /dev/null +++ b/src/actor/ac_countdown_clip.c_inc @@ -0,0 +1,17 @@ +static void aCOU_anime_play(void) { + CLIP(countdown_clip)->anime_play_flag = TRUE; +} + +static void aCOU_init_clip_area(void) { + if (CLIP(countdown_clip) == NULL) { + CLIP(countdown_clip) = &aCOU_clip; + CLIP(countdown_clip)->anime_play_proc = aCOU_anime_play; + CLIP(countdown_clip)->anime_play_flag = FALSE; + } +} + +static void aCOU_free_clip_area(void) { + if (CLIP(countdown_clip) != NULL) { + CLIP(countdown_clip) = NULL; + } +} diff --git a/src/actor/ac_countdown_draw.c_inc b/src/actor/ac_countdown_draw.c_inc new file mode 100644 index 00000000..e14788ae --- /dev/null +++ b/src/actor/ac_countdown_draw.c_inc @@ -0,0 +1,106 @@ +static int aCOU_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) { + static rgba_t prmcolor[10] = { + // clang-format off + {0xFF, 0xFF, 0xFF, 0xFF}, + {0x64, 0x46, 0xC8, 0xFF}, + {0x50, 0xC8, 0x00, 0xFF}, + {0xFF, 0xFF, 0x00, 0xFF}, + {0x00, 0x00, 0x00, 0xFF}, + {0xFF, 0xFF, 0xFF, 0xFF}, + {0x00, 0x00, 0x46, 0xFF}, + {0x00, 0x28, 0x00, 0xFF}, + {0x32, 0x0A, 0x00, 0xFF}, + {0x00, 0x00, 0x00, 0xFF}, + // clang-format on + }; + + static rgba_t envcolor[5] = { + // clang-format off + {0x00, 0x00, 0x00, 0x00}, + {0x0A, 0x0A, 0x50, 0xFF}, + {0x00, 0x50, 0x00, 0xFF}, + {0xB4, 0x00, 0x00, 0xFF}, + {0x00, 0x00, 0x00, 0x00}, + // clang-format on + }; + COUNT_ACTOR* actor = (COUNT_ACTOR*)arg; + int prim_l = 0; + int col_idx; + rgba_t* color; + + OPEN_POLY_OPA_DISP(game->graph); + + if (actor->structure_class.arg0 == aCOU_ACT_HAPPY_NEW_YEAR) { + col_idx = actor->structure_class.action / 20; + col_idx += 1; + + if (joint_idx != 4) { + col_idx += 5; + } + } else { + col_idx = joint_idx == 4 ? 1 : 4; + } + + switch (joint_idx) { + case 4: + prim_l = 128; + break; + case 5: + prim_l = 40; + break; + case 6: + prim_l = 20; + break; + } + + if (prim_l != 0) { + gDPPipeSync(POLY_OPA_DISP++); + + if (joint_idx == 4) { + gDPSetEnvColor(POLY_OPA_DISP++, envcolor[col_idx].r, envcolor[col_idx].g, envcolor[col_idx].b, envcolor[col_idx].a); + } else { + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 60, 255); + } + + gDPSetPrimColor(POLY_OPA_DISP++, 0, prim_l, prmcolor[col_idx].r, prmcolor[col_idx].g, prmcolor[col_idx].b, prmcolor[col_idx].a); + } + + CLOSE_POLY_OPA_DISP(game->graph); + + return TRUE; +} + +static void aCOU_actor_draw(ACTOR* actorx, GAME* game) { + GRAPH* graph = game->graph; + cKF_SkeletonInfo_R_c* keyframe; + Mtx* mtx; + COUNT_ACTOR* actor = (COUNT_ACTOR*)actorx; + + keyframe = &actor->structure_class.keyframe; + mtx = GRAPH_ALLOC_TYPE(graph, Mtx, keyframe->skeleton->num_shown_joints); + if (mtx != NULL) { + Gfx* scroll = two_tex_scroll(graph, 0, 16, 0, 16, 16, 1, 72, actor->structure_class.arg1, 16, 16); + + if (scroll != NULL) { + u16* palette = CLIP(structure_clip)->get_pal_segment_proc(aSTR_PAL_COUNT); + + + _texture_z_light_fog_prim(graph); + + OPEN_POLY_OPA_DISP(graph); + gSPSegment(POLY_OPA_DISP++, ANIME_2_TXT_SEG, palette); + CLOSE_POLY_OPA_DISP(graph); + + + _texture_z_light_fog_prim_xlu(graph); + + OPEN_POLY_XLU_DISP(graph); + gSPSegment(POLY_XLU_DISP++, ANIME_1_TXT_SEG, scroll); + CLOSE_POLY_XLU_DISP(graph); + + cKF_Si3_draw_R_SV(game, keyframe, mtx, aCOU_actor_draw_before, NULL, actorx); + CLIP(bg_item_clip)->draw_shadow_proc(game, &aCOU_shadow_data, FALSE); + } + } +} diff --git a/src/actor/ac_countdown_move.c_inc b/src/actor/ac_countdown_move.c_inc new file mode 100644 index 00000000..b854066b --- /dev/null +++ b/src/actor/ac_countdown_move.c_inc @@ -0,0 +1,119 @@ +static void aCOU_set_bgOffset(ACTOR* actorx, int idx) { + // @ 8056df44 + static mCoBG_OffsetTable_c height_table_ct[6] = { + // clang-format off + {mCoBG_ATTRIBUTE_NONE, 9, 0, 9, 9, 9, TRUE}, + {mCoBG_ATTRIBUTE_NONE, 9, 9, 9, 9, 9, FALSE}, + {mCoBG_ATTRIBUTE_NONE, 9, 9, 9, 9, 0, TRUE}, + {mCoBG_ATTRIBUTE_NONE, 9, 9, 9, 9, 9, FALSE}, + {mCoBG_ATTRIBUTE_NONE, 9, 9, 9, 9, 9, FALSE}, + {mCoBG_ATTRIBUTE_NONE, 9, 9, 9, 9, 9, FALSE}, + // clang-format on + }; + + static mCoBG_OffsetTable_c* height_table[2] = { height_table_ct, height_table_ct }; + + static float addX[3] = { -40.0f, 0.0f, 40.0f }; + static float addZ[2] = { -40.0f, 0.0f }; + + mCoBG_OffsetTable_c* table_p = height_table[idx]; + xyz_t pos; + int i; + + for (i = 0; i < 2; i++) { + pos.z = actorx->home.position.z + addZ[i]; + + pos.x = actorx->home.position.x + addX[0]; + mCoBG_SetPluss5PointOffset_file(pos, *table_p, __FILE__, 113); + table_p++; + + pos.x = actorx->home.position.x + addX[1]; + mCoBG_SetPluss5PointOffset_file(pos, *table_p, __FILE__, 117); + table_p++; + + pos.x = actorx->home.position.x + addX[2]; + mCoBG_SetPluss5PointOffset_file(pos, *table_p, __FILE__, 121); + table_p++; + } +} + +static void aCOU_wait(COUNT_ACTOR* actor) { + int action = aCOU_ACT_HAPPY_NEW_YEAR; + + if (CLIP(countdown_clip)->anime_play_flag) { + lbRTC_time_c* time = Common_GetPointer(time.rtc_time); + + if (time->month == lbRTC_DECEMBER && time->day == 31 && time->hour == 23 && time->min == 59) { + action = aCOU_ACT_MOVE; + } + + aCOU_setup_action(actor, action); + } +} + +static void aCOU_move(COUNT_ACTOR* actor) { + if (actor->structure_class.keyframe_saved_keyframe == 61) { + aCOU_setup_action(actor, aCOU_ACT_HAPPY_NEW_YEAR); + } +} + +static void aCOU_happy_new_year(COUNT_ACTOR* actor) { + int action = actor->structure_class.action; + + actor->structure_class.action = action >= 59 ? 0 : action + 1; +} + +static void aCOU_setup_action(COUNT_ACTOR* actor, int action) { + static aSTR_MOVE_PROC process[] = { + // clang-format off + (aSTR_MOVE_PROC)aCOU_wait, + (aSTR_MOVE_PROC)aCOU_move, + (aSTR_MOVE_PROC)aCOU_happy_new_year, + // clang-format on + }; + + static float anime_start[] = { 1.0f, 1.0f, 61.0f }; + static float anime_spd[] = { 0.0f, 0.5f, 0.0f }; + + cKF_SkeletonInfo_R_init(&actor->structure_class.keyframe, actor->structure_class.keyframe.skeleton, + &cKF_ba_r_obj_e_count01, anime_start[action], 61.0f, anime_start[action], anime_spd[action], + 0.0f, cKF_FRAMECONTROL_STOP, NULL); + actor->structure_class.action_proc = process[action]; + actor->structure_class.arg0 = action; + actor->structure_class.action = 0; +} + +static void aCOU_actor_move(ACTOR* actorx, GAME* game) { + COUNT_ACTOR* actor = (COUNT_ACTOR*)actorx; + GAME_PLAY* play = (GAME_PLAY*)game; + ACTOR* playerx = GET_PLAYER_ACTOR_ACTOR(play); + int count_bx; + int count_bz; + int player_bx; + int player_bz; + + mFI_Wpos2BlockNum(&count_bx, &count_bz, actorx->world.position); + mFI_Wpos2BlockNum(&player_bx, &player_bz, playerx->world.position); + + if (!mDemo_Check(mDemo_TYPE_SCROLL, playerx) && !mDemo_Check(mDemo_TYPE_SCROLL2, playerx) && + !mDemo_Check(mDemo_TYPE_SCROLL3, playerx) && (count_bx != player_bx || count_bz != player_bz)) { + Actor_delete(actorx); + return; + } + + actor->structure_class.keyframe_state = cKF_SkeletonInfo_R_play(&actor->structure_class.keyframe); + actor->structure_class.keyframe_saved_keyframe = actor->structure_class.keyframe.frame_control.current_frame; + actor->structure_class.action_proc((STRUCTURE_ACTOR*)actor, play); + + if ((++actor->structure_class.arg2) & 1) { + actor->structure_class.arg1--; + } +} + +static void aCOU_actor_init(ACTOR* actorx, GAME* game) { + COUNT_ACTOR* actor = (COUNT_ACTOR*)actorx; + + mFI_SetFG_common(DUMMY_COUNT, actorx->home.position, FALSE); + aCOU_actor_move(actorx, game); + actorx->mv_proc = aCOU_actor_move; +}