diff --git a/configure.py b/configure.py index 195d1fa9..6fbbd9b6 100644 --- a/configure.py +++ b/configure.py @@ -962,7 +962,7 @@ config.libs = [ Object(Matching, "actor/ac_buggy.c"), Object(Matching, "actor/ac_conveni.c"), Object(Matching, "actor/ac_cottage.c"), - Object(NonMatching, "actor/ac_count02.c"), + Object(Matching, "actor/ac_count02.c"), Object(Matching, "actor/ac_countdown.c"), Object(Matching, "actor/ac_depart.c"), Object(Matching, "actor/ac_douzou.c"), diff --git a/include/ac_count02.h b/include/ac_count02.h index 624a7466..8c220607 100644 --- a/include/ac_count02.h +++ b/include/ac_count02.h @@ -2,7 +2,7 @@ #define AC_COUNT02_H #include "types.h" -#include "m_actor.h" +#include "ac_structure.h" #ifdef __cplusplus extern "C" { @@ -15,4 +15,3 @@ extern ACTOR_PROFILE Count02_Profile; #endif #endif - diff --git a/include/m_name_table.h b/include/m_name_table.h index c552a3f0..4a98fb63 100644 --- a/include/m_name_table.h +++ b/include/m_name_table.h @@ -3389,6 +3389,7 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define DUMMY_TUKIMI 0xF10A #define DUMMY_MIKUJI 0xF10D #define DUMMY_COUNT 0xF10E +#define DUMMY_COUNT02 0xF10F #define DUMMY_TAMA 0xF110 #define DUMMY_TURI 0xF111 #define DUMMY_KOINOBORI 0xF114 diff --git a/src/actor/ac_count02.c b/src/actor/ac_count02.c new file mode 100644 index 00000000..15b6eb1c --- /dev/null +++ b/src/actor/ac_count02.c @@ -0,0 +1,67 @@ +#include "ac_count02.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_INIT, + aCOU_ACT_WAIT, + + aCOU_ACT_NUM +}; + +static void aCOU_actor_ct(ACTOR* actorx, GAME* game); +static void aCOU_actor_draw(ACTOR* actorx, GAME* game); +static void aCOU_actor_dt(ACTOR* actorx, GAME* game); +static void aCOU_actor_init(ACTOR* actorx, GAME* game); + +ACTOR_PROFILE Count02_Profile = { + // clang-format off + mAc_PROFILE_COUNT02, + ACTOR_PART_ITEM, + ACTOR_STATE_TA_SET | ACTOR_STATE_NO_DRAW_WHILE_CULLED | ACTOR_STATE_NO_MOVE_WHILE_CULLED, + NEWYEAR_COUNTDOWN1, + ACTOR_OBJ_BANK_KEEP, + sizeof(STRUCTURE_ACTOR), + aCOU_actor_ct, + aCOU_actor_dt, + aCOU_actor_init, + aCOU_actor_draw, + NULL, + // clang-format on +}; + +extern cKF_Skeleton_R_c cKF_bs_r_obj_e_count02_cl; +extern cKF_Animation_R_c cKF_ba_r_obj_e_count02_cl; + +static void aCOU_setup_action(STRUCTURE_ACTOR* actor, int action); + +static void aCOU_actor_ct(ACTOR* actorx, GAME* game) { + lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); + STRUCTURE_ACTOR* actor = (STRUCTURE_ACTOR*)actorx; + + cKF_SkeletonInfo_R_ct(&actor->keyframe, &cKF_bs_r_obj_e_count02_cl, NULL, + actor->work_area, actor->morph_area); + + if (rtc_time->month == lbRTC_DECEMBER && rtc_time->day == 31 && rtc_time->hour == 23 && rtc_time->min == 59) { + actor->arg2_f = 1.0f; + } else { + actor->arg2_f = 0.0f; + } + + aCOU_setup_action(actor, aCOU_ACT_INIT); + actorx->world.position.z += mFI_UT_WORLDSIZE_Z_F; + cKF_SkeletonInfo_R_play(&actor->keyframe); +} + +static void aCOU_actor_dt(ACTOR* actorx, GAME* game) { + STRUCTURE_ACTOR* actor = (STRUCTURE_ACTOR*)actorx; + + cKF_SkeletonInfo_R_dt(&actor->keyframe); +} + +#include "../src/actor/ac_count02_move.c_inc" +#include "../src/actor/ac_count02_draw.c_inc" diff --git a/src/actor/ac_count02_draw.c_inc b/src/actor/ac_count02_draw.c_inc new file mode 100644 index 00000000..e8d41021 --- /dev/null +++ b/src/actor/ac_count02_draw.c_inc @@ -0,0 +1,89 @@ +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) { + STRUCTURE_ACTOR* actor = (STRUCTURE_ACTOR*)arg; + + if (joint_idx == 2 && (int)actor->arg0_f != 0) { + Matrix_RotateZ((s16)actor->arg1_f << 12, TRUE); + } + + return TRUE; +} + +extern u8 obj_e_count02_0_tex[]; +extern u8 obj_e_count02_1_tex[]; +extern u8 obj_e_count02_2_tex[]; +extern u8 obj_e_count02_3_tex[]; +extern u8 obj_e_count02_4_tex[]; +extern u8 obj_e_count02_5_tex[]; +extern u8 obj_e_count02_6_tex[]; +extern u8 obj_e_count02_7_tex[]; +extern u8 obj_e_count02_8_tex[]; +extern u8 obj_e_count02_9_tex[]; + +static void aCOU_actor_draw(ACTOR* actorx, GAME* game) { + static u8* textbl[10] = { + // clang-format off + obj_e_count02_0_tex, + obj_e_count02_1_tex, + obj_e_count02_2_tex, + obj_e_count02_3_tex, + obj_e_count02_4_tex, + obj_e_count02_5_tex, + obj_e_count02_6_tex, + obj_e_count02_7_tex, + obj_e_count02_8_tex, + obj_e_count02_9_tex, + // clang-format on + }; + + static float xpos_tbl[4] = { -33.0f, -13.0f, 10.0f, 30.0f }; + + GRAPH* graph = game->graph; + STRUCTURE_ACTOR* actor = (STRUCTURE_ACTOR*)actorx; + cKF_SkeletonInfo_R_c* keyframe = &actor->keyframe; + int disp_joint_num = keyframe->skeleton->num_shown_joints; + u16* palette = CLIP(structure_clip)->get_pal_segment_proc(aSTR_PAL_COUNT02); + Mtx* mtx; + int digit0; + int digit1; + int i; + int draw_display_bitfield = 0b1000; // currently drawn digit display + + _texture_z_light_fog_prim_npc(graph); + for (i = 0; i < 4; i++) { + mtx = GRAPH_ALLOC_TYPE(graph, Mtx, disp_joint_num); + if (mtx == NULL) { + break; + } + + digit0 = aCOU_getTime(actor->arg1, 3 - i); + digit1 = aCOU_getTime(actor->arg0, 3 - i); + + Matrix_push(); + + OPEN_POLY_OPA_DISP(graph); + + gSPSegment(POLY_OPA_DISP++, ANIME_3_TXT_SEG, palette); + gSPSegment(POLY_OPA_DISP++, ANIME_1_TXT_SEG, textbl[digit0]); + gSPSegment(POLY_OPA_DISP++, ANIME_2_TXT_SEG, textbl[digit1]); + + Matrix_translate(100.0f * xpos_tbl[i], 0.0f, 0.0f, 1); + + CLOSE_POLY_OPA_DISP(graph); + + actor->arg0_f = (int)(actor->arg2 & draw_display_bitfield); + cKF_Si3_draw_R_SV(game, keyframe, mtx, aCOU_actor_draw_before, NULL, actorx); + Matrix_pull(); + draw_display_bitfield >>= 1; + } + + if (actor->arg0 != actor->arg1) { + if (actor->arg1_f < 8.0f) { + actor->arg1_f = actor->arg1_f + 1.0f; + } else { + actor->arg1 = actor->arg0; + actor->arg2 = 0; + actor->arg1_f = 0.0f; + } + } +} diff --git a/src/actor/ac_count02_move.c_inc b/src/actor/ac_count02_move.c_inc new file mode 100644 index 00000000..0a1c1667 --- /dev/null +++ b/src/actor/ac_count02_move.c_inc @@ -0,0 +1,122 @@ +static int aCOU_setNowTime(STRUCTURE_ACTOR* actor) { + lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); + int now_sec = Common_Get(time.now_sec); + + if (rtc_time->month == lbRTC_DECEMBER && now_sec >= mTM_TIME2SEC(23, 0, 0)) { + actor->arg0 = mTM_TIME2SEC(24, 0, 0) - now_sec; + } else if (rtc_time->month != lbRTC_DECEMBER) { + actor->arg0 = 0; + } else { + actor->arg0 = mTM_TIME2SEC(1, 0, 0) - 1; + } + + return actor->arg0; +} + +static int aCOU_getTime(int nowsec, int digit) { + int ret = 0; + int min = (nowsec / mTM_SECONDS_IN_MINUTE) % mTM_MINUTES_IN_HOUR; + int sec = nowsec % mTM_SECONDS_IN_MINUTE; + + switch (digit) { + case 0: + ret = sec % 10; + break; + case 1: + ret = sec / 10; + break; + case 2: + ret = min % 10; + break; + case 3: + ret = min / 10; + break; + } + + return ret; +} + +static void aCOU_init(STRUCTURE_ACTOR* actor, GAME_PLAY* play) { + actor->arg1 = aCOU_setNowTime(actor); + actor->arg1_f = 0.0f; + actor->arg2 = 0; + aCOU_setup_action(actor, aCOU_ACT_WAIT); +} + +static void aCOU_wait(STRUCTURE_ACTOR* actor, GAME_PLAY* play) { + int digit_bits = 0b1111; // bitfield for each digit in the display + int i; + + if ((int)actor->arg1_f == 0) { + aCOU_setNowTime(actor); + } else { + return; + } + + if (CLIP(countdown_clip) != NULL && CLIP(countdown_clip)->anime_play_flag == FALSE && actor->arg0 <= 2) { + CLIP(countdown_clip)->anime_play_proc(); + } + + if (actor->arg1 != actor->arg0) { + if ((int)actor->arg2_f == 0 && mEv_check_status(mEv_EVENT_NEW_YEARS_EVE_COUNTDOWN, mEv_STATUS_PLAYSOUND)) { + actor->arg2_f = 1.0f; + } + + for (i = 0; i < 4; i++) { + if (aCOU_getTime(actor->arg0, 3 - i) != aCOU_getTime(actor->arg1, 3 - i)) { + break; + } + + digit_bits >>= 1; + } + + actor->arg2 = digit_bits; + } +} + +static void aCOU_setup_action(STRUCTURE_ACTOR* actor, int action) { + static aSTR_MOVE_PROC process[] = { + // clang-format off + aCOU_init, + aCOU_wait, + // why are these here? + NULL, + NULL, + // clang-format on + }; + + if (action == aCOU_ACT_INIT) { + cKF_SkeletonInfo_R_init(&actor->keyframe, actor->keyframe.skeleton, &cKF_ba_r_obj_e_count02_cl, 1.0f, 10.0f, + 1.0f, 0.5f, 0.0f, cKF_FRAMECONTROL_STOP, NULL); + } + + actor->action_proc = process[action]; + actor->action = action; +} + +static void aCOU_actor_move(ACTOR* actorx, GAME* game) { + GAME_PLAY* play = (GAME_PLAY*)game; + STRUCTURE_ACTOR* actor = (STRUCTURE_ACTOR*)actorx; + 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->action_proc)(actor, play); +} + +static void aCOU_actor_init(ACTOR* actorx, GAME* game) { + mFI_SetFG_common(DUMMY_COUNT02, actorx->home.position, FALSE); + aCOU_actor_move(actorx, game); + actorx->mv_proc = aCOU_actor_move; +}