Files
ac-decomp/src/ac_misin.c
T
2024-02-28 14:53:10 -05:00

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