From ba410c175ba1477bdb31364f2ee53908a7a2c358 Mon Sep 17 00:00:00 2001 From: Cuyler36 Date: Wed, 28 Feb 2024 14:53:10 -0500 Subject: [PATCH] Implement & link ac_misin --- config/rel_slices.yml | 4 + include/ac_misin.h | 53 +++++- include/m_clip.h | 98 +++++------ src/ac_misin.c | 370 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 478 insertions(+), 47 deletions(-) create mode 100644 src/ac_misin.c diff --git a/config/rel_slices.yml b/config/rel_slices.yml index 3cbf7cae..46105227 100644 --- a/config/rel_slices.yml +++ b/config/rel_slices.yml @@ -430,6 +430,10 @@ ac_mbg.c: .text: [0x8042DCA0, 0x8042DEC8] .rodata: [0x80644218, 0x80644238] .data: [0x80684BB0, 0x80684CB8] +ac_misin.c: + .text: [0x8042DEC8, 0x8042EAE0] + .rodata: [0x80644238, 0x80644288] + .data: [0x80684CB8, 0x80684D20] ac_museum_fossil.c: .text: [0x8042EDC0, 0x8042F170] .rodata: [0x806442A0, 0x806442D0] diff --git a/include/ac_misin.h b/include/ac_misin.h index e736f8ba..a25bf781 100644 --- a/include/ac_misin.h +++ b/include/ac_misin.h @@ -3,11 +3,63 @@ #include "types.h" #include "m_actor.h" +#include "m_needlework.h" +#include "c_keyframe.h" #ifdef __cplusplus extern "C" { #endif +typedef struct misin_actor_s MISIN_ACTOR; + +typedef void (*aMSN_REQUEST_MISIN_STOP_PROC)(void); +typedef void (*aMSN_REQUEST_MISIN_MOVE_PROC)(void); + +typedef void (*aMSN_REQUEST_DUSTCLOTH_STOP_PROC)(void); +typedef void (*aMSN_REQUEST_DUSTCLOTH_MOVE_PROC)(void); + +typedef struct misin_clip_s { + MISIN_ACTOR* misin_actor_p; + aMSN_REQUEST_MISIN_STOP_PROC request_misin_stop_proc; + aMSN_REQUEST_MISIN_MOVE_PROC request_misin_move_proc; + aMSN_REQUEST_DUSTCLOTH_STOP_PROC request_dustcloth_stop_proc; + aMSN_REQUEST_DUSTCLOTH_MOVE_PROC request_dustcloth_move_proc; +} aMSN_Clip_c; + +#define aMSN_GetClip() ((aMSN_Clip_c*)Common_Get(clip).misin_clip) + +typedef struct misin_dustcloth_s { + s16 switch_flag; + s16 frame; + xyz_t pos; + xyz_t target_pos; + int target_idx; + s16 target_angle_y; + int moving_flag; + mNW_original_design_c* original_p; + u16* palette_p; +} aMSN_DustCloth_c; + +typedef struct misin_misin_s { + s16 status; + f32 speed; + xyz_t pos; + f32 needle_y_counter; + xyz_t needle_offset; + s16 y_scroll; + cKF_SkeletonInfo_R_c keyframe; + s_xyz work[17]; + s_xyz morph[17]; + Mtx mtx[2][16] ATTRIBUTE_ALIGN(8); +} aMSN_Misin_c; + +struct misin_actor_s { + ACTOR actor_class; + aMSN_DustCloth_c dustcloth; + aMSN_Misin_c misin; + aMSN_Clip_c clip; +}; + extern ACTOR_PROFILE Misin_Profile; #ifdef __cplusplus @@ -15,4 +67,3 @@ extern ACTOR_PROFILE Misin_Profile; #endif #endif - diff --git a/include/m_clip.h b/include/m_clip.h index 5c19bd74..306f493f 100644 --- a/include/m_clip.h +++ b/include/m_clip.h @@ -32,52 +32,58 @@ typedef void (*CLIP_NONE_PROC)(); /* sizeof(Clip_c) == 0x104 */ typedef struct clip_s { - /* 0x000 */ void* _000[(0x020 - 0x000) / sizeof(void*)]; - /* 0x020 */ int arrange_ftr_num; - /* 0x024 */ void* _024[(0x040 - 0x024) / sizeof(void*)]; - /* 0x040 */ aNPC_Clip_c* npc_clip; - /* 0x044 */ void* _044[(0x060 - 0x044) / sizeof(void*)]; - /* 0x060 */ aSM_Clip_c* shop_manekin_clip; - /* 0x064 */ void* _064; - /* 0x068 */ CLIP_NONE_PROC _068; - /* 0x06C */ aQMgr_Clip_c* quest_manager_clip; - /* 0x070 */ aSI_Clip_c* shop_indoor_clip; - /* 0x074 */ bIT_Clip_c* bg_item_clip; - /* 0x078 */ aWeather_Clip_c* weather_clip; - /* 0x07C */ aINS_Clip_c* insect_clip; - /* 0x080 */ aMR_Clip_c* my_room_clip; - /* 0x084 */ void* _084; - /* 0x088 */ aHOI_Clip_c* handOverItem_clip; - /* 0x08C */ aSTR_Clip_c* structure_clip; - /* 0x090 */ eEC_EffectControl_Clip_c* effect_clip; - /* 0x094 */ aTOL_Clip_c* tools_clip; - /* 0x098 */ void* _098; - /* 0x09C */ aMI_Clip_c* my_indoor_clip; - /* 0x0A0 */ mDemo_Clip_c* demo_clip; /* can be multiple clip classes */ - /* 0x0A4 */ mDemo_Clip_c* demo_clip2; /* can be multiple clip classes */ - /* 0x0A8 */ void* _0A8; - /* 0x0AC */ aGYO_Clip_c* gyo_clip; - /* 0x0B0 */ void* _0B0; - /* 0x0B4 */ void* _0B4; - /* 0x0B8 */ aShopUmbrella_Clip_c* shop_umbrella_clip; - /* 0x0BC */ aAR_Clip_c* arrange_room_clip; - /* 0x0C0 */ void* _0C0; - /* 0x0C4 */ void* _0C4; - /* 0x0C8 */ void* shrine_clip; - /* 0x0CC */ void* _0CC; - /* 0x0D0 */ void* _0D0; - /* 0x0D4 */ CLIP_NONE_PROC ball_redma_proc; /* removed in DnM+ */ - /* 0x0D8 */ void* _0D8; - /* 0x0DC */ aAL_Clip_c* animal_logo_clip; - /* 0x0E0 */ void* _0E0; - /* 0x0E4 */ void* _0E4; - /* 0x0E8 */ void* _0E8; - /* 0x0EC */ aAPC_Clip_c* aprilfool_control_clip; - /* 0x0F0 */ aEvMgr_Clip_c* event_manager_clip; - /* 0x0F4 */ aGHC_Clip_c* groundhog_control_clip; - /* 0x0F8 */ void* _0F8; - /* 0x0FC */ void* _0FC; - /* 0x100 */ void* _100; + /* 0x000 */ void* _000[(0x020 - 0x000) / sizeof(void*)]; + /* 0x020 */ int arrange_ftr_num; + /* 0x024 */ void* _024; + /* 0x028 */ void* misin_clip; + /* 0x02C */ void* _02C; + /* 0x030 */ void* _030; + /* 0x034 */ void* _034; + /* 0x038 */ void* _038; + /* 0x03C */ void* _03C; + /* 0x040 */ aNPC_Clip_c* npc_clip; + /* 0x044 */ void* _044[(0x060 - 0x044) / sizeof(void*)]; + /* 0x060 */ aSM_Clip_c* shop_manekin_clip; + /* 0x064 */ void* _064; + /* 0x068 */ CLIP_NONE_PROC _068; + /* 0x06C */ aQMgr_Clip_c* quest_manager_clip; + /* 0x070 */ aSI_Clip_c* shop_indoor_clip; + /* 0x074 */ bIT_Clip_c* bg_item_clip; + /* 0x078 */ aWeather_Clip_c* weather_clip; + /* 0x07C */ aINS_Clip_c* insect_clip; + /* 0x080 */ aMR_Clip_c* my_room_clip; + /* 0x084 */ void* _084; + /* 0x088 */ aHOI_Clip_c* handOverItem_clip; + /* 0x08C */ aSTR_Clip_c* structure_clip; + /* 0x090 */ eEC_EffectControl_Clip_c* effect_clip; + /* 0x094 */ aTOL_Clip_c* tools_clip; + /* 0x098 */ void* _098; + /* 0x09C */ aMI_Clip_c* my_indoor_clip; + /* 0x0A0 */ mDemo_Clip_c* demo_clip; /* can be multiple clip classes */ + /* 0x0A4 */ mDemo_Clip_c* demo_clip2; /* can be multiple clip classes */ + /* 0x0A8 */ void* _0A8; + /* 0x0AC */ aGYO_Clip_c* gyo_clip; + /* 0x0B0 */ void* _0B0; + /* 0x0B4 */ void* _0B4; + /* 0x0B8 */ aShopUmbrella_Clip_c* shop_umbrella_clip; + /* 0x0BC */ aAR_Clip_c* arrange_room_clip; + /* 0x0C0 */ void* _0C0; + /* 0x0C4 */ void* _0C4; + /* 0x0C8 */ void* shrine_clip; + /* 0x0CC */ void* _0CC; + /* 0x0D0 */ void* _0D0; + /* 0x0D4 */ CLIP_NONE_PROC ball_redma_proc; /* removed in DnM+ */ + /* 0x0D8 */ void* _0D8; + /* 0x0DC */ aAL_Clip_c* animal_logo_clip; + /* 0x0E0 */ void* _0E0; + /* 0x0E4 */ void* _0E4; + /* 0x0E8 */ void* _0E8; + /* 0x0EC */ aAPC_Clip_c* aprilfool_control_clip; + /* 0x0F0 */ aEvMgr_Clip_c* event_manager_clip; + /* 0x0F4 */ aGHC_Clip_c* groundhog_control_clip; + /* 0x0F8 */ void* _0F8; + /* 0x0FC */ void* _0FC; + /* 0x100 */ void* _100; } Clip_c; extern void clip_clear(); diff --git a/src/ac_misin.c b/src/ac_misin.c new file mode 100644 index 00000000..2ccb610f --- /dev/null +++ b/src/ac_misin.c @@ -0,0 +1,370 @@ +#include "ac_misin.h" + +#include "m_common_data.h" +#include "m_malloc.h" +#include "m_player_lib.h" +#include "m_rcp.h" +#include "sys_matrix.h" + +static void Misin_Actor_ct(ACTOR* actorx, GAME* game); +static void Misin_Actor_dt(ACTOR* actorx, GAME* game); +static void Misin_Actor_draw(ACTOR* actorx, GAME* game); +static void Misin_Actor_move(ACTOR* actorx, GAME* game); + +ACTOR_PROFILE Misin_Profile = { + mAc_PROFILE_MISIN, + ACTOR_PART_BG, + ACTOR_STATE_CAN_MOVE_IN_DEMO_SCENES | ACTOR_STATE_NO_DRAW_WHILE_CULLED | ACTOR_STATE_NO_MOVE_WHILE_CULLED, + EMPTY_NO, + ACTOR_OBJ_BANK_KEEP, + sizeof(MISIN_ACTOR), + &Misin_Actor_ct, + &Misin_Actor_dt, + &Misin_Actor_move, + &Misin_Actor_draw, + NULL, +}; + +static void aMSN_SetDustclothSwitch(s16 switch_flag) { + if (aMSN_GetClip() != NULL) { + aMSN_GetClip()->misin_actor_p->dustcloth.switch_flag = switch_flag; + } +} + +static void aMSN_RequestDustclothMove(void) { + aMSN_SetDustclothSwitch(TRUE); +} + +static void aMSN_RequestDustclothStop(void) { + aMSN_SetDustclothSwitch(FALSE); +} + +static xyz_t aMSN_dustcloth_target_table[4] = { + { -4.0f, 0.0f, 4.0f }, + { -4.0f, 0.0f, -4.0f }, + { 4.0f, 0.0f, -4.0f }, + { 4.0f, 0.0f, 4.0f }, +}; + +static void aMSN_DustclothCT(aMSN_DustCloth_c* dustcloth, GAME* game) { + dustcloth->switch_flag = TRUE; + dustcloth->frame = 0; + dustcloth->original_p = (mNW_original_design_c*)zelda_malloc_align(sizeof(mNW_original_design_c), 32); + + if (dustcloth->original_p != NULL) { + if (RANDOM(3) == 1) { + mNW_CopyOriginalTextureClass(dustcloth->original_p, + &Save_Get(needlework).original_design[RANDOM(1000) & 7]); + } else { + dustcloth->palette_p = (u16*)zelda_malloc_align(sizeof(u16) * 16, 32); + if (dustcloth->palette_p != NULL) { + mActor_name_t cloth; + + mSP_SelectRandomItem_New(NULL, &cloth, 1, NULL, 0, mSP_KIND_CLOTH, mSP_LISTTYPE_ABC, FALSE); + mPlib_Load_PlayerTexAndPallet(dustcloth->original_p->design.data, dustcloth->palette_p, + ITEM_NAME_GET_INDEX(cloth)); + } + } + } + + dustcloth->target_idx = 1; + dustcloth->pos.x = 91.0f; + dustcloth->pos.y = 0.0f; + dustcloth->pos.z = 136.0f; + dustcloth->target_pos = aMSN_dustcloth_target_table[(dustcloth->target_idx - 1) & 3]; +} + +static void aMSN_SetMisinStatus(s16 status) { + if (aMSN_GetClip() != NULL) { + aMSN_GetClip()->misin_actor_p->misin.status = status; + } +} + +static void aMSN_RequestMisinStop(void) { + aMSN_SetMisinStatus(FALSE); +} + +static void aMSN_ReqeustMisinMove(void) { + aMSN_SetMisinStatus(TRUE); +} + +extern cKF_Skeleton_R_c cKF_bs_r_obj_misin; +extern cKF_Animation_R_c cKF_ba_r_obj_misin; + +static void aMSN_MisinCT(aMSN_Misin_c* misin, GAME* game) { + cKF_SkeletonInfo_R_c* keyframe = &misin->keyframe; + + misin->status = TRUE; + cKF_SkeletonInfo_R_ct(keyframe, &cKF_bs_r_obj_misin, &cKF_ba_r_obj_misin, misin->work, misin->morph); + cKF_SkeletonInfo_R_init_standard_repeat(keyframe, &cKF_ba_r_obj_misin, NULL); + cKF_SkeletonInfo_R_play(keyframe); + + misin->speed = 1.0f; + keyframe->frame_control.speed = 1.0f; + misin->pos.x = 0.0f; + misin->pos.y = 0.0f; + misin->pos.z = 0.0f; + misin->needle_y_counter = 0.0f; +} + +static void aMSN_SetClipInfo(ACTOR* actorx, GAME* game) { + MISIN_ACTOR* misin_actor = (MISIN_ACTOR*)actorx; + aMSN_Clip_c* clip = &misin_actor->clip; + + clip->misin_actor_p = misin_actor; + clip->request_misin_stop_proc = &aMSN_RequestMisinStop; + clip->request_misin_move_proc = &aMSN_ReqeustMisinMove; + clip->request_dustcloth_stop_proc = &aMSN_RequestDustclothStop; + clip->request_dustcloth_move_proc = &aMSN_RequestDustclothMove; + Common_Get(clip).misin_clip = clip; +} + +static void Misin_Actor_ct(ACTOR* actorx, GAME* game) { + MISIN_ACTOR* misin_actor = (MISIN_ACTOR*)actorx; + aMSN_DustCloth_c* dustcloth = &misin_actor->dustcloth; + aMSN_Misin_c* misin = &misin_actor->misin; + + aMSN_DustclothCT(dustcloth, game); + aMSN_MisinCT(misin, game); + aMSN_SetClipInfo(actorx, game); +} + +static void Misin_Actor_dt(ACTOR* actorx, GAME* game) { + MISIN_ACTOR* misin = (MISIN_ACTOR*)actorx; + + if (misin->dustcloth.original_p != NULL) { + zelda_free(misin->dustcloth.original_p); + } + + if (misin->dustcloth.palette_p != NULL) { + zelda_free(misin->dustcloth.palette_p); + } + + Common_Get(clip).misin_clip = NULL; +} + +extern Gfx obj_misin_cloth_model[]; + +static void aMSN_DrawDustcloth(aMSN_DustCloth_c* dustcloth, GAME* game) { + s16 target_angle_y = dustcloth->target_angle_y; + + if (dustcloth->original_p != NULL) { + _texture_z_light_fog_prim(game->graph); + + OPEN_DISP(game->graph); + + /* Segment 8 holds the custom design or shirt texture */ + gSPSegment(NEXT_POLY_OPA_DISP, G_MWO_SEGMENT_8, dustcloth->original_p->design.data); + + if (dustcloth->palette_p != NULL) { + /* Segment 9 holds the palette for the shirt */ + gSPSegment(NEXT_POLY_OPA_DISP, G_MWO_SEGMENT_9, dustcloth->palette_p); + } else { + /* Segment 9 holds the palette for the custom design */ + gSPSegment(NEXT_POLY_OPA_DISP, G_MWO_SEGMENT_9, mNW_PaletteIdx2Palette(dustcloth->original_p->palette)); + } + + Matrix_translate(dustcloth->pos.x, dustcloth->pos.y, dustcloth->pos.z, 0); + Matrix_RotateY(target_angle_y, 1); + Matrix_translate(-dustcloth->target_pos.x, -dustcloth->target_pos.y, -dustcloth->target_pos.z, 1); + Matrix_scale(0.01f, 0.01f, 0.01f, 1); + + gSPMatrix(NEXT_POLY_OPA_DISP, _Matrix_to_Mtx_new(game->graph), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(NEXT_POLY_OPA_DISP, obj_misin_cloth_model); + + CLOSE_DISP(game->graph); + } +} + +static int aMSN_DrawMisinBefore(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) { + /* Skip drawing the needle model */ + if (joint_idx == 3) { + *joint_shape = NULL; + } + + return TRUE; +} + +extern Gfx obj_misin_hari_model[]; + +static int aMSN_DrawMisinAfter(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) { + aMSN_Misin_c* misin = (aMSN_Misin_c*)arg; + + /* Now draw the needle model */ + if (joint_idx == 3) { + OPEN_DISP(game->graph); + + Matrix_translate(87.0f, 62.0f + misin->needle_offset.y, 141.0f, 0); + Matrix_RotateY(DEG2SHORT_ANGLE(0.0f), 1); + Matrix_RotateZ(DEG2SHORT_ANGLE(-90.0f), 1); + Matrix_scale(0.01f, 0.01f, 0.01f, 1); + + gSPMatrix(NEXT_POLY_OPA_DISP, _Matrix_to_Mtx_new(game->graph), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(NEXT_POLY_OPA_DISP, obj_misin_hari_model); + + CLOSE_DISP(game->graph); + } + + return TRUE; +} + +static Gfx* aMSN_MakeBeltGFX(aMSN_Misin_c* misin, GAME* game) { + return two_tex_scroll_dolphin(game->graph, 0, 0, misin->y_scroll, 8, 32, 1, 0, 0, 0, 0); +} + +static void aMSN_DrawMisin(aMSN_Misin_c* misin, GAME* game) { + cKF_SkeletonInfo_R_c* keyframe = &misin->keyframe; + Mtx* mtx_p = misin->mtx[game->frame_counter & 1]; + Gfx* belt_gfx = aMSN_MakeBeltGFX(misin, game); + + _texture_z_light_fog_prim(game->graph); + if (belt_gfx != NULL) { + OPEN_DISP(game->graph); + + Matrix_translate(misin->pos.x, misin->pos.y, misin->pos.z, 0); + Matrix_RotateY(DEG2SHORT_ANGLE(0.0f), 1); + Matrix_scale(0.01f, 0.01f, 0.01f, 1); + + gSPMatrix(NEXT_POLY_OPA_DISP, _Matrix_to_Mtx_new(game->graph), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + + /* Segment 9 has the scrolled belt gfx */ + gSPSegment(NEXT_POLY_OPA_DISP, G_MWO_SEGMENT_9, belt_gfx); + + /* Draw animated model */ + cKF_Si3_draw_R_SV(game, keyframe, mtx_p, &aMSN_DrawMisinBefore, &aMSN_DrawMisinAfter, misin); + + CLOSE_DISP(game->graph); + } +} + +static void Misin_Actor_draw(ACTOR* actorx, GAME* game) { + MISIN_ACTOR* misin = (MISIN_ACTOR*)actorx; + + aMSN_DrawDustcloth(&misin->dustcloth, game); + aMSN_DrawMisin(&misin->misin, game); +} + +static void aMSN_MoveDustcloth(aMSN_DustCloth_c* dustcloth, GAME* game) { + static s16 target_angle_table[4] = { + DEG2SHORT_ANGLE(0.0f), + DEG2SHORT_ANGLE(90.0f), + DEG2SHORT_ANGLE(-180.0f), + DEG2SHORT_ANGLE(-90.0f), + }; + dustcloth->moving_flag = FALSE; + + if (dustcloth->switch_flag != FALSE) { + if (dustcloth->frame == 137) { + int target_idx = dustcloth->target_idx; + + dustcloth->target_pos = aMSN_dustcloth_target_table[target_idx]; + dustcloth->target_angle_y = target_angle_table[target_idx]; + + if (dustcloth->target_angle_y == DEG2SHORT_ANGLE(0.0f)) { + dustcloth->target_angle_y = -1; + } + } + + if (dustcloth->frame < 98) { + f32 percent = get_percent(97, 0, dustcloth->frame); + int now_idx = dustcloth->target_idx; + int prev_idx = (dustcloth->target_idx - 1) & 3; + + /* Interpolate position between last target pos & now target pos */ + dustcloth->target_pos.x = + aMSN_dustcloth_target_table[prev_idx].x + + percent * (aMSN_dustcloth_target_table[now_idx].x - aMSN_dustcloth_target_table[prev_idx].x); + dustcloth->target_pos.z = + aMSN_dustcloth_target_table[prev_idx].z + + percent * (aMSN_dustcloth_target_table[now_idx].z - aMSN_dustcloth_target_table[prev_idx].z); + + /* Set rotation */ + dustcloth->target_angle_y = target_angle_table[prev_idx]; + + if (dustcloth->frame > 21) { + /* Play sewing SFX */ + xyz_t pos = { 91.0f, 40.0f, 136.0f }; + + sAdo_OngenPos((u32)&aMSN_MoveDustcloth, 0x48, &pos); + } + } else if (dustcloth->frame >= 120) { + f32 percent = get_percent(138, 120, dustcloth->frame); + int now_idx = dustcloth->target_idx; + int prev_idx = (dustcloth->target_idx - 1) & 3; + + /* Interpolate rotation */ + dustcloth->target_angle_y = target_angle_table[prev_idx] + (s16)(percent * (f32)DEG2SHORT_ANGLE(90.0f)); + } + + if (!(dustcloth->frame > 4 && dustcloth->frame < 118)) { + dustcloth->moving_flag = TRUE; + } + + dustcloth->frame++; + if (dustcloth->frame >= 138) { + dustcloth->target_idx = (dustcloth->target_idx + 1) & 3; + dustcloth->frame = 0; + } + } +} + +static void aMSN_SetNeedleOffsetPosition(aMSN_Misin_c* misin, aMSN_DustCloth_c* dustcloth) { + static xyz_t zero_offset = { 0.0f, 0.0f, 0.0f }; + int counter = misin->needle_y_counter; + + if (counter < 10) { + misin->needle_offset.y = (misin->needle_y_counter / 10.0f) * -3.0f; + } else if (counter < 17) { + misin->needle_offset.y = ((misin->needle_y_counter - 10.0f) / 7.0f) * 3.0f + -3.0f; + } else { + misin->needle_offset = zero_offset; + } + + if (dustcloth->moving_flag == FALSE) { + misin->needle_y_counter += misin->speed; + } + + if (misin->needle_y_counter > 19.0f) { + misin->needle_y_counter -= 19.0f; + } +} + +static void aMSN_MoveMisin(aMSN_Misin_c* misin, aMSN_DustCloth_c* dustcloth, GAME* game) { + f32 target_speed; + cKF_SkeletonInfo_R_c* keyframe; + + if (misin->status == TRUE) { + target_speed = 1.0f; + } else { + target_speed = 0.0f; + } + + keyframe = &misin->keyframe; + aMSN_SetNeedleOffsetPosition(misin, dustcloth); + misin->y_scroll += (s16)(misin->speed * -6.0f); + cKF_SkeletonInfo_R_play(keyframe); + + if (misin->speed < target_speed) { + misin->speed += 0.01f; + } else { + misin->speed -= 0.01f; + } + + if (misin->speed < 0.0f) { + misin->speed = 0.0f; + } else if (misin->speed > 1.0f) { + misin->speed = 1.0f; + } + + keyframe->frame_control.speed = misin->speed; +} + +static void Misin_Actor_move(ACTOR* actorx, GAME* game) { + MISIN_ACTOR* misin = (MISIN_ACTOR*)actorx; + aMSN_DustCloth_c* dustcloth = &misin->dustcloth; + + aMSN_MoveDustcloth(dustcloth, game); + aMSN_MoveMisin(&misin->misin, dustcloth, game); +}