mirror of
https://github.com/ACreTeam/ac-decomp
synced 2026-05-25 07:02:50 -04:00
371 lines
12 KiB
C
371 lines
12 KiB
C
#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);
|
|
}
|