Implement & link ac_mailbox

This commit is contained in:
Cuyler36
2025-05-24 16:23:00 -04:00
parent 39d5602766
commit 2f436ab3ef
4 changed files with 445 additions and 2 deletions
+1 -1
View File
@@ -1014,7 +1014,7 @@ config.libs = [
Object(Matching, "actor/ac_koinobori.c"),
Object(NonMatching, "actor/ac_lighthouse_switch.c"),
Object(Matching, "actor/ac_lotus.c"),
Object(NonMatching, "actor/ac_mailbox.c"),
Object(Matching, "actor/ac_mailbox.c"),
Object(Matching, "actor/ac_mbg.c"),
Object(Matching, "actor/ac_mikanbox.c"),
Object(Matching, "actor/ac_mikuji.c"),
+39 -1
View File
@@ -3,11 +3,50 @@
#include "types.h"
#include "m_actor.h"
#include "c_keyframe.h"
#ifdef __cplusplus
extern "C" {
#endif
#define aMBX_PLAYER_OPEN_ANGLE DEG2SHORT_ANGLE2(38.2379150390625f)
typedef struct mailbox_actor_s MAILBOX_ACTOR;
typedef void (*aMBX_ACT_PROC)(MAILBOX_ACTOR* actor, GAME_PLAY* play);
#define aMBX_JOINT_NUM 6
enum {
aMBX_REQUEST_NONE, // no current request
aMBX_REQUEST_DELIVERY, // delivery by Pete, open -> close
aMBX_REQUEST_OPEN, // player opens mailbox, hold state for submenu
aMBX_REQUEST_NUM
};
struct mailbox_actor_s {
ACTOR actor_class;
void* segp;
int kf0_state;
cKF_SkeletonInfo_R_c kf0;
s_xyz joint0[aMBX_JOINT_NUM+1];
s_xyz morph0[aMBX_JOINT_NUM+1];
int anim_idx0;
int kf1_state;
cKF_SkeletonInfo_R_c kf1;
s_xyz joint1[aMBX_JOINT_NUM+1];
s_xyz morph1[aMBX_JOINT_NUM+1];
int anim_idx1;
int action;
aMBX_ACT_PROC act_proc;
int arrange_idx;
int req;
};
extern ACTOR_PROFILE MailBox_Profile;
#ifdef __cplusplus
@@ -15,4 +54,3 @@ extern ACTOR_PROFILE MailBox_Profile;
#endif
#endif
+199
View File
@@ -0,0 +1,199 @@
#include "ac_mailbox.h"
#include "m_common_data.h"
#include "sys_matrix.h"
#include "m_rcp.h"
#include "m_house.h"
#include "m_player_lib.h"
enum {
aMBX_ACT_WAIT,
aMBX_ACT_PL_WAIT,
aMBX_ACT_OPEN_AND_CLOSE,
aMBX_ACT_PL_OPEN,
aMBX_ACT_PL_CLOSE,
aMBX_ACT_NUM
};
enum {
aMBX_ANIME_WAIT,
aMBX_ANIME_OPEN_AND_CLOSE,
aMBX_ANIME_PL_OPEN,
aMBX_ANIME_PL_CLOSE,
aMBX_ANIME_FLAG_UP,
aMBX_ANIME_FLAG_UP_WAIT,
aMBX_ANIME_FLAG_DOWN,
aMBX_ANIME_NUM
};
static void aMBX_actor_ct(ACTOR* actorx, GAME* game);
static void aMBX_actor_dt(ACTOR* actorx, GAME* game);
static void aMBX_actor_move(ACTOR* actorx, GAME* game);
static void aMBX_actor_init(ACTOR* actorx, GAME* game);
static void aMBX_actor_draw(ACTOR* actorx, GAME* game);
// clang-format off
ACTOR_PROFILE MailBox_Profile = {
mAc_PROFILE_MAILBOX,
ACTOR_PART_ITEM,
ACTOR_STATE_NONE,
ACTOR_PROP_MAILBOX0,
ACTOR_OBJ_BANK_26,
sizeof(MAILBOX_ACTOR),
aMBX_actor_ct,
aMBX_actor_dt,
aMBX_actor_init,
mActor_NONE_PROC1,
NULL,
};
// clang-format on
extern cKF_Skeleton_R_c cKF_bs_r_obj_s_post;
extern cKF_Skeleton_R_c cKF_bs_r_obj_w_post;
extern cKF_Animation_R_c cKF_ba_r_obj_s_post_delivery1;
extern cKF_Animation_R_c cKF_ba_r_obj_s_post_flag_off1;
extern cKF_Animation_R_c cKF_ba_r_obj_s_post_flag_on1;
extern cKF_Animation_R_c cKF_ba_r_obj_s_post_flag_on_wait1;
extern cKF_Animation_R_c cKF_ba_r_obj_s_post_open1;
extern cKF_Animation_R_c cKF_ba_r_obj_s_post;
typedef struct {
cKF_Animation_R_c* anim;
f32 start;
f32 end;
} aMBX_anime_info_c;
static aMBX_anime_info_c aMBX_animeTable[7] = {
{ &cKF_ba_r_obj_s_post, 1.0f, 2.0f },
{ &cKF_ba_r_obj_s_post_delivery1, 1.0f, 98.0f },
{ &cKF_ba_r_obj_s_post_open1, 1.0f, 31.0f },
{ &cKF_ba_r_obj_s_post_open1, 31.0f, 1.0f },
{ &cKF_ba_r_obj_s_post_flag_on1, 1.0f, 17.0f },
{ &cKF_ba_r_obj_s_post_flag_on_wait1, 1.0f, 31.0f },
{ &cKF_ba_r_obj_s_post_flag_off1, 1.0f, 17.0f },
};
static int aMBX_animeSeqNoTable[5] = {
aMBX_ANIME_WAIT,
aMBX_ANIME_WAIT,
aMBX_ANIME_OPEN_AND_CLOSE,
aMBX_ANIME_PL_OPEN,
aMBX_ANIME_PL_CLOSE,
};
static cKF_Skeleton_R_c* aMBX_skeleton[2] = { &cKF_bs_r_obj_s_post, &cKF_bs_r_obj_w_post };
static void aMBX_check_flag(MAILBOX_ACTOR* actor);
static void aMBX_setupAction(MAILBOX_ACTOR* actor, int action);
static void aMBX_actor_ct(ACTOR* actorx, GAME* game) {
static s16 angle_table[] = {
DEG2SHORT_ANGLE(90.0f),
DEG2SHORT_ANGLE(0.0f),
DEG2SHORT_ANGLE(90.0f),
DEG2SHORT_ANGLE(0.0f),
};
MAILBOX_ACTOR* actor = (MAILBOX_ACTOR*)actorx;
int season = Common_Get(time.season) == mTM_SEASON_WINTER;
int idx = actorx->npc_id - ACTOR_PROP_MAILBOX0;
cKF_Skeleton_R_c* skeleton_p = aMBX_skeleton[season];
cKF_SkeletonInfo_R_ct(&actor->kf0, skeleton_p, NULL, actor->joint0, actor->morph0);
cKF_SkeletonInfo_R_ct(&actor->kf1, skeleton_p, NULL, actor->joint1, actor->morph1);
actor->segp = ((GAME_PLAY*)game)->object_exchange.banks[actorx->data_bank_id].ram_start;
actor->anim_idx0 = aMBX_ANIME_NUM;
actor->arrange_idx = idx;
actor->anim_idx1 = aMBX_ANIME_NUM;
actorx->shape_info.rotation.y = angle_table[idx];
aMBX_check_flag(actor);
actor->kf0.frame_control.current_frame = actor->kf0.frame_control.end_frame;
}
static void aMBX_actor_dt(ACTOR* actorx, GAME* game) {
MAILBOX_ACTOR* actor = (MAILBOX_ACTOR*)actorx;
cKF_SkeletonInfo_R_dt(&actor->kf0); // @BUG - why not dt on the second skeleton??
}
#include "../src/actor/ac_mailbox_move.c_inc"
static Gfx post_flag_saki_common_DL[] = {
gsSPTexture(65535, 65535, 0, 0, G_ON),
gsDPSetRenderMode(G_RM_FOG_SHADE_A, G_RM_AA_ZB_TEX_EDGE2),
gsDPSetPrimColor(0, 128, 255, 255, 255, 255),
gsSPLoadGeometryMode(G_ZBUFFER | G_SHADE | G_FOG | G_SHADING_SMOOTH),
gsSPEndDisplayList(),
};
static Gfx post_flag_saki_model_type0[] = {
gsSPDisplayList(post_flag_saki_common_DL),
gsDPSetCombineLERP(0, 0, 0, TEXEL0, 0, 0, 0, TEXEL0, PRIMITIVE, 0, COMBINED, 0, 0, 0, 0, COMBINED),
gsDPLoadTextureBlock_4b_Dolphin(anime_1_txt, G_IM_FMT_CI, 16, 32, 15, GX_MIRROR, GX_CLAMP, 0, 0),
gsDPSetTileSize(0, 0, 0, 124, 124),
gsSPEndDisplayList(),
};
static Gfx post_flag_saki_model_type1[] = {
gsSPDisplayList(post_flag_saki_common_DL),
gsDPSetCombineLERP(TEXEL0, 0, SHADE, 0, 0, 0, 0, TEXEL0, PRIMITIVE, 0, COMBINED, 0, 0, 0, 0, COMBINED),
gsDPLoadTextureBlock_4b_Dolphin(anime_2_txt, G_IM_FMT_CI, 16, 32, 15, GX_MIRROR, GX_CLAMP, 0, 0),
gsSPEndDisplayList(),
};
static int aMBX_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) {
static Gfx* post_flag_saki_model[] = { post_flag_saki_model_type0, post_flag_saki_model_type1 };
MAILBOX_ACTOR* actor = (MAILBOX_ACTOR*)arg;
if (joint_idx == 3) {
GRAPH* graph = game->graph;
int idx = actor->anim_idx1 == aMBX_ANIME_FLAG_UP_WAIT;
OPEN_POLY_OPA_DISP(graph);
gSPDisplayList(POLY_OPA_DISP++, post_flag_saki_model[idx]);
CLOSE_POLY_OPA_DISP(graph);
}
return TRUE;
}
extern u8 obj_s_post_flag2_TA_tex_txt[];
extern u8 obj_w_post_flag2_TA_tex_txt[];
extern EVW_ANIME_DATA obj_s_post_flag_on_wait1_evw_anime;
extern EVW_ANIME_DATA obj_w_post_flag_on_wait1_evw_anime;
static void aMBX_actor_draw(ACTOR* actorx, GAME* game) {
static u8* tex_table[] = { obj_s_post_flag2_TA_tex_txt, obj_w_post_flag2_TA_tex_txt };
static EVW_ANIME_DATA* evw_table[] = { &obj_s_post_flag_on_wait1_evw_anime, &obj_w_post_flag_on_wait1_evw_anime };
MAILBOX_ACTOR* actor = (MAILBOX_ACTOR*)actorx;
cKF_SkeletonInfo_R_c* kf0 = &actor->kf0;
GRAPH* graph = game->graph;
GAME_PLAY* play = (GAME_PLAY*)game;
Mtx* mtx = GRAPH_ALLOC_TYPE(graph, Mtx, kf0->skeleton->num_shown_joints);
if (mtx != NULL) {
_texture_z_light_fog_prim(graph);
if (actor->anim_idx1 == aMBX_ANIME_FLAG_UP_WAIT) {
Evw_Anime_Set(play, evw_table[Common_Get(time.season) == mTM_SEASON_WINTER]);
if (Common_Get(player_no) == mHS_get_pl_no(actor->arrange_idx) &&
play->game_frame % FRAMES_PER_SECOND == 0) {
sAdo_OngenTrgStart(0x43B, &actorx->world.position);
}
} else {
OPEN_POLY_OPA_DISP(graph);
gSPSegment(POLY_OPA_DISP++, ANIME_1_TXT_SEG, tex_table[Common_Get(time.season) == mTM_SEASON_WINTER]);
CLOSE_POLY_OPA_DISP(graph);
}
cKF_Si3_draw_R_SV(game, kf0, mtx, aMBX_actor_draw_before, NULL, actorx);
}
}
+206
View File
@@ -0,0 +1,206 @@
static void aMBX_anime_proc(ACTOR* actorx, GAME_PLAY* play) {
static s8 part_tbl[] = { 0, 0, 0, 1, 1, 0, 0 };
MAILBOX_ACTOR* actor = (MAILBOX_ACTOR*)actorx;
actor->kf0_state = cKF_SkeletonInfo_R_combine_play(&actor->kf0, &actor->kf1, part_tbl);
}
static void aMBX_setup_flag_anime(MAILBOX_ACTOR* actor, int anime_idx) {
aMBX_anime_info_c* info_p = &aMBX_animeTable[anime_idx];
cKF_SkeletonInfo_R_c* kf1 = &actor->kf1;
int mode = cKF_FRAMECONTROL_STOP;
if (anime_idx == aMBX_ANIME_FLAG_UP_WAIT) {
mode = cKF_FRAMECONTROL_REPEAT;
}
cKF_SkeletonInfo_R_init(kf1, kf1->skeleton, info_p->anim, info_p->start, info_p->end, info_p->start, 0.5f, 0.0f, mode, NULL);
actor->anim_idx1 = anime_idx;
}
static void aMBX_check_take_mail(MAILBOX_ACTOR* actor, GAME_PLAY* play) {
ACTOR* playerx = GET_PLAYER_ACTOR_ACTOR(play);
if (playerx != NULL) {
PLAYER_ACTOR* player = (PLAYER_ACTOR*)playerx;
int arrange_idx = actor->arrange_idx;
int pl_no = mHS_get_pl_no(arrange_idx);
ACTOR* actorx = (ACTOR*)actor;
int mbox_angle = actorx->shape_info.rotation.y + DEG2SHORT_ANGLE2(-45.0f);
int mbox_pl_angle = actorx->player_angle_y;
int dAngle = (s16)(mbox_pl_angle - mbox_angle);
int abs_dAngle = ABS(dAngle);
if (abs_dAngle < aMBX_PLAYER_OPEN_ANGLE && player->a_btn_pressed == TRUE && pl_no == Common_Get(player_no) && player->item_in_front == (DUMMY_MAILBOX0 + arrange_idx)) {
if (Common_Get(reset_flag) == TRUE && Now_Private->reset_count < 3) {
Common_Set(reset_type, 5);
} else if (!mPr_NullCheckPersonalID(&Save_Get(homes[arrange_idx]).ownerID)) {
Submenu* submenu = &play->submenu;
if (submenu->start_refuse == FALSE && submenu->start_refuse_timer == 0 && mPlib_able_submenu_type1((GAME*)play) && actor->req == 0) {
player->a_btn_triggers_submenu = TRUE;
actor->req = aMBX_REQUEST_OPEN;
}
}
}
}
}
static void aMBX_check_flag(MAILBOX_ACTOR* actor) {
int anime_idx = aMBX_ANIME_FLAG_DOWN;
int mail_count = mMl_count_use_mail_space(Save_Get(homes[actor->arrange_idx]).mailbox, HOME_MAILBOX_SIZE);
if (mail_count != 0) {
if (actor->anim_idx1 == aMBX_ANIME_FLAG_UP_WAIT || actor->anim_idx1 == aMBX_ANIME_NUM) {
anime_idx = aMBX_ANIME_FLAG_UP_WAIT;
} else {
anime_idx = aMBX_ANIME_FLAG_UP;
}
}
if (actor->anim_idx1 != anime_idx) {
aMBX_setup_flag_anime(actor, anime_idx);
}
}
static void aMBX_setup_flag_se_sub(u16 se_no, MAILBOX_ACTOR* actor, f32 frame) {
if (cKF_FrameControl_passCheck_now(&actor->kf1.frame_control, frame) == TRUE) {
sAdo_OngenTrgStart(se_no, &actor->actor_class.world.position);
}
}
static void aMBX_setup_flag_se(MAILBOX_ACTOR* actor) {
switch (actor->anim_idx1) {
case aMBX_ANIME_FLAG_UP:
aMBX_setup_flag_se_sub(0x433, actor, 15.0f);
break;
case aMBX_ANIME_FLAG_DOWN:
aMBX_setup_flag_se_sub(0x434, actor, 15.0f);
break;
}
}
static void aMBX_wait(MAILBOX_ACTOR* actor, GAME_PLAY* play) {
if (actor->kf0_state == cKF_STATE_STOPPED) {
aMBX_check_take_mail(actor, play);
switch (actor->req) {
case aMBX_REQUEST_DELIVERY:
aMBX_setupAction(actor, aMBX_ACT_OPEN_AND_CLOSE);
break;
case aMBX_REQUEST_OPEN:
aMBX_setupAction(actor, aMBX_ACT_PL_WAIT);
break;
}
}
aMBX_check_flag(actor);
if (actor->anim_idx1 == aMBX_ANIME_FLAG_UP && actor->kf1.frame_control.current_frame == actor->kf1.frame_control.end_frame) {
aMBX_setup_flag_anime(actor, aMBX_ANIME_FLAG_UP_WAIT);
}
}
static void aMBX_pl_wait(MAILBOX_ACTOR* actor, GAME_PLAY* play) {
static s16 angle[] = { DEG2SHORT_ANGLE2(-135.0f), DEG2SHORT_ANGLE2(135.0f) };
static f32 posX[] = { 24.0f, -24.0f };
if (mPlib_get_player_actor_main_index((GAME*)play) == mPlayer_INDEX_MAIL_JUMP) {
aMBX_setupAction(actor, aMBX_ACT_PL_OPEN);
} else {
xyz_t pos;
int idx = actor->arrange_idx & 1;
pos.x = actor->actor_class.world.position.x + posX[idx];
pos.z = actor->actor_class.world.position.z + 24.0f;
mPlib_request_main_mail_jump_type1((GAME*)play, &pos, angle[idx]);
}
}
static void aMBX_open_and_close(MAILBOX_ACTOR* actor, GAME_PLAY* play) {
cKF_FrameControl_c* fc0 = &actor->kf0.frame_control;
if (cKF_FrameControl_passCheck_now(fc0, 88.0f) == TRUE) {
aMBX_check_flag(actor);
} else if (cKF_FrameControl_passCheck_now(fc0, 14.0f) == TRUE) {
sAdo_OngenTrgStart(0x146, &actor->actor_class.world.position);
} else if (cKF_FrameControl_passCheck_now(fc0, 80.0f) == TRUE) {
sAdo_OngenTrgStart(0x147, &actor->actor_class.world.position);
}
if (actor->kf0_state == cKF_STATE_STOPPED) {
actor->req = aMBX_REQUEST_NONE;
aMBX_setupAction(actor, aMBX_ACT_WAIT);
}
}
static void aMBX_pl_open(MAILBOX_ACTOR* actor, GAME_PLAY* play) {
cKF_FrameControl_c* fc0 = &actor->kf0.frame_control;
if (cKF_FrameControl_passCheck_now(fc0, 18.0f) == TRUE) {
sAdo_OngenTrgStart(0x146, &actor->actor_class.world.position);
}
if (actor->kf0_state == cKF_STATE_STOPPED) {
Submenu* submenu = &play->submenu;
mSM_open_submenu(submenu, mSM_OVL_INVENTORY, mSM_IV_OPEN_MAILBOX, 0);
aMBX_setupAction(actor, aMBX_ACT_PL_CLOSE);
}
}
static void aMBX_pl_close(MAILBOX_ACTOR* actor, GAME_PLAY* play) {
cKF_FrameControl_c* fc0 = &actor->kf0.frame_control;
if (cKF_FrameControl_passCheck_now(fc0, 4.0f) == TRUE) {
sAdo_OngenTrgStart(0x147, &actor->actor_class.world.position);
}
if (actor->kf0_state == cKF_STATE_STOPPED) {
aMBX_check_flag(actor);
actor->req = aMBX_REQUEST_NONE;
aMBX_setupAction(actor, aMBX_ACT_WAIT);
}
}
static void aMBX_setupAction(MAILBOX_ACTOR* actor, int action) {
// clang-format off
static aMBX_ACT_PROC process[] = {
aMBX_wait,
aMBX_pl_wait,
aMBX_open_and_close,
aMBX_pl_open,
aMBX_pl_close,
};
// clang-format on
int anim_idx = aMBX_animeSeqNoTable[action];
aMBX_anime_info_c* info;
cKF_SkeletonInfo_R_c* kf = &actor->kf0;
actor->action = action;
actor->act_proc = process[action];
info = &aMBX_animeTable[anim_idx];
cKF_SkeletonInfo_R_init(kf, kf->skeleton, info->anim, info->start, info->end, info->start, 0.5f, 0.0f, cKF_FRAMECONTROL_STOP, NULL);
actor->anim_idx0 = anim_idx;
}
static void aMBX_actor_move(ACTOR* actorx, GAME* game) {
MAILBOX_ACTOR* actor = (MAILBOX_ACTOR*)actorx;
GAME_PLAY* play = (GAME_PLAY*)game;
aMBX_anime_proc(actorx, play);
actor->act_proc(actor, play);
aMBX_setup_flag_se(actor);
}
static void aMBX_actor_init(ACTOR* actorx, GAME* game) {
MAILBOX_ACTOR* actor = (MAILBOX_ACTOR*)actorx;
actorx->mv_proc = aMBX_actor_move;
actorx->dw_proc = aMBX_actor_draw;
mFI_SetFG_common(DUMMY_MAILBOX0 + actor->arrange_idx, actorx->world.position, FALSE);
aMBX_setupAction(actor, aMBX_ACT_WAIT);
aMBX_check_flag(actor);
actor->kf1.frame_control.current_frame = actor->kf1.frame_control.end_frame;
aMBX_actor_move(actorx, game);
}