Implement & link ac_tokyoso_control

This commit is contained in:
Cuyler36
2025-05-20 03:59:24 -04:00
parent 9310692e68
commit 9250889dde
6 changed files with 676 additions and 7 deletions
+1 -1
View File
@@ -1070,7 +1070,7 @@ config.libs = [
Object(Matching, "actor/ac_super.c"),
Object(Matching, "actor/ac_tama.c"),
Object(Matching, "actor/ac_tent.c"),
Object(NonMatching, "actor/ac_tokyoso_control.c"),
Object(Matching, "actor/ac_tokyoso_control.c"),
Object(Matching, "actor/ac_tools.c"),
Object(Matching, "actor/ac_toudai.c"),
Object(Matching, "actor/ac_train0.c"),
+66 -4
View File
@@ -8,20 +8,82 @@
extern "C" {
#endif
#define aTKC_LAP_NUM 4
#define aTKC_SUBLAP_NUM (2 * aTKC_LAP_NUM) // split into half of the circuit
#define aTKC_NPC_NUM 2
#define aTKC_ANGLE_FOR_LAP_COMPLETION 4000 // approximately 22 degrees
#define aTKC_FLAG_5 (1 << 5)
#define aTKC_FLAG_6 (1 << 6)
#define aTKC_FLAG_7 (1 << 7)
#define aTKC_FLAG_8 (1 << 8)
#define aTKC_FLAG_9 (1 << 9)
#define aTKC_FLAG_RACE_ACTIVE (1 << 10)
#define aTKC_FLAG_11 (1 << 11)
#define aTKC_FLAG_12 (1 << 12)
#define aTKC_FLAG_13 (1 << 13)
#define aTKC_FLAG_14 (1 << 14)
#define aTKC_FLAG_15 (1 << 15)
#define aTKC_MASK_13_14 (aTKC_FLAG_13 | aTKC_FLAG_14)
enum {
aTKC_GOAL_NONE,
aTKC_GOAL_WON,
aTKC_GOAL_LOSE,
aTKC_GOAL_NUM
};
typedef struct ac_tokyoso_event_s {
u8 _00;
u8 _01;
u16 flags;
s16 pos_04[3];
s16 yasiro_pos[3]; // shrine pos (wishing well in AC and e+)
s16 pos_0A[2][2];
s16 angle[2];
s16 pos_16[2];
u8 _1A[2];
u8 _1C[2];
s16 next_angle[2];
u8 lap[2];
u8 goal[2];
} aEv_tokyoso_c;
typedef void (*aTKC_NEXT_RUN_PROC)(ACTOR* actorx);
typedef s16 (*aTKC_GET_ANGLE_PROC)(ACTOR* actorx);
typedef void (*aTKC_RUN_PROC)(ACTOR* actorx);
typedef s16 (*aTKC_RUN_CHECK_PROC)(ACTOR* actorx);
typedef s16 (*aTKC_TOP_CHECK_PROC)(ACTOR* actorx);
typedef s16 (*aTKC_GOAL_CHECK_PROC)(ACTOR* actorx);
typedef void (*aTKC_NPC1_THINK_INIT_PROC)(ACTOR* actorx, GAME_PLAY* play, u8 type);
typedef void (*aTKC_NEXT_POS_PROC)(ACTOR* actorx, int idx);
typedef void (*aTKC_NEXT_WARMUP_PROC)(ACTOR* actorx);
typedef void (*aTKC_SET_TALK_REQUEST_PROC)(ACTOR* actorx);
typedef struct tokyoso_control_clip_s {
aTKC_NEXT_RUN_PROC next_run_proc;
aTKC_GET_ANGLE_PROC get_angle_proc;
aTKC_RUN_PROC run_proc;
aTKC_RUN_CHECK_PROC run_check_proc;
aTKC_TOP_CHECK_PROC top_check_proc;
aTKC_GOAL_CHECK_PROC goal_check_proc;
aTKC_NPC1_THINK_INIT_PROC npc1_think_init_proc;
aTKC_NEXT_POS_PROC next_pos_proc;
aTKC_NEXT_WARMUP_PROC next_warmup_proc;
aTKC_SET_TALK_REQUEST_PROC set_talk_request_proc;
} aTKC_clip_c;
typedef struct tokyoso_control_actor_s TOKYOSO_CONTROL_ACTOR;
typedef void (*aTKC_PROC)(TOKYOSO_CONTROL_ACTOR* actor, GAME_PLAY* play);
struct tokyoso_control_actor_s {
ACTOR actor_class;
aTKC_clip_c clip;
aTKC_PROC act_proc;
int action;
s16 timer;
};
extern ACTOR_PROFILE Tokyoso_Control_Profile;
#ifdef __cplusplus
+20 -1
View File
@@ -1,13 +1,33 @@
#ifndef AC_TOKYOSO_NPC1_H
#define AC_TOKYOSO_NPC1_H
#include "lb_reki.h"
#include "types.h"
#include "m_actor.h"
#include "ac_npc.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct tokyoso_npc1_actor_s TOKYOSO_NPC1_ACTOR;
// TODO: finish this
struct tokyoso_npc1_actor_s {
NPC_ACTOR npc_class;
void* think_proc;
int msg_start_no;
f32 speed;
s16 _9A0;
s16 start_pos[2];
s16 timer;
u8 _9A8;
u8 _9A9;
u8 _9AA;
u8 talk_idx;
u8 _9AC;
};
extern ACTOR_PROFILE Tokyoso_Npc1_Profile;
#ifdef __cplusplus
@@ -15,4 +35,3 @@ extern ACTOR_PROFILE Tokyoso_Npc1_Profile;
#endif
#endif
+2 -1
View File
@@ -37,6 +37,7 @@
#include "ac_mikanbox_clip.h"
#include "ac_needlework_indoor_clip.h"
#include "ac_countdown_clip.h"
#include "ac_tokyoso_control.h"
#ifdef __cplusplus
extern "C" {
@@ -90,7 +91,7 @@ typedef struct clip_s {
/* 0x0C0 */ aGRGR_clip_c* garagara_clip;
/* 0x0C4 */ aHTMD_clip_c* hatumode_clip;
/* 0x0C8 */ void* shrine_clip;
/* 0x0CC */ void* _0CC;
/* 0x0CC */ aTKC_clip_c* tokyoso_clip;
/* 0x0D0 */ aCOU_Clip_c* countdown_clip;
/* 0x0D4 */ CLIP_NONE_PROC ball_redma_proc; /* removed in DnM+ */
/* 0x0D8 */ aMKBC_Clip_c* mikanbox_clip;
+348
View File
@@ -0,0 +1,348 @@
static int aTKN1_set_request_act(TOKYOSO_NPC1_ACTOR* actor, u8 prio, u8 idx, u8 type, u16 obj, s16 move_x, s16 move_z) {
int ret = FALSE;
if (prio >= actor->npc_class.request.act_priority) {
u16 arg_data[aNPC_REQUEST_ARG_NUM];
bzero(arg_data, sizeof(arg_data));
arg_data[0] = obj;
arg_data[2] = move_x;
arg_data[3] = move_z;
actor->npc_class.request.act_priority = prio;
actor->npc_class.request.act_idx = idx;
actor->npc_class.request.act_type = type;
mem_copy((u8*)actor->npc_class.request.act_args, (u8*)arg_data, sizeof(arg_data));
ret = TRUE;
}
return ret;
}
static void aTKN1_normal_wait_init(TOKYOSO_NPC1_ACTOR* actor, GAME_PLAY* play) {
aTKN1_set_request_act(actor, 4, aNPC_ACT_WAIT, aNPC_ACT_TYPE_DEFAULT, aNPC_ACT_OBJ_DEFAULT, 0, 0);
}
static void aTKN1_wait_init(TOKYOSO_NPC1_ACTOR* actor, GAME_PLAY* play) {
actor->npc_class.action.idx = aNPC_ACT_WAIT;
aTKN1_normal_wait_init(actor, play);
}
static void aTKN1_run_init(TOKYOSO_NPC1_ACTOR* actor, GAME_PLAY* play) {
aTKN1_set_request_act(actor, 4, aNPC_ACT_RUN, aNPC_ACT_TYPE_TO_POINT, aNPC_ACT_OBJ_DEFAULT, actor->start_pos[0], actor->start_pos[1]);
actor->npc_class.actor_class.status_data.weight = MASSTYPE_HEAVY-4;
actor->npc_class.talk_info.default_animation = aNPC_ANIM_ASIHUMI1;
actor->npc_class.talk_info.turn = aNPC_TALK_TURN_NORMAL;
}
static void aTKN1_turn_d_init(TOKYOSO_NPC1_ACTOR* actor, GAME_PLAY* play) {
ACTOR* actorx = (ACTOR*)actor;
aTKN1_set_request_act(actor, 4, aNPC_ACT_TURN, aNPC_ACT_TYPE_TO_POINT, aNPC_ACT_OBJ_DEFAULT, actorx->world.position.x, actorx->world.position.z - 10.0f);
}
static void aTKN1_turn_f_init(TOKYOSO_NPC1_ACTOR* actor, GAME_PLAY* play) {
ACTOR* actorx = (ACTOR*)actor;
aTKN1_set_request_act(actor, 4, aNPC_ACT_TURN, aNPC_ACT_TYPE_TO_POINT, aNPC_ACT_OBJ_DEFAULT, actorx->world.position.x, actorx->world.position.z + 10.0f);
}
static void aTKN1_turn_l_init(TOKYOSO_NPC1_ACTOR* actor, GAME_PLAY* play) {
ACTOR* actorx = (ACTOR*)actor;
aTKN1_set_request_act(actor, 4, aNPC_ACT_TURN, aNPC_ACT_TYPE_TO_POINT, aNPC_ACT_OBJ_DEFAULT, actorx->world.position.x - 10.0f, actorx->world.position.z);
}
static void aTKN1_turn_init(TOKYOSO_NPC1_ACTOR* actor, GAME_PLAY* play) {
aTKN1_set_request_act(actor, 4, aNPC_ACT_TURN, aNPC_ACT_TYPE_TO_POINT, aNPC_ACT_OBJ_DEFAULT, actor->start_pos[0], actor->start_pos[1]);
actor->npc_class.condition_info.demo_flg &= ~(aNPC_COND_DEMO_SKIP_MOVE_Y | aNPC_COND_DEMO_SKIP_BGCHECK);
}
static void aTKN1_run_turn_init(TOKYOSO_NPC1_ACTOR* actor, GAME_PLAY* play) {
aTKC_clip_next_run((ACTOR*)actor);
aTKN1_turn_init(actor, play);
actor->npc_class.talk_info.default_animation = aNPC_ANIM_ASIHUMI1;
actor->npc_class.talk_info.turn = aNPC_TALK_TURN_NORMAL;
}
static void aTKN1_warmup_init(TOKYOSO_NPC1_ACTOR* actor, GAME_PLAY* play) {
aEv_tokyoso_c* tokyoso = (aEv_tokyoso_c*)mEv_get_save_area(mEv_EVENT_SPORTS_FAIR_FOOT_RACE, 8);
NPC_CLIP->animation_init_proc((ACTOR*)actor, aNPC_ANIM_WARMUP1, FALSE);
tokyoso->flags &= ~(aTKC_FLAG_5 << ((actor->npc_class.actor_class.npc_id - SP_NPC_EV_TOKYOSO_0) & 1));
actor->_9A0 = 240;
}
static void aTKN1_ready_init(TOKYOSO_NPC1_ACTOR* actor, GAME_PLAY* play) {
aTKN1_wait_init(actor, play);
NPC_CLIP->animation_init_proc((ACTOR*)actor, aNPC_ANIM_READY1, FALSE);
actor->npc_class.talk_info.default_animation = aNPC_ANIM_READY1;
actor->npc_class.talk_info.turn = aNPC_TALK_TURN_NONE;
}
static void aTKN1_kokeru_init(TOKYOSO_NPC1_ACTOR* actor, GAME_PLAY* play) {
NPC_CLIP->animation_init_proc((ACTOR*)actor, aNPC_ANIM_KOKERU1, FALSE);
actor->npc_class.draw.main_animation.keyframe.frame_control.mode = cKF_FRAMECONTROL_STOP;
actor->npc_class.movement.speed.max_speed = 0.0f;
actor->npc_class.movement.speed.deceleration = 0.2f;
actor->npc_class.movement.mv_add_angl = 0;
actor->npc_class.talk_info.default_animation = aNPC_ANIM_KOKERU1;
actor->npc_class.talk_info.turn = aNPC_TALK_TURN_NONE;
}
static void aTKN1_getup_init(TOKYOSO_NPC1_ACTOR* actor, GAME_PLAY* play) {
NPC_CLIP->animation_init_proc((ACTOR*)actor, aNPC_ANIM_KOKERU_GETUP1, FALSE);
actor->npc_class.draw.main_animation.keyframe.frame_control.mode = cKF_FRAMECONTROL_STOP;
actor->npc_class.movement.speed.deceleration = 0.6f;
actor->npc_class.talk_info.default_animation = aNPC_ANIM_KOKERU_GETUP1;
actor->npc_class.talk_info.turn = aNPC_TALK_TURN_NONE;
}
static void aTKN1_goal_init(TOKYOSO_NPC1_ACTOR* actor, GAME_PLAY* play) {
ACTOR* actorx = (ACTOR*)actor;
aEv_tokyoso_c* tokyoso = (aEv_tokyoso_c*)mEv_get_save_area(mEv_EVENT_SPORTS_FAIR_FOOT_RACE, 8);
actor->npc_class.actor_class.status_data.weight = MASSTYPE_HEAVY;
aTKN1_turn_f_init(actor, play);
actor->npc_class.talk_info.default_animation = aNPC_ANIM_WAIT1;
actor->npc_class.talk_info.turn = aNPC_TALK_TURN_NORMAL;
tokyoso->_01 |= (u8)(1 << ((2 + actorx->npc_id - SP_NPC_EV_TOKYOSO_0) & 3));
}
static void aTKN1_goal1_init(TOKYOSO_NPC1_ACTOR* actor, GAME_PLAY* play) {
aTKN1_wait_init(actor, play);
NPC_CLIP->animation_init_proc((ACTOR*)actor, aNPC_ANIM_BANZAI1, FALSE);
actor->npc_class.draw.main_animation.keyframe.frame_control.mode = cKF_FRAMECONTROL_REPEAT;
}
static void aTKN1_goal2_init(TOKYOSO_NPC1_ACTOR* actor, GAME_PLAY* play) {
aTKN1_wait_init(actor, play);
NPC_CLIP->animation_init_proc((ACTOR*)actor, aNPC_ANIM_TIRED1, FALSE);
actor->npc_class.draw.main_animation.keyframe.frame_control.mode = cKF_FRAMECONTROL_REPEAT;
}
static void aTKN1_kansen_init(TOKYOSO_NPC1_ACTOR* actor, GAME_PLAY* play) {
aTKN1_normal_wait_init(actor, play);
actor->npc_class.condition_info.demo_flg |= (aNPC_COND_DEMO_SKIP_BGCHECK | aNPC_COND_DEMO_SKIP_MOVE_Y);
}
static void aTKN1_omedeto_init(TOKYOSO_NPC1_ACTOR* actor, GAME_PLAY* play) {
aTKN1_wait_init(actor, play);
NPC_CLIP->animation_init_proc((ACTOR*)actor, aNPC_ANIM_CLAP1, FALSE);
actor->npc_class.draw.main_animation.keyframe.frame_control.mode = cKF_FRAMECONTROL_REPEAT;
actor->npc_class.condition_info.demo_flg |= (aNPC_COND_DEMO_SKIP_BGCHECK | aNPC_COND_DEMO_SKIP_MOVE_Y);
}
static void aTKN1_omedeto_af_init(TOKYOSO_NPC1_ACTOR* actor, GAME_PLAY* play) {
actor->npc_class.action.idx = aNPC_ACT_RUN;
aTKN1_normal_wait_init(actor, play);
actor->npc_class.condition_info.demo_flg |= (aNPC_COND_DEMO_SKIP_BGCHECK | aNPC_COND_DEMO_SKIP_MOVE_Y);
}
static void aTKN1_move_init(TOKYOSO_NPC1_ACTOR* actor, GAME_PLAY* play) {
aTKN1_set_request_act(actor, 4, aNPC_ACT_WALK, aNPC_ACT_TYPE_TO_POINT, aNPC_ACT_OBJ_DEFAULT, actor->start_pos[0], actor->start_pos[1]);
}
static void aTKN1_lookl_init(TOKYOSO_NPC1_ACTOR* actor, GAME_PLAY* play) {
ACTOR* actorx = (ACTOR*)actor;
aEv_tokyoso_c* tokyoso = (aEv_tokyoso_c*)mEv_get_save_area(mEv_EVENT_SPORTS_FAIR_FOOT_RACE, 8);
aTKN1_turn_l_init(actor, play);
tokyoso->flags &= ~(aTKC_FLAG_11 << ((actorx->npc_id - SP_NPC_EV_TOKYOSO_0) & 1));
}
typedef void (*aTKN1_THINK_INIT_PROC)(TOKYOSO_NPC1_ACTOR* actor, GAME_PLAY* play);
// clang-format off
static aTKN1_THINK_INIT_PROC init_table[] = {
(aTKN1_THINK_INIT_PROC)none_proc1,
aTKN1_normal_wait_init,
aTKN1_wait_init,
aTKN1_run_init,
aTKN1_turn_d_init,
aTKN1_turn_l_init,
aTKN1_turn_f_init,
aTKN1_turn_init,
aTKN1_warmup_init,
aTKN1_ready_init,
aTKN1_kokeru_init,
aTKN1_getup_init,
aTKN1_goal_init,
aTKN1_goal1_init,
aTKN1_goal2_init,
aTKN1_omedeto_init,
aTKN1_move_init,
aTKN1_lookl_init,
aTKN1_run_turn_init,
aTKN1_kansen_init,
aTKN1_omedeto_af_init,
};
// clang-fomrat on
static void aTKC_clip_npc1_think_init(ACTOR* actorx, GAME_PLAY* play, u8 think_init) {
(*init_table[think_init])((TOKYOSO_NPC1_ACTOR*)actorx, play);
}
static void aTKC_clip_next_run(ACTOR* actorx) {
TOKYOSO_NPC1_ACTOR* actor = (TOKYOSO_NPC1_ACTOR*)actorx;
s16 angle = aTKC_clip_get_angle(actorx);
f32 f;
int idx = (actorx->npc_id - SP_NPC_EV_TOKYOSO_0) & 1;
aEv_tokyoso_c* tokyoso = (aEv_tokyoso_c*)mEv_get_save_area(mEv_EVENT_SPORTS_FAIR_FOOT_RACE, 8);
angle += (s16)(aTKC_ANGLE_FOR_LAP_COMPLETION + RANDOM_F(aTKC_ANGLE_FOR_LAP_COMPLETION));
f = (160.0f + RANDOM_F(20.0f)) - idx * 35.0f;
actor->speed = (4.0f + f * (1.0f / 90.0f)) - idx * 0.5f;
if (aTKC_clip_top_check(actorx)) {
actor->speed -= 1.0f;
}
actor->start_pos[0] = tokyoso->yasiro_pos[0] + f * cos_s(angle);
actor->start_pos[1] = tokyoso->yasiro_pos[1] - f * sin_s(angle);
tokyoso->next_angle[idx] = angle;
actor->npc_class.movement.speed.deceleration = 0.6f;
if (tokyoso->lap[idx] == aTKC_SUBLAP_NUM && tokyoso->next_angle[idx] > 0) {
actor->start_pos[0] = (tokyoso->yasiro_pos[0] + 220.0f) - idx * 60.0f + (RANDOM_F(10.0f) - 5.0f);
actor->start_pos[1] = (tokyoso->yasiro_pos[1] - 130.0f) + idx * 60.0f + (RANDOM_F(10.0f) - 5.0f);
}
actor->timer = 300;
}
static s16 aTKC_clip_get_angle(ACTOR* actorx) {
f32 dx;
f32 dz;
s16 angle;
aEv_tokyoso_c* tokyoso = (aEv_tokyoso_c*)mEv_get_save_area(mEv_EVENT_SPORTS_FAIR_FOOT_RACE, 8);
dx = (tokyoso->yasiro_pos[0] + 20) - actorx->world.position.x;
dz = tokyoso->yasiro_pos[1] - actorx->world.position.z;
angle = atans_table(dz, dx);
return DEG2SHORT_ANGLE(90.0f) + angle;
}
static void aTKC_clip_run_proc(ACTOR* actorx) {
int idx = (actorx->npc_id - SP_NPC_EV_TOKYOSO_0) & 1;
aEv_tokyoso_c* tokyoso = (aEv_tokyoso_c*)mEv_get_save_area(mEv_EVENT_SPORTS_FAIR_FOOT_RACE, 8);
tokyoso->pos_0A[idx][0] = actorx->world.position.x;
tokyoso->pos_0A[idx][1] = actorx->world.position.z;
tokyoso->angle[idx] = aTKC_clip_get_angle(actorx);
}
static s16 aTKC_clip_run_check(ACTOR* actorx) {
int idx = (actorx->npc_id - SP_NPC_EV_TOKYOSO_0) & 1;
s16 angle;
aEv_tokyoso_c* tokyoso = (aEv_tokyoso_c*)mEv_get_save_area(mEv_EVENT_SPORTS_FAIR_FOOT_RACE, 8);
TOKYOSO_NPC1_ACTOR* actor = (TOKYOSO_NPC1_ACTOR*)actorx;
if (actor->timer > 0) {
actor->timer--;
if (actor->timer == 0) {
return TRUE;
}
}
if (tokyoso->lap[idx] == aTKC_SUBLAP_NUM && tokyoso->next_angle[idx] > 0) {
return FALSE;
}
angle = tokyoso->angle[idx] - tokyoso->next_angle[idx];
#ifdef BUGFIXES
if (angle > DEG2SHORT_ANGLE2(-22.5f) && angle < DEG2SHORT_ANGLE2(22.5f)) {
#else
// @BUG - did the devs miss a hex specifier here? Shouldn't this be angle >= -[0x]1000?
if (angle > -1000 && angle < DEG2SHORT_ANGLE2(22.5f)) {
#endif
return TRUE;
}
return FALSE;
}
static s16 aTKC_clip_top_check(ACTOR* actorx) {
int idx0 = (actorx->npc_id - SP_NPC_EV_TOKYOSO_0) & 1;
int idx1 = (idx0 + 1) & 1;
s16 angle;
aEv_tokyoso_c* tokyoso = (aEv_tokyoso_c*)mEv_get_save_area(mEv_EVENT_SPORTS_FAIR_FOOT_RACE, 8);
if ((tokyoso->flags & aTKC_FLAG_RACE_ACTIVE) == 0) {
return FALSE;
}
angle = tokyoso->angle[idx0] - tokyoso->angle[idx1];
if (tokyoso->lap[idx0] > tokyoso->lap[idx1] || (tokyoso->lap[idx0] == tokyoso->lap[idx1] && angle > 0)) {
return TRUE;
}
return FALSE;
}
static s16 aTKC_clip_goal_check(ACTOR* actorx) {
int idx = (actorx->npc_id - SP_NPC_EV_TOKYOSO_0) & 1;
aEv_tokyoso_c* tokyoso = (aEv_tokyoso_c*)mEv_get_save_area(mEv_EVENT_SPORTS_FAIR_FOOT_RACE, 8);
if ((tokyoso->flags & aTKC_FLAG_RACE_ACTIVE) == 0) {
return FALSE;
}
if (tokyoso->goal[idx] == aTKC_GOAL_NONE) {
return FALSE;
}
return tokyoso->goal[idx];
}
static void aTKC_clip_next_pos(ACTOR* actorx, int idx) {
static s16 tableX[] = { 200, 160, 280, 280 };
static s16 tableZ[] = { 0, 0, 40, 0 };
TOKYOSO_NPC1_ACTOR* actor = (TOKYOSO_NPC1_ACTOR*)actorx;
aEv_tokyoso_c* tokyoso = (aEv_tokyoso_c*)mEv_get_save_area(mEv_EVENT_SPORTS_FAIR_FOOT_RACE, 8);
actor->start_pos[0] = tokyoso->yasiro_pos[0] + tableX[idx];
actor->start_pos[1] = tokyoso->yasiro_pos[1] + tableZ[idx];
}
static void aTKC_clip_next_warmup(ACTOR* actorx) {
static s16 tableX[] = { 200, 160 };
static f32 tableXR[] = { 40.0f, -40.0f };
int idx = (actorx->npc_id - SP_NPC_EV_TOKYOSO_0) & 1;
TOKYOSO_NPC1_ACTOR* actor = (TOKYOSO_NPC1_ACTOR*)actorx;
aEv_tokyoso_c* tokyoso = (aEv_tokyoso_c*)mEv_get_save_area(mEv_EVENT_SPORTS_FAIR_FOOT_RACE, 8);
actor->start_pos[0] = tokyoso->yasiro_pos[0] + tableX[idx] + (s16)RANDOM_F(tableXR[idx]);
actor->start_pos[1] = tokyoso->yasiro_pos[1] + RANDOM_F(80.0f) - 40.0f;
}
typedef struct {
int msg_no;
u8 turn_flag;
u8 camera_type;
} aTCK_npc1_talk_data_c;
static void aTKC_clip_set_talk_request(ACTOR* actorx) {
static aTCK_npc1_talk_data_c dt_tbl[] = {
{14, FALSE, CAMERA2_PROCESS_TALK},
{ 2, FALSE, CAMERA2_PROCESS_TALK},
{14, FALSE, CAMERA2_PROCESS_TALK},
{ 4, FALSE, CAMERA2_PROCESS_TALK},
{ 6, TRUE, CAMERA2_PROCESS_TALK},
{ 8, TRUE, CAMERA2_PROCESS_TALK},
{ 8, TRUE, CAMERA2_PROCESS_TALK},
{10, FALSE, CAMERA2_PROCESS_TALK},
{10, FALSE, CAMERA2_PROCESS_TALK},
{12, TRUE, CAMERA2_PROCESS_TALK},
{12, TRUE, CAMERA2_PROCESS_TALK},
{12, TRUE, CAMERA2_PROCESS_TALK},
{12, TRUE, CAMERA2_PROCESS_TALK},
};
TOKYOSO_NPC1_ACTOR* actor = (TOKYOSO_NPC1_ACTOR*)actorx;
aTCK_npc1_talk_data_c* data_p = &dt_tbl[actor->talk_idx];
mDemo_Set_msg_num(actor->msg_start_no + data_p->msg_no + RANDOM(2));
mDemo_Set_talk_turn(data_p->turn_flag);
mDemo_Set_camera(data_p->camera_type);
}
+239
View File
@@ -0,0 +1,239 @@
#include "ac_tokyoso_control.h"
#include "m_actor.h"
#include "m_actor_type.h"
#include "m_common_data.h"
#include "m_event.h"
#include "m_field_info.h"
#include "m_name_table.h"
#include "ac_tokyoso_npc1.h"
#include "libultra/libultra.h"
enum {
aTKC_ACT_WAIT,
aTKC_ACT_WAIT2,
aTKC_ACT_STRECH,
aTKC_ACT_READY,
aTKC_ACT_SET,
aTKC_ACT_GO,
aTKC_ACT_GOAL,
aTKC_ACT_IREKAE_1,
aTKC_ACT_IREKAE_2,
aTKC_ACT_NUM
};
static void aTKC_actor_ct(ACTOR* actorx, GAME* game);
static void aTKC_actor_dt(ACTOR* actorx, GAME* game);
static void aTKC_actor_move(ACTOR* actorx, GAME* game);
// clang-format off
ACTOR_PROFILE Tokyoso_Control_Profile = {
mAc_PROFILE_TOKYOSO_CONTROL,
ACTOR_PART_CONTROL,
ACTOR_STATE_NO_MOVE_WHILE_CULLED,
EMPTY_NO,
ACTOR_OBJ_BANK_KEEP,
sizeof(TOKYOSO_CONTROL_ACTOR),
aTKC_actor_ct,
aTKC_actor_dt,
aTKC_actor_move,
mActor_NONE_PROC1,
NULL,
};
// clang-format on
static void aTKC_setupAction(TOKYOSO_CONTROL_ACTOR* actor, int action);
// clip declarations
static void aTKC_clip_next_run(ACTOR* actorx);
static s16 aTKC_clip_get_angle(ACTOR* actorx);
static void aTKC_clip_run_proc(ACTOR* actorx);
static s16 aTKC_clip_run_check(ACTOR* actorx);
static s16 aTKC_clip_top_check(ACTOR* actorx);
static s16 aTKC_clip_goal_check(ACTOR* actorx);
static void aTKC_clip_npc1_think_init(ACTOR* actorx, GAME_PLAY* play, u8 type);
static void aTKC_clip_next_pos(ACTOR* actorx, int idx);
static void aTKC_clip_next_warmup(ACTOR* actorx);
static void aTKC_clip_set_talk_request(ACTOR* actorx);
static void aTKC_actor_ct(ACTOR* actorx, GAME* game) {
TOKYOSO_CONTROL_ACTOR* actor = (TOKYOSO_CONTROL_ACTOR*)actorx;
aEv_tokyoso_c* tokyoso = (aEv_tokyoso_c*)mEv_get_save_area(mEv_EVENT_SPORTS_FAIR_FOOT_RACE, 8);
if (tokyoso == NULL) {
tokyoso = (aEv_tokyoso_c*)mEv_reserve_save_area(mEv_EVENT_SPORTS_FAIR_FOOT_RACE, 8);
tokyoso->_00 = 0;
tokyoso->flags = 0;
}
actor->clip.next_run_proc = aTKC_clip_next_run;
actor->clip.get_angle_proc = aTKC_clip_get_angle;
actor->clip.run_proc = aTKC_clip_run_proc;
actor->clip.run_check_proc = aTKC_clip_run_check;
actor->clip.top_check_proc = aTKC_clip_top_check;
actor->clip.goal_check_proc = aTKC_clip_goal_check;
actor->clip.npc1_think_init_proc = aTKC_clip_npc1_think_init;
actor->clip.next_pos_proc = aTKC_clip_next_pos;
actor->clip.next_warmup_proc = aTKC_clip_next_warmup;
actor->clip.set_talk_request_proc = aTKC_clip_set_talk_request;
CLIP(tokyoso_clip) = &actor->clip;
aTKC_setupAction(actor, aTKC_ACT_WAIT);
}
static void aTKC_actor_dt(ACTOR* actorx, GAME* game) {
CLIP(tokyoso_clip) = NULL;
mEv_actor_dying_message(mEv_EVENT_SPORTS_FAIR_FOOT_RACE, actorx);
}
static void aTKC_actor_move(ACTOR* actorx, GAME* game) {
TOKYOSO_CONTROL_ACTOR* actor = (TOKYOSO_CONTROL_ACTOR*)actorx;
aEv_tokyoso_c* tokyoso = (aEv_tokyoso_c*)mEv_get_save_area(mEv_EVENT_SPORTS_FAIR_FOOT_RACE, 8);
if (tokyoso->_00 == 3 && actor->action != aTKC_ACT_WAIT2) {
aTKC_setupAction(actor, aTKC_ACT_WAIT2);
} else {
actor->act_proc(actor, (GAME_PLAY*)game);
}
}
static void aTKC_irekae_2(TOKYOSO_CONTROL_ACTOR* actor, GAME_PLAY* play) {
aEv_tokyoso_c* tokyoso = (aEv_tokyoso_c*)mEv_get_save_area(mEv_EVENT_SPORTS_FAIR_FOOT_RACE, 8);
if ((tokyoso->flags & aTKC_FLAG_11) == 0) {
aTKC_setupAction(actor, aTKC_ACT_STRECH);
actor->timer = 600;
}
}
static void aTKC_irekae_1(TOKYOSO_CONTROL_ACTOR* actor, GAME_PLAY* play) {
aEv_tokyoso_c* tokyoso = (aEv_tokyoso_c*)mEv_get_save_area(mEv_EVENT_SPORTS_FAIR_FOOT_RACE, 8);
if ((tokyoso->flags & aTKC_FLAG_12) == 0) {
aTKC_setupAction(actor, aTKC_ACT_IREKAE_2);
tokyoso->flags |= aTKC_FLAG_5;
tokyoso->flags |= aTKC_FLAG_11;
}
}
static void aTKC_goal(TOKYOSO_CONTROL_ACTOR* actor, GAME_PLAY* play) {
aEv_tokyoso_c* tokyoso = (aEv_tokyoso_c*)mEv_get_save_area(mEv_EVENT_SPORTS_FAIR_FOOT_RACE, 8);
if ((tokyoso->flags & aTKC_MASK_13_14) == aTKC_MASK_13_14) {
if (actor->timer > 0) {
actor->timer--;
} else {
aTKC_setupAction(actor, aTKC_ACT_IREKAE_1);
tokyoso->flags |= aTKC_FLAG_6;
tokyoso->flags |= aTKC_FLAG_12;
tokyoso->flags &= ~aTKC_FLAG_RACE_ACTIVE;
tokyoso->flags &= ~aTKC_MASK_13_14;
}
}
}
static void aTKC_go(TOKYOSO_CONTROL_ACTOR* actor, GAME_PLAY* play) {
int i;
aEv_tokyoso_c* tokyoso = (aEv_tokyoso_c*)mEv_get_save_area(mEv_EVENT_SPORTS_FAIR_FOOT_RACE, 8);
for (i = 0; i < aTKC_NPC_NUM; i++) {
if (tokyoso->lap[i] & 1) {
if (tokyoso->angle[i] < -aTKC_ANGLE_FOR_LAP_COMPLETION) {
tokyoso->lap[i]++;
}
} else {
if (tokyoso->angle[i] > aTKC_ANGLE_FOR_LAP_COMPLETION) {
tokyoso->lap[i]++;
}
}
if (tokyoso->lap[i] > aTKC_SUBLAP_NUM && tokyoso->goal[i] == aTKC_GOAL_NONE) {
if (tokyoso->goal[(i + 1) & 1] == aTKC_GOAL_NONE) {
tokyoso->goal[i] = aTKC_GOAL_WON;
} else {
aTKC_setupAction(actor, aTKC_ACT_GOAL);
tokyoso->goal[i] = aTKC_GOAL_LOSE;
actor->timer = 600;
}
}
}
}
static void aTKC_set(TOKYOSO_CONTROL_ACTOR* actor, GAME_PLAY* play) {
aEv_tokyoso_c* tokyoso = (aEv_tokyoso_c*)mEv_get_save_area(mEv_EVENT_SPORTS_FAIR_FOOT_RACE, 8);
if ((tokyoso->flags & (aTKC_FLAG_7 | aTKC_FLAG_8 | aTKC_FLAG_9)) == 0) {
aTKC_setupAction(actor, aTKC_ACT_GO); // @BUG - this is called twice
tokyoso->flags |= aTKC_FLAG_RACE_ACTIVE;
tokyoso->lap[0] = tokyoso->lap[1] = 0;
tokyoso->goal[0] = tokyoso->goal[1] = aTKC_GOAL_NONE;
aTKC_setupAction(actor, aTKC_ACT_GO);
}
}
static void aTKC_ready(TOKYOSO_CONTROL_ACTOR* actor, GAME_PLAY* play) {
aEv_tokyoso_c* tokyoso = (aEv_tokyoso_c*)mEv_get_save_area(mEv_EVENT_SPORTS_FAIR_FOOT_RACE, 8);
if ((tokyoso->flags & (aTKC_FLAG_7 | aTKC_FLAG_8 | aTKC_FLAG_9)) == 0) {
if (actor->timer > 0) {
actor->timer--;
} else {
aTKC_setupAction(actor, aTKC_ACT_SET);
tokyoso->flags |= (aTKC_FLAG_7 | aTKC_FLAG_8 | aTKC_FLAG_9);
}
}
}
static void aTKC_strech(TOKYOSO_CONTROL_ACTOR* actor, GAME_PLAY* play) {
aEv_tokyoso_c* tokyoso = (aEv_tokyoso_c*)mEv_get_save_area(mEv_EVENT_SPORTS_FAIR_FOOT_RACE, 8);
if ((tokyoso->flags & (aTKC_FLAG_5 | aTKC_FLAG_6)) == 0) {
if (actor->timer > 0) {
actor->timer--;
} else {
actor->timer = 120;
aTKC_setupAction(actor, aTKC_ACT_READY);
tokyoso->flags |= (aTKC_FLAG_7 | aTKC_FLAG_8 | aTKC_FLAG_9);
}
}
}
static void aTKC_wait2(TOKYOSO_CONTROL_ACTOR* actor, GAME_PLAY* play) {
aEv_tokyoso_c* tokyoso = (aEv_tokyoso_c*)mEv_get_save_area(mEv_EVENT_SPORTS_FAIR_FOOT_RACE, 8);
if (tokyoso->_00 == 0) {
tokyoso->_00 = 1;
aTKC_setupAction(actor, aTKC_ACT_STRECH);
actor->timer = 600;
}
}
static void aTKC_wait(TOKYOSO_CONTROL_ACTOR* actor, GAME_PLAY* play) {
aEv_tokyoso_c* tokyoso = (aEv_tokyoso_c*)mEv_get_save_area(mEv_EVENT_SPORTS_FAIR_FOOT_RACE, 8);
if (mFI_SetOyasiroPos(tokyoso->yasiro_pos)) {
tokyoso->_00 = 1;
aTKC_setupAction(actor, aTKC_ACT_STRECH);
actor->timer = 600;
}
}
static void aTKC_setupAction(TOKYOSO_CONTROL_ACTOR* actor, int action) {
// clang-format off
static aTKC_PROC process[] = {
aTKC_wait,
aTKC_wait2,
aTKC_strech,
aTKC_ready,
aTKC_set,
aTKC_go,
aTKC_goal,
aTKC_irekae_1,
aTKC_irekae_2,
};
// clang-format on
actor->action = action;
actor->act_proc = process[action];
}
#include "../src/actor/ac_tokyoso_clip.c_inc"