#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); }